Skip to content

Commit c8d77c6

Browse files
authored
Merge pull request #79326 from tshortli/availability-constraint-reason
AST: Split `AvailabilityConstraint` classifications into separate `Reason` and `Kind` enums
2 parents d6e6d26 + aa7bd60 commit c8d77c6

9 files changed

+139
-77
lines changed

include/swift/AST/AvailabilityConstraint.h

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,23 +33,23 @@ class Decl;
3333
/// certain context.
3434
class AvailabilityConstraint {
3535
public:
36-
enum class Kind {
36+
enum class Reason {
3737
/// The declaration is referenced in a context in which it is generally
3838
/// unavailable. For example, a reference to a declaration that is
3939
/// unavailable on macOS from a context that may execute on macOS has this
4040
/// constraint.
41-
AlwaysUnavailable,
41+
UnconditionallyUnavailable,
4242

4343
/// The declaration is referenced in a context in which it is considered
4444
/// obsolete. For example, a reference to a declaration that is obsolete in
4545
/// macOS 13 from a context that may execute on macOS 13 or later has this
4646
/// constraint.
4747
Obsoleted,
4848

49-
/// The declaration is only available in a different version. For example,
49+
/// The declaration is only available in a later version. For example,
5050
/// the declaration might only be introduced in the Swift 6 language mode
5151
/// while the module is being compiled in the Swift 5 language mode.
52-
RequiresVersion,
52+
IntroducedInLaterVersion,
5353

5454
/// The declaration is referenced in a context that does not have an
5555
/// adequate minimum version constraint. For example, a reference to a
@@ -58,37 +58,69 @@ class AvailabilityConstraint {
5858
/// kind of constraint can be satisfied by tightening the minimum
5959
/// version of the context with `if #available(...)` or by adding or
6060
/// adjusting an `@available` attribute.
61-
IntroducedInNewerVersion,
61+
IntroducedInLaterDynamicVersion,
62+
};
63+
64+
/// Classifies constraints into different high level categories.
65+
enum class Kind {
66+
/// There are no contexts in which the declaration would be available.
67+
Unavailable,
68+
69+
/// There are some contexts in which the declaration would be available if
70+
/// additional constraints were added.
71+
PotentiallyAvailable,
6272
};
6373

6474
private:
65-
llvm::PointerIntPair<SemanticAvailableAttr, 2, Kind> attrAndKind;
75+
llvm::PointerIntPair<SemanticAvailableAttr, 2, Reason> attrAndReason;
6676

67-
AvailabilityConstraint(Kind kind, SemanticAvailableAttr attr)
68-
: attrAndKind(attr, kind) {};
77+
AvailabilityConstraint(Reason reason, SemanticAvailableAttr attr)
78+
: attrAndReason(attr, reason) {};
6979

7080
public:
7181
static AvailabilityConstraint
72-
forAlwaysUnavailable(SemanticAvailableAttr attr) {
73-
return AvailabilityConstraint(Kind::AlwaysUnavailable, attr);
82+
unconditionallyUnavailable(SemanticAvailableAttr attr) {
83+
return AvailabilityConstraint(Reason::UnconditionallyUnavailable, attr);
7484
}
7585

76-
static AvailabilityConstraint forObsoleted(SemanticAvailableAttr attr) {
77-
return AvailabilityConstraint(Kind::Obsoleted, attr);
86+
static AvailabilityConstraint obsoleted(SemanticAvailableAttr attr) {
87+
return AvailabilityConstraint(Reason::Obsoleted, attr);
7888
}
7989

80-
static AvailabilityConstraint forRequiresVersion(SemanticAvailableAttr attr) {
81-
return AvailabilityConstraint(Kind::RequiresVersion, attr);
90+
static AvailabilityConstraint
91+
introducedInLaterVersion(SemanticAvailableAttr attr) {
92+
return AvailabilityConstraint(Reason::IntroducedInLaterVersion, attr);
8293
}
8394

8495
static AvailabilityConstraint
85-
forIntroducedInNewerVersion(SemanticAvailableAttr attr) {
86-
return AvailabilityConstraint(Kind::IntroducedInNewerVersion, attr);
96+
introducedInLaterDynamicVersion(SemanticAvailableAttr attr) {
97+
return AvailabilityConstraint(Reason::IntroducedInLaterDynamicVersion,
98+
attr);
8799
}
88100

89-
Kind getKind() const { return attrAndKind.getInt(); }
101+
Reason getReason() const { return attrAndReason.getInt(); }
90102
SemanticAvailableAttr getAttr() const {
91-
return static_cast<SemanticAvailableAttr>(attrAndKind.getPointer());
103+
return static_cast<SemanticAvailableAttr>(attrAndReason.getPointer());
104+
}
105+
106+
Kind getKind() const {
107+
switch (getReason()) {
108+
case Reason::UnconditionallyUnavailable:
109+
case Reason::Obsoleted:
110+
case Reason::IntroducedInLaterVersion:
111+
return Kind::Unavailable;
112+
case Reason::IntroducedInLaterDynamicVersion:
113+
return Kind::PotentiallyAvailable;
114+
}
115+
}
116+
117+
/// Returns true if the constraint cannot be satisfied at runtime.
118+
bool isUnavailable() const { return getKind() == Kind::Unavailable; }
119+
120+
/// Returns true if the constraint is unsatisfied but could be satisfied at
121+
/// runtime in a more constrained context.
122+
bool isPotentiallyAvailable() const {
123+
return getKind() == Kind::PotentiallyAvailable;
92124
}
93125

94126
/// Returns the domain that the constraint applies to.
@@ -103,10 +135,6 @@ class AvailabilityConstraint {
103135
std::optional<AvailabilityRange>
104136
getRequiredNewerAvailabilityRange(ASTContext &ctx) const;
105137

106-
/// Returns true if this unmet requirement can be satisfied by introducing an
107-
/// `if #available(...)` condition in source.
108-
bool isConditionallySatisfiable() const;
109-
110138
/// Some availability constraints are active for type-checking but cannot
111139
/// be translated directly into an `if #available(...)` runtime query.
112140
bool isActiveForRuntimeQueries(ASTContext &ctx) const;

lib/AST/AvailabilityConstraint.cpp

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,16 @@ PlatformKind AvailabilityConstraint::getPlatform() const {
2525
std::optional<AvailabilityRange>
2626
AvailabilityConstraint::getRequiredNewerAvailabilityRange(
2727
ASTContext &ctx) const {
28-
switch (getKind()) {
29-
case Kind::AlwaysUnavailable:
30-
case Kind::RequiresVersion:
31-
case Kind::Obsoleted:
28+
switch (getReason()) {
29+
case Reason::UnconditionallyUnavailable:
30+
case Reason::Obsoleted:
31+
case Reason::IntroducedInLaterVersion:
3232
return std::nullopt;
33-
case Kind::IntroducedInNewerVersion:
33+
case Reason::IntroducedInLaterDynamicVersion:
3434
return getAttr().getIntroducedRange(ctx);
3535
}
3636
}
3737

38-
bool AvailabilityConstraint::isConditionallySatisfiable() const {
39-
switch (getKind()) {
40-
case Kind::AlwaysUnavailable:
41-
case Kind::RequiresVersion:
42-
case Kind::Obsoleted:
43-
return false;
44-
case Kind::IntroducedInNewerVersion:
45-
return true;
46-
}
47-
}
48-
4938
bool AvailabilityConstraint::isActiveForRuntimeQueries(ASTContext &ctx) const {
5039
if (getAttr().getPlatform() == PlatformKind::none)
5140
return true;
@@ -84,7 +73,7 @@ swift::getAvailabilityConstraintForAttr(const Decl *decl,
8473
return std::nullopt;
8574

8675
if (attr.isUnconditionallyUnavailable())
87-
return AvailabilityConstraint::forAlwaysUnavailable(attr);
76+
return AvailabilityConstraint::unconditionallyUnavailable(attr);
8877

8978
auto &ctx = decl->getASTContext();
9079
auto deploymentVersion = attr.getActiveVersion(ctx);
@@ -101,16 +90,16 @@ swift::getAvailabilityConstraintForAttr(const Decl *decl,
10190
}
10291

10392
if (obsoletedVersion && *obsoletedVersion <= deploymentVersion)
104-
return AvailabilityConstraint::forObsoleted(attr);
93+
return AvailabilityConstraint::obsoleted(attr);
10594

10695
AvailabilityRange introducedRange = attr.getIntroducedRange(ctx);
10796

10897
// FIXME: [availability] Expand this to cover custom versioned domains
10998
if (attr.isPlatformSpecific()) {
11099
if (!context.getPlatformRange().isContainedIn(introducedRange))
111-
return AvailabilityConstraint::forIntroducedInNewerVersion(attr);
100+
return AvailabilityConstraint::introducedInLaterDynamicVersion(attr);
112101
} else if (!deploymentRange.isContainedIn(introducedRange)) {
113-
return AvailabilityConstraint::forRequiresVersion(attr);
102+
return AvailabilityConstraint::introducedInLaterVersion(attr);
114103
}
115104

116105
return std::nullopt;

lib/AST/AvailabilityContext.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,13 @@ bool AvailabilityContext::Info::constrainWith(
7171
for (auto constraint : constraints) {
7272
auto attr = constraint.getAttr();
7373
auto domain = attr.getDomain();
74-
switch (constraint.getKind()) {
75-
case AvailabilityConstraint::Kind::AlwaysUnavailable:
76-
case AvailabilityConstraint::Kind::Obsoleted:
77-
case AvailabilityConstraint::Kind::RequiresVersion:
74+
switch (constraint.getReason()) {
75+
case AvailabilityConstraint::Reason::UnconditionallyUnavailable:
76+
case AvailabilityConstraint::Reason::Obsoleted:
77+
case AvailabilityConstraint::Reason::IntroducedInLaterVersion:
7878
isConstrained |= constrainUnavailability(domain);
7979
break;
80-
case AvailabilityConstraint::Kind::IntroducedInNewerVersion:
80+
case AvailabilityConstraint::Reason::IntroducedInLaterDynamicVersion:
8181
// FIXME: [availability] Support versioning for other kinds of domains.
8282
DEBUG_ASSERT(domain.isPlatform());
8383
if (domain.isPlatform())

lib/Sema/CSSyntacticElement.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2467,7 +2467,7 @@ class ResultBuilderRewriter : public SyntacticElementSolutionApplication {
24672467

24682468
auto constraint = getUnsatisfiedAvailabilityConstraint(
24692469
nominal, context.getAsDeclContext(), loc);
2470-
if (constraint && constraint->isConditionallySatisfiable()) {
2470+
if (constraint && constraint->isPotentiallyAvailable()) {
24712471
auto &ctx = getASTContext();
24722472
ctx.Diags.diagnose(loc,
24732473
diag::result_builder_missing_limited_availability,

lib/Sema/ConstraintSystem.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4918,11 +4918,11 @@ bool ConstraintSystem::isReadOnlyKeyPathComponent(
49184918
// If the setter is unavailable, then the keypath ought to be read-only
49194919
// in this context.
49204920
if (auto setter = storage->getOpaqueAccessor(AccessorKind::Set)) {
4921-
// FIXME: Fully unavailable setters should cause the key path to be
4922-
// readonly too.
4921+
// FIXME: [availability] Fully unavailable setters should cause the key path
4922+
// to be readonly too.
49234923
auto constraint =
49244924
getUnsatisfiedAvailabilityConstraint(setter, DC, referenceLoc);
4925-
if (constraint && constraint->isConditionallySatisfiable())
4925+
if (constraint && constraint->isPotentiallyAvailable())
49264926
return true;
49274927
}
49284928

lib/Sema/DerivedConformanceRawRepresentable.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,15 +247,15 @@ checkAvailability(const EnumElementDecl *elt,
247247
if (!constraint)
248248
return true;
249249

250+
// Is it never available?
251+
if (constraint->isUnavailable())
252+
return false;
253+
250254
// Some constraints are active for type checking but can't translate to
251255
// runtime restrictions.
252256
if (!constraint->isActiveForRuntimeQueries(C))
253257
return true;
254258

255-
// Is it never available?
256-
if (!constraint->isConditionallySatisfiable())
257-
return false;
258-
259259
// It's conditionally available; create a version constraint and return true.
260260
auto platform = constraint->getPlatform();
261261
auto range = constraint->getRequiredNewerAvailabilityRange(C);

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3013,12 +3013,12 @@ bool shouldHideDomainNameForConstraintDiagnostic(
30133013

30143014
case AvailabilityDomain::Kind::PackageDescription:
30153015
case AvailabilityDomain::Kind::SwiftLanguage:
3016-
switch (constraint.getKind()) {
3017-
case AvailabilityConstraint::Kind::AlwaysUnavailable:
3018-
case AvailabilityConstraint::Kind::IntroducedInNewerVersion:
3016+
switch (constraint.getReason()) {
3017+
case AvailabilityConstraint::Reason::UnconditionallyUnavailable:
3018+
case AvailabilityConstraint::Reason::IntroducedInLaterVersion:
30193019
return false;
3020-
case AvailabilityConstraint::Kind::RequiresVersion:
3021-
case AvailabilityConstraint::Kind::Obsoleted:
3020+
case AvailabilityConstraint::Reason::IntroducedInLaterDynamicVersion:
3021+
case AvailabilityConstraint::Reason::Obsoleted:
30223022
return true;
30233023
}
30243024
}
@@ -3031,7 +3031,7 @@ bool diagnoseExplicitUnavailability(SourceLoc loc,
30313031
const ExportContext &where,
30323032
bool warnIfConformanceUnavailablePreSwift6,
30333033
bool preconcurrency) {
3034-
if (constraint.isConditionallySatisfiable())
3034+
if (!constraint.isUnavailable())
30353035
return false;
30363036

30373037
// Invertible protocols are never unavailable.
@@ -3062,24 +3062,24 @@ bool diagnoseExplicitUnavailability(SourceLoc loc,
30623062
.limitBehaviorWithPreconcurrency(behavior, preconcurrency)
30633063
.warnUntilSwiftVersionIf(warnIfConformanceUnavailablePreSwift6, 6);
30643064

3065-
switch (constraint.getKind()) {
3066-
case AvailabilityConstraint::Kind::AlwaysUnavailable:
3065+
switch (constraint.getReason()) {
3066+
case AvailabilityConstraint::Reason::UnconditionallyUnavailable:
30673067
diags
30683068
.diagnose(ext, diag::conformance_availability_marked_unavailable, type,
30693069
proto)
30703070
.highlight(attr.getParsedAttr()->getRange());
30713071
break;
3072-
case AvailabilityConstraint::Kind::RequiresVersion:
3072+
case AvailabilityConstraint::Reason::IntroducedInLaterVersion:
30733073
diags.diagnose(ext, diag::conformance_availability_introduced_in_version,
30743074
type, proto, versionedPlatform, *attr.getIntroduced());
30753075
break;
3076-
case AvailabilityConstraint::Kind::Obsoleted:
3076+
case AvailabilityConstraint::Reason::Obsoleted:
30773077
diags
30783078
.diagnose(ext, diag::conformance_availability_obsoleted, type, proto,
30793079
versionedPlatform, *attr.getObsoleted())
30803080
.highlight(attr.getParsedAttr()->getRange());
30813081
break;
3082-
case AvailabilityConstraint::Kind::IntroducedInNewerVersion:
3082+
case AvailabilityConstraint::Reason::IntroducedInLaterDynamicVersion:
30833083
llvm_unreachable("unexpected constraint");
30843084
}
30853085
return true;
@@ -3108,20 +3108,21 @@ swift::getUnsatisfiedAvailabilityConstraint(
31083108
if ((attr->isSwiftLanguageModeSpecific() ||
31093109
attr->isPackageDescriptionVersionSpecific()) &&
31103110
attr->getIntroduced().has_value())
3111-
return AvailabilityConstraint::forRequiresVersion(*attr);
3111+
return AvailabilityConstraint::introducedInLaterVersion(*attr);
31123112

3113-
return AvailabilityConstraint::forAlwaysUnavailable(*attr);
3113+
return AvailabilityConstraint::unconditionallyUnavailable(*attr);
31143114

31153115
case AvailableVersionComparison::Obsoleted:
3116-
return AvailabilityConstraint::forObsoleted(*attr);
3116+
return AvailabilityConstraint::obsoleted(*attr);
31173117
}
31183118
}
31193119

31203120
// Check whether the declaration is available in a newer platform version.
31213121
if (auto rangeAttr = decl->getAvailableAttrForPlatformIntroduction()) {
31223122
auto range = rangeAttr->getIntroducedRange(ctx);
31233123
if (!availabilityContext.getPlatformRange().isContainedIn(range))
3124-
return AvailabilityConstraint::forIntroducedInNewerVersion(*rangeAttr);
3124+
return AvailabilityConstraint::introducedInLaterDynamicVersion(
3125+
*rangeAttr);
31253126
}
31263127

31273128
return std::nullopt;
@@ -3463,7 +3464,7 @@ bool diagnoseExplicitUnavailability(
34633464
const ExportContext &Where, DeclAvailabilityFlags Flags,
34643465
llvm::function_ref<void(InFlightDiagnostic &, StringRef)>
34653466
attachRenameFixIts) {
3466-
if (constraint.isConditionallySatisfiable())
3467+
if (!constraint.isUnavailable())
34673468
return false;
34683469

34693470
auto Attr = constraint.getAttr();
@@ -3527,24 +3528,24 @@ bool diagnoseExplicitUnavailability(
35273528
}
35283529

35293530
auto sourceRange = Attr.getParsedAttr()->getRange();
3530-
switch (constraint.getKind()) {
3531-
case AvailabilityConstraint::Kind::AlwaysUnavailable:
3531+
switch (constraint.getReason()) {
3532+
case AvailabilityConstraint::Reason::UnconditionallyUnavailable:
35323533
diags.diagnose(D, diag::availability_marked_unavailable, D)
35333534
.highlight(sourceRange);
35343535
break;
3535-
case AvailabilityConstraint::Kind::RequiresVersion:
3536+
case AvailabilityConstraint::Reason::IntroducedInLaterVersion:
35363537
diags
35373538
.diagnose(D, diag::availability_introduced_in_version, D,
35383539
versionedPlatform, *Attr.getIntroduced())
35393540
.highlight(sourceRange);
35403541
break;
3541-
case AvailabilityConstraint::Kind::Obsoleted:
3542+
case AvailabilityConstraint::Reason::Obsoleted:
35423543
diags
35433544
.diagnose(D, diag::availability_obsoleted, D, versionedPlatform,
35443545
*Attr.getObsoleted())
35453546
.highlight(sourceRange);
35463547
break;
3547-
case AvailabilityConstraint::Kind::IntroducedInNewerVersion:
3548+
case AvailabilityConstraint::Reason::IntroducedInLaterDynamicVersion:
35483549
llvm_unreachable("unexpected constraint");
35493550
break;
35503551
}

lib/Sema/TypeCheckPattern.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static EnumElementDecl *extractEnumElement(DeclContext *DC, SourceLoc UseLoc,
4141
if (auto constraint =
4242
getUnsatisfiedAvailabilityConstraint(constant, DC, UseLoc)) {
4343
// Only diagnose explicit unavailability.
44-
if (!constraint->isConditionallySatisfiable())
44+
if (constraint->isUnavailable())
4545
diagnoseDeclAvailability(constant, UseLoc, nullptr,
4646
ExportContext::forFunctionBody(DC, UseLoc));
4747
}

0 commit comments

Comments
 (0)