@@ -24,7 +24,7 @@ PlatformKind AvailabilityConstraint::getPlatform() const {
24
24
25
25
std::optional<AvailabilityRange>
26
26
AvailabilityConstraint::getRequiredNewerAvailabilityRange (
27
- ASTContext &ctx) const {
27
+ const ASTContext &ctx) const {
28
28
switch (getReason ()) {
29
29
case Reason::UnconditionallyUnavailable:
30
30
case Reason::Obsoleted:
@@ -35,7 +35,8 @@ AvailabilityConstraint::getRequiredNewerAvailabilityRange(
35
35
}
36
36
}
37
37
38
- bool AvailabilityConstraint::isActiveForRuntimeQueries (ASTContext &ctx) const {
38
+ bool AvailabilityConstraint::isActiveForRuntimeQueries (
39
+ const ASTContext &ctx) const {
39
40
if (getAttr ().getPlatform () == PlatformKind::none)
40
41
return true ;
41
42
@@ -44,6 +45,74 @@ bool AvailabilityConstraint::isActiveForRuntimeQueries(ASTContext &ctx) const {
44
45
/* forRuntimeQuery=*/ true );
45
46
}
46
47
48
+ static bool constraintIsStronger (const AvailabilityConstraint &lhs,
49
+ const AvailabilityConstraint &rhs) {
50
+ DEBUG_ASSERT (lhs.getDomain () == rhs.getDomain ());
51
+
52
+ // If the constraints have matching domains but different reasons, the
53
+ // constraint with the lowest reason is "strongest".
54
+ if (lhs.getReason () != rhs.getReason ())
55
+ return lhs.getReason () < rhs.getReason ();
56
+
57
+ switch (lhs.getReason ()) {
58
+ case AvailabilityConstraint::Reason::UnconditionallyUnavailable:
59
+ // Just keep the first.
60
+ return false ;
61
+
62
+ case AvailabilityConstraint::Reason::Obsoleted:
63
+ // Pick the earliest obsoleted version.
64
+ return *lhs.getAttr ().getObsoleted () < *rhs.getAttr ().getObsoleted ();
65
+
66
+ case AvailabilityConstraint::Reason::IntroducedInLaterVersion:
67
+ case AvailabilityConstraint::Reason::IntroducedInLaterDynamicVersion:
68
+ // Pick the latest introduced version.
69
+ return *lhs.getAttr ().getIntroduced () > *rhs.getAttr ().getIntroduced ();
70
+ }
71
+ }
72
+
73
+ void addConstraint (llvm::SmallVector<AvailabilityConstraint, 4 > &constraints,
74
+ const AvailabilityConstraint &constraint,
75
+ const ASTContext &ctx) {
76
+
77
+ auto iter = llvm::find_if (
78
+ constraints, [&constraint](AvailabilityConstraint &existing) {
79
+ return constraint.getDomain () == existing.getDomain ();
80
+ });
81
+
82
+ // There's no existing constraint for the same domain so just add it.
83
+ if (iter == constraints.end ()) {
84
+ constraints.emplace_back (constraint);
85
+ return ;
86
+ }
87
+
88
+ if (constraintIsStronger (constraint, *iter)) {
89
+ constraints.erase (iter);
90
+ constraints.emplace_back (constraint);
91
+ }
92
+ }
93
+
94
+ std::optional<AvailabilityConstraint>
95
+ DeclAvailabilityConstraints::getPrimaryConstraint () const {
96
+ std::optional<AvailabilityConstraint> result;
97
+
98
+ auto isStrongerConstraint = [](const AvailabilityConstraint &lhs,
99
+ const AvailabilityConstraint &rhs) {
100
+ // Pick the strongest constraint. Constraint kinds are defined in descending
101
+ // order of strength.
102
+ if (lhs.getKind () != rhs.getKind ())
103
+ return lhs.getKind () < rhs.getKind ();
104
+
105
+ return false ;
106
+ };
107
+
108
+ for (auto const &constraint : constraints) {
109
+ if (!result || isStrongerConstraint (constraint, *result))
110
+ result.emplace (constraint);
111
+ }
112
+
113
+ return result;
114
+ }
115
+
47
116
static bool
48
117
isInsideCompatibleUnavailableDeclaration (const Decl *decl,
49
118
const SemanticAvailableAttr &attr,
@@ -65,13 +134,12 @@ isInsideCompatibleUnavailableDeclaration(const Decl *decl,
65
134
return context.containsUnavailableDomain (domain);
66
135
}
67
136
68
- std::optional<AvailabilityConstraint>
69
- swift::getAvailabilityConstraintForAttr (const Decl *decl,
70
- const SemanticAvailableAttr &attr,
71
- const AvailabilityContext &context) {
72
- if (isInsideCompatibleUnavailableDeclaration (decl, attr, context))
73
- return std::nullopt ;
74
-
137
+ // / Returns the `AvailabilityConstraint` that describes how \p attr restricts
138
+ // / use of \p decl in \p context or `std::nullopt` if there is no restriction.
139
+ static std::optional<AvailabilityConstraint>
140
+ getAvailabilityConstraintForAttr (const Decl *decl,
141
+ const SemanticAvailableAttr &attr,
142
+ const AvailabilityContext &context) {
75
143
if (attr.isUnconditionallyUnavailable ())
76
144
return AvailabilityConstraint::unconditionallyUnavailable (attr);
77
145
@@ -128,10 +196,10 @@ activePlatformDomainForDecl(const Decl *decl) {
128
196
return activeDomain;
129
197
}
130
198
131
- static void
132
- getAvailabilityConstraintsForDecl (DeclAvailabilityConstraints &constraints,
133
- const Decl *decl,
134
- const AvailabilityContext &context) {
199
+ static void getAvailabilityConstraintsForDecl (
200
+ llvm::SmallVector<AvailabilityConstraint, 4 > &constraints, const Decl *decl ,
201
+ const AvailabilityContext &context) {
202
+ auto &ctx = decl-> getASTContext ();
135
203
auto activePlatformDomain = activePlatformDomainForDecl (decl);
136
204
137
205
for (auto attr :
@@ -141,20 +209,27 @@ getAvailabilityConstraintsForDecl(DeclAvailabilityConstraints &constraints,
141
209
!activePlatformDomain->contains (domain))
142
210
continue ;
143
211
144
- if (auto constraint =
145
- swift::getAvailabilityConstraintForAttr (decl, attr, context))
146
- constraints.addConstraint (*constraint);
212
+ if (auto constraint = getAvailabilityConstraintForAttr (decl, attr, context))
213
+ addConstraint (constraints, *constraint, ctx);
147
214
}
215
+
216
+ // After resolving constraints, remove any constraints that indicate the
217
+ // declaration is unconditionally unavailable in a domain for which
218
+ // the context is already unavailable.
219
+ llvm::erase_if (constraints, [&](const AvailabilityConstraint &constraint) {
220
+ return isInsideCompatibleUnavailableDeclaration (decl, constraint.getAttr (),
221
+ context);
222
+ });
148
223
}
149
224
150
225
DeclAvailabilityConstraints
151
226
swift::getAvailabilityConstraintsForDecl (const Decl *decl,
152
227
const AvailabilityContext &context) {
153
- DeclAvailabilityConstraints constraints;
228
+ llvm::SmallVector<AvailabilityConstraint, 4 > constraints;
154
229
155
230
// Generic parameters are always available.
156
231
if (isa<GenericTypeParamDecl>(decl))
157
- return constraints ;
232
+ return DeclAvailabilityConstraints () ;
158
233
159
234
decl = abstractSyntaxDeclForAvailableAttribute (decl);
160
235
0 commit comments