mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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.
This commit is contained in:
@@ -893,7 +893,8 @@ ERROR(serialization_xref_to_hidden_dependency,none,
|
||||
"invalid reference to implementation-only imported module %0"
|
||||
"%select{| for %1}1",
|
||||
(const ModuleDecl *, const Decl *))
|
||||
|
||||
WARNING(serialization_dropped_custom_availability,none,
|
||||
"ignoring unresolved custom availability domain %0", (Identifier))
|
||||
WARNING(can_import_invalid_swiftmodule,none,
|
||||
"canImport() evaluated to false due to invalid swiftmodule: %0", (StringRef))
|
||||
|
||||
|
||||
@@ -5777,9 +5777,9 @@ decodeDomainKind(uint8_t kind) {
|
||||
}
|
||||
}
|
||||
|
||||
static std::optional<AvailabilityDomain>
|
||||
decodeAvailabilityDomain(AvailabilityDomainKind domainKind,
|
||||
PlatformKind platformKind, ValueDecl *decl) {
|
||||
static AvailabilityDomain
|
||||
decodeNonCustomAvailabilityDomain(AvailabilityDomainKind domainKind,
|
||||
PlatformKind platformKind) {
|
||||
switch (domainKind) {
|
||||
case AvailabilityDomainKind::Universal:
|
||||
return AvailabilityDomain::forUniversal();
|
||||
@@ -5794,7 +5794,8 @@ decodeAvailabilityDomain(AvailabilityDomainKind domainKind,
|
||||
case AvailabilityDomainKind::Platform:
|
||||
return AvailabilityDomain::forPlatform(platformKind);
|
||||
case AvailabilityDomainKind::Custom:
|
||||
return AvailabilityDomain::forCustom(decl);
|
||||
llvm_unreachable("custom domains aren't handled here");
|
||||
return AvailabilityDomain::forUniversal();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5808,7 +5809,7 @@ DeclDeserializer::readAvailable_DECL_ATTR(SmallVectorImpl<uint64_t> &scratch,
|
||||
bool isSPI;
|
||||
uint8_t rawDomainKind;
|
||||
unsigned rawPlatform;
|
||||
DeclID domainDeclID;
|
||||
DeclID customDomainID;
|
||||
DEF_VER_TUPLE_PIECES(Introduced);
|
||||
DEF_VER_TUPLE_PIECES(Deprecated);
|
||||
DEF_VER_TUPLE_PIECES(Obsoleted);
|
||||
@@ -5817,7 +5818,7 @@ DeclDeserializer::readAvailable_DECL_ATTR(SmallVectorImpl<uint64_t> &scratch,
|
||||
// Decode the record, pulling the version tuple information.
|
||||
serialization::decls_block::AvailableDeclAttrLayout::readRecord(
|
||||
scratch, isImplicit, isUnavailable, isDeprecated, isNoAsync, isSPI,
|
||||
rawDomainKind, rawPlatform, domainDeclID,
|
||||
rawDomainKind, rawPlatform, customDomainID,
|
||||
LIST_VER_TUPLE_PIECES(Introduced), LIST_VER_TUPLE_PIECES(Deprecated),
|
||||
LIST_VER_TUPLE_PIECES(Obsoleted), messageSize, renameSize);
|
||||
|
||||
@@ -5849,24 +5850,49 @@ DeclDeserializer::readAvailable_DECL_ATTR(SmallVectorImpl<uint64_t> &scratch,
|
||||
else
|
||||
kind = AvailableAttr::Kind::Default;
|
||||
|
||||
ValueDecl *domainDecl = nullptr;
|
||||
if (domainDeclID) {
|
||||
Decl *decodedDomainDecl = nullptr;
|
||||
SET_OR_RETURN_ERROR(decodedDomainDecl, MF.getDeclChecked(domainDeclID));
|
||||
AvailabilityDomain domain;
|
||||
if (domainKind == AvailabilityDomainKind::Custom) {
|
||||
if (customDomainID & 0x01) {
|
||||
IdentifierID customDomainNameID = customDomainID >> 1;
|
||||
Identifier customDomainName = MF.getIdentifier(customDomainNameID);
|
||||
SmallVector<AvailabilityDomain, 1> foundDomains;
|
||||
if (ctx.MainModule) {
|
||||
ctx.MainModule->lookupAvailabilityDomains(
|
||||
customDomainName, foundDomains);
|
||||
}
|
||||
|
||||
if (decodedDomainDecl) {
|
||||
domainDecl = dyn_cast<ValueDecl>(decodedDomainDecl);
|
||||
if (!domainDecl)
|
||||
if (foundDomains.size() == 1) {
|
||||
domain = foundDomains[0];
|
||||
} else {
|
||||
ctx.Diags.diagnose(
|
||||
SourceLoc(), diag::serialization_dropped_custom_availability,
|
||||
customDomainName);
|
||||
domain = AvailabilityDomain::forUniversal();
|
||||
}
|
||||
} else {
|
||||
DeclID domainDeclID = customDomainID >> 1;
|
||||
Decl *decodedDomainDecl = nullptr;
|
||||
SET_OR_RETURN_ERROR(decodedDomainDecl, MF.getDeclChecked(domainDeclID));
|
||||
|
||||
if (decodedDomainDecl) {
|
||||
auto domainDecl = dyn_cast<ValueDecl>(decodedDomainDecl);
|
||||
if (!domainDecl)
|
||||
return llvm::make_error<InavalidAvailabilityDomainError>();
|
||||
|
||||
if (auto customDomain = AvailabilityDomain::forCustom(domainDecl))
|
||||
domain = *customDomain;
|
||||
else
|
||||
return llvm::make_error<InavalidAvailabilityDomainError>();
|
||||
} else {
|
||||
return llvm::make_error<InavalidAvailabilityDomainError>();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
domain = decodeNonCustomAvailabilityDomain(domainKind, platform);
|
||||
}
|
||||
|
||||
auto domain = decodeAvailabilityDomain(domainKind, platform, domainDecl);
|
||||
if (!domain)
|
||||
return llvm::make_error<InavalidAvailabilityDomainError>();
|
||||
|
||||
auto attr = new (ctx)
|
||||
AvailableAttr(SourceLoc(), SourceRange(), *domain, SourceLoc(), kind,
|
||||
AvailableAttr(SourceLoc(), SourceRange(), domain, SourceLoc(), kind,
|
||||
message, rename, Introduced, SourceRange(), Deprecated,
|
||||
SourceRange(), Obsoleted, SourceRange(), isImplicit, isSPI);
|
||||
return attr;
|
||||
|
||||
@@ -3182,7 +3182,18 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
|
||||
};
|
||||
|
||||
auto domainKind = getDomainKind(domain);
|
||||
const Decl *domainDecl = domain.getDecl();
|
||||
|
||||
// Custom availablity domains provided via the command line don't have
|
||||
// corresponding declarations. Serialize them as identifiers instead.
|
||||
DeclID customDomainID = 0;
|
||||
if (auto custom = domain.getCustomDomain()) {
|
||||
if (auto customDecl = custom->getDecl()) {
|
||||
customDomainID = S.addDeclRef(customDecl) << 1;
|
||||
} else {
|
||||
// emit the name,
|
||||
customDomainID = (S.addDeclBaseNameRef(custom->getName()) << 1) | 0x1;
|
||||
}
|
||||
}
|
||||
|
||||
llvm::SmallString<32> blob;
|
||||
blob.append(theAttr->getMessage());
|
||||
@@ -3197,7 +3208,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
|
||||
theAttr->isSPI(),
|
||||
static_cast<uint8_t>(domainKind),
|
||||
static_cast<unsigned>(domain.getPlatformKind()),
|
||||
S.addDeclRef(domainDecl),
|
||||
customDomainID,
|
||||
LIST_VER_TUPLE_PIECES(Introduced),
|
||||
LIST_VER_TUPLE_PIECES(Deprecated),
|
||||
LIST_VER_TUPLE_PIECES(Obsoleted),
|
||||
|
||||
48
test/Availability/custom_domain_serialization.swift
Normal file
48
test/Availability/custom_domain_serialization.swift
Normal file
@@ -0,0 +1,48 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
|
||||
// RUN: %target-swift-frontend -emit-module -o %t -module-name Library %s -DLIBRARY \
|
||||
// RUN: -enable-experimental-feature CustomAvailability \
|
||||
// RUN: -define-enabled-availability-domain EnabledDomain \
|
||||
// RUN: -define-always-enabled-availability-domain AlwaysEnabledDomain \
|
||||
// RUN: -define-disabled-availability-domain DisabledDomain \
|
||||
// RUN: -define-dynamic-availability-domain DynamicDomain
|
||||
|
||||
// RUN: %target-typecheck-verify-swift -I %t -enable-experimental-feature CustomAvailability \
|
||||
// RUN: -define-enabled-availability-domain EnabledDomain \
|
||||
// RUN: -define-always-enabled-availability-domain AlwaysEnabledDomain \
|
||||
// RUN: -define-disabled-availability-domain DisabledDomain \
|
||||
// RUN: -define-dynamic-availability-domain DynamicDomain
|
||||
|
||||
// RUN: not %target-swift-frontend -typecheck -I %t -enable-experimental-feature CustomAvailability %s > %t/missing.log 2>&1
|
||||
// RUN: %FileCheck %s < %t/missing.log
|
||||
|
||||
// REQUIRES: swift_feature_CustomAvailability
|
||||
|
||||
#if LIBRARY
|
||||
|
||||
@available(EnabledDomain)
|
||||
public func availableInEnabledDomain() { }
|
||||
|
||||
@available(AlwaysEnabledDomain)
|
||||
public func availableInAlwaysEnabledDomain() { }
|
||||
|
||||
#else
|
||||
import Library
|
||||
|
||||
func test1() { // expected-note{{add '@available' attribute to enclosing global function}}
|
||||
availableInEnabledDomain() // expected-error{{'availableInEnabledDomain()' is only available in EnabledDomain}}
|
||||
// expected-note@-1{{add 'if #available' version check}}
|
||||
availableInAlwaysEnabledDomain()
|
||||
}
|
||||
|
||||
@available(EnabledDomain)
|
||||
func test2() {
|
||||
availableInEnabledDomain()
|
||||
availableInAlwaysEnabledDomain()
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// CHECK: error: unrecognized platform name 'EnabledDomain'
|
||||
// CHECK: warning: ignoring unresolved custom availability domain 'EnabledDomain'
|
||||
// CHECK: warning: ignoring unresolved custom availability domain 'AlwaysEnabledDomain'
|
||||
Reference in New Issue
Block a user