@@ -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,19 @@ 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
+
118
158
AvailabilityContext
119
159
AvailabilityContext::forPlatformRange (const AvailabilityRange &range,
120
160
ASTContext &ctx) {
121
- Info info{range, /* UnavailableDomain */ std::nullopt ,
161
+ Info info{range, /* UnavailableDomains */ {} ,
122
162
/* IsDeprecated*/ false };
123
163
return AvailabilityContext (Storage::get (info, ctx));
124
164
}
@@ -133,27 +173,20 @@ AvailabilityContext AvailabilityContext::forDeploymentTarget(ASTContext &ctx) {
133
173
AvailabilityRange::forDeploymentTarget (ctx), ctx);
134
174
}
135
175
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
176
AvailabilityRange AvailabilityContext::getPlatformRange () const {
145
177
return storage->info .Range ;
146
178
}
147
179
148
180
bool AvailabilityContext::isUnavailable () const {
149
- return storage->info .UnavailableDomain . has_value () ;
181
+ return storage->info .UnavailableDomains . size () > 0 ;
150
182
}
151
183
152
184
bool AvailabilityContext::containsUnavailableDomain (
153
185
AvailabilityDomain domain) const {
154
- if (auto unavailableDomain = storage->info .UnavailableDomain )
155
- return unavailableDomain->contains (domain);
156
-
186
+ for (auto unavailableDomain : storage->info .UnavailableDomains ) {
187
+ if (unavailableDomain.contains (domain))
188
+ return true ;
189
+ }
157
190
return false ;
158
191
}
159
192
@@ -217,10 +250,7 @@ void AvailabilityContext::constrainWithDeclAndPlatformRange(
217
250
}
218
251
219
252
bool AvailabilityContext::isContainedIn (const AvailabilityContext other) const {
220
- if (!storage->info .isContainedIn (other.storage ->info ))
221
- return false ;
222
-
223
- return true ;
253
+ return storage->info .isContainedIn (other.storage ->info );
224
254
}
225
255
226
256
static std::string
@@ -236,8 +266,12 @@ stringForAvailability(const AvailabilityRange &availability) {
236
266
void AvailabilityContext::print (llvm::raw_ostream &os) const {
237
267
os << " version=" << stringForAvailability (getPlatformRange ());
238
268
239
- if (auto unavailableDomain = storage->info .UnavailableDomain )
240
- os << " unavailable=" << unavailableDomain->getNameForAttributePrinting ();
269
+ if (storage->info .UnavailableDomains .size () > 0 ) {
270
+ os << " unavailable=" ;
271
+ llvm::interleave (
272
+ storage->info .UnavailableDomains , os,
273
+ [&](const AvailabilityDomain &domain) { domain.print (os); }, " ," );
274
+ }
241
275
242
276
if (isDeprecated ())
243
277
os << " deprecated" ;
0 commit comments