Skip to content

Commit 7ae3a86

Browse files
committed
AST: Introduce "root" availability domains.
A root availability domain is a direct descendant of the universal availability domain.
1 parent feb8146 commit 7ae3a86

File tree

4 files changed

+68
-36
lines changed

4 files changed

+68
-36
lines changed

include/swift/AST/AvailabilityDomain.h

+8-4
Original file line numberDiff line numberDiff line change
@@ -251,10 +251,14 @@ class AvailabilityDomain final {
251251
/// universal domain (`*`) is the bottom element.
252252
bool contains(const AvailabilityDomain &other) const;
253253

254-
/// Returns the root availability domain that this domain must be compatible
255-
/// with. For example, macCatalyst and visionOS must both be ABI compatible
256-
/// with iOS. The compatible domain must contain this domain.
257-
AvailabilityDomain getABICompatibilityDomain() const;
254+
/// Returns true for domains that are not contained by any domain other than
255+
/// the universal domain.
256+
bool isRoot() const;
257+
258+
/// Returns the root availability domain that contains this domain (see
259+
/// `isRoot()`). For example, macCatalyst and visionOS are both ultimately
260+
/// descendants of the iOS domain.
261+
AvailabilityDomain getRootDomain() const;
258262

259263
bool operator==(const AvailabilityDomain &other) const {
260264
return storage.getOpaqueValue() == other.storage.getOpaqueValue();

lib/AST/Availability.cpp

+15-14
Original file line numberDiff line numberDiff line change
@@ -541,8 +541,10 @@ std::optional<SemanticAvailableAttr> Decl::getUnavailableAttr() const {
541541
return std::nullopt;
542542
}
543543

544+
/// Returns the mutually exclusive root platform domains that must all be
545+
/// unavailable in order for a declaration to be unavailable at runtime.
544546
static llvm::SmallSetVector<AvailabilityDomain, 2>
545-
availabilityDomainsForABICompatibility(const ASTContext &ctx) {
547+
getRootTargetDomains(const ASTContext &ctx) {
546548
llvm::SmallSetVector<AvailabilityDomain, 2> domains;
547549

548550
// Regardless of target platform, binaries built for Embedded do not require
@@ -551,10 +553,10 @@ availabilityDomainsForABICompatibility(const ASTContext &ctx) {
551553
return domains;
552554

553555
if (auto targetDomain = AvailabilityDomain::forTargetPlatform(ctx))
554-
domains.insert(targetDomain->getABICompatibilityDomain());
556+
domains.insert(targetDomain->getRootDomain());
555557

556558
if (auto variantDomain = AvailabilityDomain::forTargetVariantPlatform(ctx))
557-
domains.insert(variantDomain->getABICompatibilityDomain());
559+
domains.insert(variantDomain->getRootDomain());
558560

559561
return domains;
560562
}
@@ -584,8 +586,8 @@ computeDeclRuntimeAvailability(const Decl *decl) {
584586
return DeclRuntimeAvailability::PotentiallyAvailable;
585587

586588
auto &ctx = decl->getASTContext();
587-
auto compatibilityDomains = availabilityDomainsForABICompatibility(ctx);
588-
auto potentiallyAvailableDomains = compatibilityDomains;
589+
auto rootTargetDomains = getRootTargetDomains(ctx);
590+
auto remainingTargetDomains = rootTargetDomains;
589591

590592
AvailabilityConstraintFlags flags;
591593

@@ -606,20 +608,19 @@ computeDeclRuntimeAvailability(const Decl *decl) {
606608

607609
// Check whether the constraint is from a relevant domain.
608610
auto domain = constraint.getDomain();
609-
bool isCompabilityDomainDescendant =
610-
llvm::find_if(compatibilityDomains,
611-
[&domain](AvailabilityDomain compatibilityDomain) {
612-
return compatibilityDomain.contains(domain);
613-
}) != compatibilityDomains.end();
611+
bool isTargetDomain = rootTargetDomains.contains(domain);
614612

615-
if (!domain.isActive(ctx) && !isCompabilityDomainDescendant)
613+
if (!domain.isActive(ctx) && !isTargetDomain)
616614
continue;
617615

618-
if (isCompabilityDomainDescendant) {
616+
if (!domain.isRoot())
617+
continue;
618+
619+
if (isTargetDomain) {
619620
// If the decl is still potentially available in some compatibility
620621
// domain, keep looking at the remaining constraints.
621-
potentiallyAvailableDomains.remove(domain);
622-
if (!potentiallyAvailableDomains.empty())
622+
remainingTargetDomains.remove(domain);
623+
if (!remainingTargetDomains.empty())
623624
continue;
624625
}
625626

lib/AST/AvailabilityDomain.cpp

+20-5
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,8 @@ bool AvailabilityDomain::isActive(const ASTContext &ctx) const {
121121
bool AvailabilityDomain::isActiveForTargetPlatform(
122122
const ASTContext &ctx) const {
123123
if (isPlatform()) {
124-
if (auto targetDomain = AvailabilityDomain::forTargetPlatform(ctx)) {
125-
auto compatibleDomain = targetDomain->getABICompatibilityDomain();
126-
return compatibleDomain.contains(*this);
127-
}
124+
if (auto targetDomain = AvailabilityDomain::forTargetPlatform(ctx))
125+
return targetDomain->getRootDomain().contains(*this);
128126
}
129127
return false;
130128
}
@@ -212,14 +210,31 @@ bool AvailabilityDomain::contains(const AvailabilityDomain &other) const {
212210
}
213211
}
214212

215-
AvailabilityDomain AvailabilityDomain::getABICompatibilityDomain() const {
213+
bool AvailabilityDomain::isRoot() const {
214+
switch (getKind()) {
215+
case AvailabilityDomain::Kind::Universal:
216+
case AvailabilityDomain::Kind::Embedded:
217+
case AvailabilityDomain::Kind::SwiftLanguage:
218+
case AvailabilityDomain::Kind::PackageDescription:
219+
return true;
220+
case AvailabilityDomain::Kind::Platform:
221+
return getRootDomain() == *this;
222+
case AvailabilityDomain::Kind::Custom:
223+
// For now, all custom domains are their own root.
224+
return true;
225+
}
226+
}
227+
228+
AvailabilityDomain AvailabilityDomain::getRootDomain() const {
216229
if (!isPlatform())
217230
return *this;
218231

232+
// iOS specifically contains a few other platforms.
219233
auto iOSDomain = AvailabilityDomain::forPlatform(PlatformKind::iOS);
220234
if (iOSDomain.contains(*this))
221235
return iOSDomain;
222236

237+
// App Extension domains are contained by their base platform domain.
223238
if (auto basePlatform = basePlatformForExtensionPlatform(getPlatformKind()))
224239
return AvailabilityDomain::forPlatform(*basePlatform);
225240

unittests/AST/AvailabilityDomainTests.cpp

+25-13
Original file line numberDiff line numberDiff line change
@@ -124,19 +124,31 @@ TEST_F(AvailabilityDomainLattice, Contains) {
124124
EXPECT_FALSE(visionOSAppExt.contains(macOSAppExt));
125125
}
126126

127-
TEST_F(AvailabilityDomainLattice, ABICompatibilityDomain) {
128-
EXPECT_EQ(Universal.getABICompatibilityDomain(), Universal);
129-
EXPECT_EQ(Swift.getABICompatibilityDomain(), Swift);
130-
EXPECT_EQ(Package.getABICompatibilityDomain(), Package);
131-
EXPECT_EQ(Embedded.getABICompatibilityDomain(), Embedded);
132-
EXPECT_EQ(macOS.getABICompatibilityDomain(), macOS);
133-
EXPECT_EQ(macOSAppExt.getABICompatibilityDomain(), macOS);
134-
EXPECT_EQ(iOS.getABICompatibilityDomain(), iOS);
135-
EXPECT_EQ(iOSAppExt.getABICompatibilityDomain(), iOS);
136-
EXPECT_EQ(macCatalyst.getABICompatibilityDomain(), iOS);
137-
EXPECT_EQ(macCatalystAppExt.getABICompatibilityDomain(), iOS);
138-
EXPECT_EQ(visionOS.getABICompatibilityDomain(), iOS);
139-
EXPECT_EQ(visionOSAppExt.getABICompatibilityDomain(), iOS);
127+
TEST_F(AvailabilityDomainLattice, RootDomain) {
128+
EXPECT_EQ(Universal.getRootDomain(), Universal);
129+
EXPECT_TRUE(Universal.isRoot());
130+
EXPECT_EQ(Swift.getRootDomain(), Swift);
131+
EXPECT_TRUE(Swift.isRoot());
132+
EXPECT_EQ(Package.getRootDomain(), Package);
133+
EXPECT_TRUE(Package.isRoot());
134+
EXPECT_EQ(Embedded.getRootDomain(), Embedded);
135+
EXPECT_TRUE(Embedded.isRoot());
136+
EXPECT_EQ(macOS.getRootDomain(), macOS);
137+
EXPECT_TRUE(macOS.isRoot());
138+
EXPECT_EQ(macOSAppExt.getRootDomain(), macOS);
139+
EXPECT_FALSE(macOSAppExt.isRoot());
140+
EXPECT_EQ(iOS.getRootDomain(), iOS);
141+
EXPECT_TRUE(iOS.isRoot());
142+
EXPECT_EQ(iOSAppExt.getRootDomain(), iOS);
143+
EXPECT_FALSE(iOSAppExt.isRoot());
144+
EXPECT_EQ(macCatalyst.getRootDomain(), iOS);
145+
EXPECT_FALSE(macCatalyst.isRoot());
146+
EXPECT_EQ(macCatalystAppExt.getRootDomain(), iOS);
147+
EXPECT_FALSE(macCatalystAppExt.isRoot());
148+
EXPECT_EQ(visionOS.getRootDomain(), iOS);
149+
EXPECT_FALSE(visionOS.isRoot());
150+
EXPECT_EQ(visionOSAppExt.getRootDomain(), iOS);
151+
EXPECT_FALSE(visionOSAppExt.isRoot());
140152
}
141153

142154
TEST(AvailabilityDomain, TargetPlatform) {

0 commit comments

Comments
 (0)