Skip to content

Commit e624915

Browse files
committed
[Custom availability] Serialize custom domains described on the command line
When a custom domain is described on the command line, there is no backing declaration for it. Serialize such custom domains by identifier and look them up globally at the point of deserialization. When that fails, warn and drop the annotation. This is all a stopgap until we have a way to spell custom availability domains in the Swift language itself.
1 parent 6b39352 commit e624915

File tree

4 files changed

+107
-21
lines changed

4 files changed

+107
-21
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -893,7 +893,8 @@ ERROR(serialization_xref_to_hidden_dependency,none,
893893
"invalid reference to implementation-only imported module %0"
894894
"%select{| for %1}1",
895895
(const ModuleDecl *, const Decl *))
896-
896+
WARNING(serialization_dropped_custom_availability,none,
897+
"ignoring unresolved custom availability domain %0", (Identifier))
897898
WARNING(can_import_invalid_swiftmodule,none,
898899
"canImport() evaluated to false due to invalid swiftmodule: %0", (StringRef))
899900

lib/Serialization/Deserialization.cpp

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5777,9 +5777,9 @@ decodeDomainKind(uint8_t kind) {
57775777
}
57785778
}
57795779

5780-
static std::optional<AvailabilityDomain>
5781-
decodeAvailabilityDomain(AvailabilityDomainKind domainKind,
5782-
PlatformKind platformKind, ValueDecl *decl) {
5780+
static AvailabilityDomain
5781+
decodeNonCustomAvailabilityDomain(AvailabilityDomainKind domainKind,
5782+
PlatformKind platformKind) {
57835783
switch (domainKind) {
57845784
case AvailabilityDomainKind::Universal:
57855785
return AvailabilityDomain::forUniversal();
@@ -5794,7 +5794,8 @@ decodeAvailabilityDomain(AvailabilityDomainKind domainKind,
57945794
case AvailabilityDomainKind::Platform:
57955795
return AvailabilityDomain::forPlatform(platformKind);
57965796
case AvailabilityDomainKind::Custom:
5797-
return AvailabilityDomain::forCustom(decl);
5797+
llvm_unreachable("custom domains aren't handled here");
5798+
return AvailabilityDomain::forUniversal();
57985799
}
57995800
}
58005801

@@ -5808,7 +5809,7 @@ DeclDeserializer::readAvailable_DECL_ATTR(SmallVectorImpl<uint64_t> &scratch,
58085809
bool isSPI;
58095810
uint8_t rawDomainKind;
58105811
unsigned rawPlatform;
5811-
DeclID domainDeclID;
5812+
DeclID customDomainID;
58125813
DEF_VER_TUPLE_PIECES(Introduced);
58135814
DEF_VER_TUPLE_PIECES(Deprecated);
58145815
DEF_VER_TUPLE_PIECES(Obsoleted);
@@ -5817,7 +5818,7 @@ DeclDeserializer::readAvailable_DECL_ATTR(SmallVectorImpl<uint64_t> &scratch,
58175818
// Decode the record, pulling the version tuple information.
58185819
serialization::decls_block::AvailableDeclAttrLayout::readRecord(
58195820
scratch, isImplicit, isUnavailable, isDeprecated, isNoAsync, isSPI,
5820-
rawDomainKind, rawPlatform, domainDeclID,
5821+
rawDomainKind, rawPlatform, customDomainID,
58215822
LIST_VER_TUPLE_PIECES(Introduced), LIST_VER_TUPLE_PIECES(Deprecated),
58225823
LIST_VER_TUPLE_PIECES(Obsoleted), messageSize, renameSize);
58235824

@@ -5849,24 +5850,49 @@ DeclDeserializer::readAvailable_DECL_ATTR(SmallVectorImpl<uint64_t> &scratch,
58495850
else
58505851
kind = AvailableAttr::Kind::Default;
58515852

5852-
ValueDecl *domainDecl = nullptr;
5853-
if (domainDeclID) {
5854-
Decl *decodedDomainDecl = nullptr;
5855-
SET_OR_RETURN_ERROR(decodedDomainDecl, MF.getDeclChecked(domainDeclID));
5853+
AvailabilityDomain domain;
5854+
if (domainKind == AvailabilityDomainKind::Custom) {
5855+
if (customDomainID & 0x01) {
5856+
IdentifierID customDomainNameID = customDomainID >> 1;
5857+
Identifier customDomainName = MF.getIdentifier(customDomainNameID);
5858+
SmallVector<AvailabilityDomain, 1> foundDomains;
5859+
if (ctx.MainModule) {
5860+
ctx.MainModule->lookupAvailabilityDomains(
5861+
customDomainName, foundDomains);
5862+
}
5863+
5864+
if (foundDomains.size() == 1) {
5865+
domain = foundDomains[0];
5866+
} else {
5867+
ctx.Diags.diagnose(
5868+
SourceLoc(), diag::serialization_dropped_custom_availability,
5869+
customDomainName);
5870+
domain = AvailabilityDomain::forUniversal();
5871+
}
5872+
} else {
5873+
DeclID domainDeclID = customDomainID >> 1;
5874+
Decl *decodedDomainDecl = nullptr;
5875+
SET_OR_RETURN_ERROR(decodedDomainDecl, MF.getDeclChecked(domainDeclID));
5876+
5877+
if (decodedDomainDecl) {
5878+
auto domainDecl = dyn_cast<ValueDecl>(decodedDomainDecl);
5879+
if (!domainDecl)
5880+
return llvm::make_error<InavalidAvailabilityDomainError>();
58565881

5857-
if (decodedDomainDecl) {
5858-
domainDecl = dyn_cast<ValueDecl>(decodedDomainDecl);
5859-
if (!domainDecl)
5882+
if (auto customDomain = AvailabilityDomain::forCustom(domainDecl))
5883+
domain = *customDomain;
5884+
else
5885+
return llvm::make_error<InavalidAvailabilityDomainError>();
5886+
} else {
58605887
return llvm::make_error<InavalidAvailabilityDomainError>();
5888+
}
58615889
}
5890+
} else {
5891+
domain = decodeNonCustomAvailabilityDomain(domainKind, platform);
58625892
}
58635893

5864-
auto domain = decodeAvailabilityDomain(domainKind, platform, domainDecl);
5865-
if (!domain)
5866-
return llvm::make_error<InavalidAvailabilityDomainError>();
5867-
58685894
auto attr = new (ctx)
5869-
AvailableAttr(SourceLoc(), SourceRange(), *domain, SourceLoc(), kind,
5895+
AvailableAttr(SourceLoc(), SourceRange(), domain, SourceLoc(), kind,
58705896
message, rename, Introduced, SourceRange(), Deprecated,
58715897
SourceRange(), Obsoleted, SourceRange(), isImplicit, isSPI);
58725898
return attr;

lib/Serialization/Serialization.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3182,7 +3182,18 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
31823182
};
31833183

31843184
auto domainKind = getDomainKind(domain);
3185-
const Decl *domainDecl = domain.getDecl();
3185+
3186+
// Custom availablity domains provided via the command line don't have
3187+
// corresponding declarations. Serialize them as identifiers instead.
3188+
DeclID customDomainID = 0;
3189+
if (auto custom = domain.getCustomDomain()) {
3190+
if (auto customDecl = custom->getDecl()) {
3191+
customDomainID = S.addDeclRef(customDecl) << 1;
3192+
} else {
3193+
// emit the name,
3194+
customDomainID = (S.addDeclBaseNameRef(custom->getName()) << 1) | 0x1;
3195+
}
3196+
}
31863197

31873198
llvm::SmallString<32> blob;
31883199
blob.append(theAttr->getMessage());
@@ -3197,7 +3208,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
31973208
theAttr->isSPI(),
31983209
static_cast<uint8_t>(domainKind),
31993210
static_cast<unsigned>(domain.getPlatformKind()),
3200-
S.addDeclRef(domainDecl),
3211+
customDomainID,
32013212
LIST_VER_TUPLE_PIECES(Introduced),
32023213
LIST_VER_TUPLE_PIECES(Deprecated),
32033214
LIST_VER_TUPLE_PIECES(Obsoleted),
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend -emit-module -o %t -module-name Library %s -DLIBRARY \
4+
// RUN: -enable-experimental-feature CustomAvailability \
5+
// RUN: -define-enabled-availability-domain EnabledDomain \
6+
// RUN: -define-always-enabled-availability-domain AlwaysEnabledDomain \
7+
// RUN: -define-disabled-availability-domain DisabledDomain \
8+
// RUN: -define-dynamic-availability-domain DynamicDomain
9+
10+
// RUN: %target-typecheck-verify-swift -I %t -enable-experimental-feature CustomAvailability \
11+
// RUN: -define-enabled-availability-domain EnabledDomain \
12+
// RUN: -define-always-enabled-availability-domain AlwaysEnabledDomain \
13+
// RUN: -define-disabled-availability-domain DisabledDomain \
14+
// RUN: -define-dynamic-availability-domain DynamicDomain
15+
16+
// RUN: not %target-swift-frontend -typecheck -I %t -enable-experimental-feature CustomAvailability %s > %t/missing.log 2>&1
17+
// RUN: %FileCheck %s < %t/missing.log
18+
19+
// REQUIRES: swift_feature_CustomAvailability
20+
21+
#if LIBRARY
22+
23+
@available(EnabledDomain)
24+
public func availableInEnabledDomain() { }
25+
26+
@available(AlwaysEnabledDomain)
27+
public func availableInAlwaysEnabledDomain() { }
28+
29+
#else
30+
import Library
31+
32+
func test1() { // expected-note{{add '@available' attribute to enclosing global function}}
33+
availableInEnabledDomain() // expected-error{{'availableInEnabledDomain()' is only available in EnabledDomain}}
34+
// expected-note@-1{{add 'if #available' version check}}
35+
availableInAlwaysEnabledDomain()
36+
}
37+
38+
@available(EnabledDomain)
39+
func test2() {
40+
availableInEnabledDomain()
41+
availableInAlwaysEnabledDomain()
42+
}
43+
44+
#endif
45+
46+
// CHECK: error: unrecognized platform name 'EnabledDomain'
47+
// CHECK: warning: ignoring unresolved custom availability domain 'EnabledDomain'
48+
// CHECK: warning: ignoring unresolved custom availability domain 'AlwaysEnabledDomain'

0 commit comments

Comments
 (0)