@@ -38,27 +38,10 @@ static bool constrainRange(AvailabilityRange &existing,
3838 return true ;
3939}
4040
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-
5741bool AvailabilityContext::Info::constrainWith (const Info &other) {
5842 bool isConstrained = false ;
5943 isConstrained |= constrainRange (Range, other.Range );
60- if (other.UnavailableDomain )
61- isConstrained |= constrainUnavailability (other.UnavailableDomain );
44+ isConstrained |= constrainUnavailability (other.UnavailableDomains );
6245 isConstrained |= CONSTRAIN_BOOL (IsDeprecated, other.IsDeprecated );
6346
6447 return isConstrained;
@@ -89,24 +72,72 @@ bool AvailabilityContext::Info::constrainWith(
8972 return isConstrained;
9073}
9174
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+
92102bool 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 ;
95120}
96121
97122bool AvailabilityContext::Info::isContainedIn (const Info &other) const {
98123 // The available versions range be the same or smaller.
99124 if (!Range.isContainedIn (other.Range ))
100125 return false ;
101126
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 ;
110141
111142 // The set of deprecated domains should be the same or larger.
112143 if (!IsDeprecated && other.IsDeprecated )
@@ -115,10 +146,29 @@ bool AvailabilityContext::Info::isContainedIn(const Info &other) const {
115146 return true ;
116147}
117148
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+
118168AvailabilityContext
119169AvailabilityContext::forPlatformRange (const AvailabilityRange &range,
120170 ASTContext &ctx) {
121- Info info{range, /* UnavailableDomain */ std:: nullopt ,
171+ Info info{range, /* UnavailableDomains */ {} ,
122172 /* IsDeprecated*/ false };
123173 return AvailabilityContext (Storage::get (info, ctx));
124174}
@@ -133,27 +183,20 @@ AvailabilityContext AvailabilityContext::forDeploymentTarget(ASTContext &ctx) {
133183 AvailabilityRange::forDeploymentTarget (ctx), ctx);
134184}
135185
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-
144186AvailabilityRange AvailabilityContext::getPlatformRange () const {
145187 return storage->info .Range ;
146188}
147189
148190bool AvailabilityContext::isUnavailable () const {
149- return storage->info .UnavailableDomain . has_value () ;
191+ return storage->info .UnavailableDomains . size () > 0 ;
150192}
151193
152194bool AvailabilityContext::containsUnavailableDomain (
153195 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+ }
157200 return false ;
158201}
159202
@@ -217,10 +260,7 @@ void AvailabilityContext::constrainWithDeclAndPlatformRange(
217260}
218261
219262bool 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 );
224264}
225265
226266static std::string
@@ -236,11 +276,19 @@ stringForAvailability(const AvailabilityRange &availability) {
236276void AvailabilityContext::print (llvm::raw_ostream &os) const {
237277 os << " version=" << stringForAvailability (getPlatformRange ());
238278
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+ }
241285
242286 if (isDeprecated ())
243287 os << " deprecated" ;
244288}
245289
246290void AvailabilityContext::dump () const { print (llvm::errs ()); }
291+
292+ bool AvailabilityContext::verify (ASTContext &ctx) const {
293+ return storage->info .verify (ctx);
294+ }
0 commit comments