Skip to content

Commit b8c4298

Browse files
committed
AST: Introduce AvailabilityDomain::contains().
This operation describes the partial ordering with which Availability domains form a lattice. As a temporary measure, a containment ordering needs to be specified for the Swift language, Embedded, and Package Description domains. Without this ordering, there won't be a way for AvailabilityContext to preserve the invariant that the unavailable domain of a child context contains the unavailable domain for the parent. However, once AvailabilityContext is refactored to represent the status of multiple availability domains simultaneously, the ordering of these domains relative to each other can be relaxed. NFC.
1 parent 4d24b7d commit b8c4298

File tree

4 files changed

+106
-0
lines changed

4 files changed

+106
-0
lines changed

include/swift/AST/AvailabilityDomain.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,11 @@ class AvailabilityDomain final {
177177
/// Returns the string to use when printing an `@available` attribute.
178178
llvm::StringRef getNameForAttributePrinting() const;
179179

180+
/// Returns true if availability in `other` is a subset of availability in
181+
/// this domain. The set of all availability domains form a lattice where the
182+
/// universal domain (`*`) is the bottom element.
183+
bool contains(const AvailabilityDomain &other) const;
184+
180185
bool operator==(const AvailabilityDomain &other) const {
181186
return storage.getOpaqueValue() == other.storage.getOpaqueValue();
182187
}
@@ -185,6 +190,7 @@ class AvailabilityDomain final {
185190
return !(*this == other);
186191
}
187192

193+
/// A total, stable ordering on domains.
188194
bool operator<(const AvailabilityDomain &other) const {
189195
if (getKind() != other.getKind())
190196
return getKind() < other.getKind();

lib/AST/AvailabilityDomain.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,25 @@ llvm::StringRef AvailabilityDomain::getNameForAttributePrinting() const {
5757
return swift::platformString(getPlatformKind());
5858
}
5959
}
60+
61+
bool AvailabilityDomain::contains(const AvailabilityDomain &other) const {
62+
// FIXME: [availability] This currently implements something closer to a
63+
// total ordering instead of the more flexible partial ordering that it
64+
// would ideally represent. Until AvailabilityContext supports tracking
65+
// multiple unavailable domains simultaneously, a stricter ordering is
66+
// necessary to support source compatibility.
67+
switch (getKind()) {
68+
case Kind::Universal:
69+
return true;
70+
case Kind::SwiftLanguage:
71+
return !other.isUniversal();
72+
case Kind::PackageDescription:
73+
case Kind::Embedded:
74+
return !other.isUniversal() && !other.isSwiftLanguage();
75+
case Kind::Platform:
76+
if (getPlatformKind() == other.getPlatformKind())
77+
return true;
78+
return inheritsAvailabilityFromPlatform(other.getPlatformKind(),
79+
getPlatformKind());
80+
}
81+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#include "swift/AST/AvailabilityDomain.h"
2+
#include "gtest/gtest.h"
3+
4+
using namespace swift;
5+
6+
class AvailabilityDomainLattice : public ::testing::Test {
7+
public:
8+
AvailabilityDomain domainForPlatform(PlatformKind kind) {
9+
return AvailabilityDomain::forPlatform(kind);
10+
}
11+
AvailabilityDomain Universal = AvailabilityDomain::forUniversal();
12+
AvailabilityDomain Swift = AvailabilityDomain::forSwiftLanguage();
13+
AvailabilityDomain Package = AvailabilityDomain::forPackageDescription();
14+
AvailabilityDomain Embedded = AvailabilityDomain::forEmbedded();
15+
AvailabilityDomain macOS = domainForPlatform(PlatformKind::macOS);
16+
AvailabilityDomain macOSAppExt =
17+
domainForPlatform(PlatformKind::macOSApplicationExtension);
18+
AvailabilityDomain iOS = domainForPlatform(PlatformKind::iOS);
19+
AvailabilityDomain iOSAppExt =
20+
domainForPlatform(PlatformKind::iOSApplicationExtension);
21+
AvailabilityDomain macCatalyst = domainForPlatform(PlatformKind::macCatalyst);
22+
AvailabilityDomain macCatalystAppExt =
23+
domainForPlatform(PlatformKind::macCatalystApplicationExtension);
24+
AvailabilityDomain visionOS = domainForPlatform(PlatformKind::visionOS);
25+
AvailabilityDomain visionOSAppExt =
26+
domainForPlatform(PlatformKind::visionOSApplicationExtension);
27+
28+
std::vector<AvailabilityDomain> all() const {
29+
return {
30+
Universal, Swift, Package, Embedded, macOS,
31+
macOSAppExt, iOS, iOSAppExt, macCatalyst, macCatalystAppExt,
32+
visionOS, visionOSAppExt};
33+
}
34+
};
35+
36+
TEST_F(AvailabilityDomainLattice, Contains) {
37+
for (auto const &domain : all()) {
38+
// The universal domain is the bottom domain and contains all others.
39+
EXPECT_TRUE(Universal.contains(domain));
40+
41+
// FIXME: [availability] The following assertions should change when
42+
// AvailabilityContext can support multiple simultaneous unavailable
43+
// domains.
44+
45+
// The Swift domain is second from the bottom.
46+
EXPECT_EQ(Swift.contains(domain), !domain.isUniversal());
47+
48+
// Package and Embedded are both third from the bottom.
49+
EXPECT_EQ(Package.contains(domain), !domain.isUniversal() && !domain.isSwiftLanguage());
50+
EXPECT_EQ(Embedded.contains(domain), !domain.isUniversal() && !domain.isSwiftLanguage());
51+
}
52+
53+
// Platform kind domains form their own lattice in which app extension domains
54+
// are contained within the domain of the same platform.
55+
EXPECT_TRUE(macOS.contains(macOS));
56+
EXPECT_FALSE(macOS.contains(iOS));
57+
EXPECT_TRUE(macOS.contains(macOSAppExt));
58+
EXPECT_FALSE(macOSAppExt.contains(macOS));
59+
EXPECT_FALSE(macOS.contains(macCatalyst));
60+
EXPECT_FALSE(macCatalyst.contains(macOS));
61+
62+
// Additionally, iOS is the ABI platform for both macCatalyst and visionOS and
63+
// thus the iOS domain contains those domains.
64+
EXPECT_TRUE(iOS.contains(iOS));
65+
EXPECT_TRUE(iOS.contains(iOSAppExt));
66+
EXPECT_FALSE(iOSAppExt.contains(iOS));
67+
EXPECT_TRUE(iOS.contains(macCatalyst));
68+
EXPECT_FALSE(macCatalyst.contains(iOS));
69+
EXPECT_TRUE(iOS.contains(macCatalystAppExt));
70+
EXPECT_FALSE(macCatalystAppExt.contains(iOS));
71+
EXPECT_TRUE(iOS.contains(visionOS));
72+
EXPECT_FALSE(visionOS.contains(iOS));
73+
EXPECT_TRUE(iOS.contains(visionOSAppExt));
74+
EXPECT_FALSE(visionOSAppExt.contains(iOS));
75+
EXPECT_FALSE(iOS.contains(macOS));
76+
EXPECT_FALSE(iOS.contains(macOSAppExt));
77+
}

unittests/AST/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ add_swift_unittest(SwiftASTTests
22
ArithmeticEvaluator.cpp
33
ASTDumperTests.cpp
44
ASTWalkerTests.cpp
5+
AvailabilityDomainTests.cpp
56
IndexSubsetTests.cpp
67
DiagnosticBehaviorTests.cpp
78
DiagnosticConsumerTests.cpp

0 commit comments

Comments
 (0)