@@ -38,27 +38,10 @@ static bool constrainRange(AvailabilityRange &existing,
38
38
return true ;
39
39
}
40
40
41
- static bool constrainUnavailableDomain (
42
- std::optional<AvailabilityDomain> &domain,
43
- const std::optional<AvailabilityDomain> &otherDomain) {
44
- // If the other domain is absent or is the same domain, it's a noop.
45
- if (!otherDomain || domain == otherDomain)
46
- return false ;
47
-
48
- // Check if the other domain is a superset and constrain to it if it is.
49
- if (!domain || otherDomain->contains (*domain)) {
50
- domain = otherDomain;
51
- return true ;
52
- }
53
-
54
- return false ;
55
- }
56
-
57
41
bool AvailabilityContext::Info::constrainWith (const Info &other) {
58
42
bool isConstrained = false ;
59
43
isConstrained |= constrainRange (Range, other.Range );
60
- if (other.UnavailableDomain )
61
- isConstrained |= constrainUnavailability (other.UnavailableDomain );
44
+ isConstrained |= constrainUnavailability (other.UnavailableDomains );
62
45
isConstrained |= CONSTRAIN_BOOL (IsDeprecated, other.IsDeprecated );
63
46
64
47
return isConstrained;
@@ -89,24 +72,72 @@ bool AvailabilityContext::Info::constrainWith(
89
72
return isConstrained;
90
73
}
91
74
75
+ // / Returns true if `domain` is not already contained in `unavailableDomains`.
76
+ // / Also, removes domains from `unavailableDomains` that are contained in
77
+ // / `domain`.
78
+ static bool shouldConstrainUnavailableDomains (
79
+ AvailabilityDomain domain,
80
+ llvm::SmallVectorImpl<AvailabilityDomain> &unavailableDomains) {
81
+ bool didRemove = false ;
82
+ for (auto iter = unavailableDomains.rbegin (), end = unavailableDomains.rend ();
83
+ iter != end; ++iter) {
84
+ auto const &existingDomain = *iter;
85
+
86
+ // Check if the domain is already unavailable.
87
+ if (existingDomain.contains (domain)) {
88
+ ASSERT (!didRemove); // This would indicate that the context is malformed.
89
+ return false ;
90
+ }
91
+
92
+ // Check if the existing domain would be absorbed by the new domain.
93
+ if (domain.contains (existingDomain)) {
94
+ unavailableDomains.erase ((iter + 1 ).base ());
95
+ didRemove = true ;
96
+ }
97
+ }
98
+
99
+ return true ;
100
+ }
101
+
92
102
bool AvailabilityContext::Info::constrainUnavailability (
93
- std::optional<AvailabilityDomain> domain) {
94
- return constrainUnavailableDomain (UnavailableDomain, domain);
103
+ const llvm::SmallVectorImpl<AvailabilityDomain> &domains) {
104
+ llvm::SmallVector<AvailabilityDomain, 2 > domainsToAdd;
105
+
106
+ for (auto domain : domains) {
107
+ if (shouldConstrainUnavailableDomains (domain, UnavailableDomains))
108
+ domainsToAdd.push_back (domain);
109
+ }
110
+
111
+ if (domainsToAdd.size () < 1 )
112
+ return false ;
113
+
114
+ // Add the candidate domain and then re-sort.
115
+ for (auto domain : domainsToAdd)
116
+ UnavailableDomains.push_back (domain);
117
+
118
+ llvm::sort (UnavailableDomains, StableAvailabilityDomainComparator ());
119
+ return true ;
95
120
}
96
121
97
122
bool AvailabilityContext::Info::isContainedIn (const Info &other) const {
98
123
// The available versions range be the same or smaller.
99
124
if (!Range.isContainedIn (other.Range ))
100
125
return false ;
101
126
102
- // The set of unavailable domains should be the same or larger.
103
- if (auto otherUnavailableDomain = other.UnavailableDomain ) {
104
- if (!UnavailableDomain)
105
- return false ;
106
-
107
- if (!UnavailableDomain->contains (otherUnavailableDomain.value ()))
108
- return false ;
109
- }
127
+ // Every unavailable domain in the other context should be contained in some
128
+ // unavailable domain in this context.
129
+ bool disjointUnavailability = llvm::any_of (
130
+ other.UnavailableDomains ,
131
+ [&](const AvailabilityDomain &otherUnavailableDomain) {
132
+ return llvm::none_of (
133
+ UnavailableDomains,
134
+ [&otherUnavailableDomain](const AvailabilityDomain &domain) {
135
+ return domain.contains (otherUnavailableDomain);
136
+ });
137
+ });
138
+
139
+ if (disjointUnavailability)
140
+ return false ;
110
141
111
142
// The set of deprecated domains should be the same or larger.
112
143
if (!IsDeprecated && other.IsDeprecated )
@@ -115,10 +146,29 @@ bool AvailabilityContext::Info::isContainedIn(const Info &other) const {
115
146
return true ;
116
147
}
117
148
149
+ void AvailabilityContext::Info::Profile (llvm::FoldingSetNodeID &ID) const {
150
+ Range.getRawVersionRange ().Profile (ID);
151
+ ID.AddInteger (UnavailableDomains.size ());
152
+ for (auto domain : UnavailableDomains) {
153
+ domain.Profile (ID);
154
+ }
155
+ ID.AddBoolean (IsDeprecated);
156
+ }
157
+
158
+ bool AvailabilityContext::Info::verify (ASTContext &ctx) const {
159
+ // Unavailable domains must be sorted to ensure folding set node lookups yield
160
+ // consistent results.
161
+ if (!llvm::is_sorted (UnavailableDomains,
162
+ StableAvailabilityDomainComparator ()))
163
+ return false ;
164
+
165
+ return true ;
166
+ }
167
+
118
168
AvailabilityContext
119
169
AvailabilityContext::forPlatformRange (const AvailabilityRange &range,
120
170
ASTContext &ctx) {
121
- Info info{range, /* UnavailableDomain */ std::nullopt ,
171
+ Info info{range, /* UnavailableDomains */ {} ,
122
172
/* IsDeprecated*/ false };
123
173
return AvailabilityContext (Storage::get (info, ctx));
124
174
}
@@ -133,27 +183,20 @@ AvailabilityContext AvailabilityContext::forDeploymentTarget(ASTContext &ctx) {
133
183
AvailabilityRange::forDeploymentTarget (ctx), ctx);
134
184
}
135
185
136
- AvailabilityContext
137
- AvailabilityContext::get (const AvailabilityRange &platformAvailability,
138
- std::optional<AvailabilityDomain> unavailableDomain,
139
- bool deprecated, ASTContext &ctx) {
140
- Info info{platformAvailability, unavailableDomain, deprecated};
141
- return AvailabilityContext (Storage::get (info, ctx));
142
- }
143
-
144
186
AvailabilityRange AvailabilityContext::getPlatformRange () const {
145
187
return storage->info .Range ;
146
188
}
147
189
148
190
bool AvailabilityContext::isUnavailable () const {
149
- return storage->info .UnavailableDomain . has_value () ;
191
+ return storage->info .UnavailableDomains . size () > 0 ;
150
192
}
151
193
152
194
bool AvailabilityContext::containsUnavailableDomain (
153
195
AvailabilityDomain domain) const {
154
- if (auto unavailableDomain = storage->info .UnavailableDomain )
155
- return unavailableDomain->contains (domain);
156
-
196
+ for (auto unavailableDomain : storage->info .UnavailableDomains ) {
197
+ if (unavailableDomain.contains (domain))
198
+ return true ;
199
+ }
157
200
return false ;
158
201
}
159
202
@@ -217,10 +260,7 @@ void AvailabilityContext::constrainWithDeclAndPlatformRange(
217
260
}
218
261
219
262
bool AvailabilityContext::isContainedIn (const AvailabilityContext other) const {
220
- if (!storage->info .isContainedIn (other.storage ->info ))
221
- return false ;
222
-
223
- return true ;
263
+ return storage->info .isContainedIn (other.storage ->info );
224
264
}
225
265
226
266
static std::string
@@ -236,11 +276,19 @@ stringForAvailability(const AvailabilityRange &availability) {
236
276
void AvailabilityContext::print (llvm::raw_ostream &os) const {
237
277
os << " version=" << stringForAvailability (getPlatformRange ());
238
278
239
- if (auto unavailableDomain = storage->info .UnavailableDomain )
240
- os << " unavailable=" << unavailableDomain->getNameForAttributePrinting ();
279
+ if (storage->info .UnavailableDomains .size () > 0 ) {
280
+ os << " unavailable=" ;
281
+ llvm::interleave (
282
+ storage->info .UnavailableDomains , os,
283
+ [&](const AvailabilityDomain &domain) { domain.print (os); }, " ," );
284
+ }
241
285
242
286
if (isDeprecated ())
243
287
os << " deprecated" ;
244
288
}
245
289
246
290
void AvailabilityContext::dump () const { print (llvm::errs ()); }
291
+
292
+ bool AvailabilityContext::verify (ASTContext &ctx) const {
293
+ return storage->info .verify (ctx);
294
+ }
0 commit comments