Skip to content

Commit 45277d2

Browse files
authored
Merge pull request #79626 from tshortli/availability-domain-lookup
AST: Centralize AvailabilityDomain lookup
2 parents c6d1060 + 62c8e72 commit 45277d2

16 files changed

+216
-153
lines changed

include/swift/AST/Attr.h

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,20 @@ class DeclAttribute : public AttributeBase {
165165
/// Whether this attribute was spelled `@_spi_available`.
166166
IsSPI : 1,
167167

168-
/// Whether this attribute belongs to a chain of adjacent `@available` attributes that were generated from a single attribute written in source using short form syntax e.g. (`@available(macOS 15, iOS 18, *)`).
168+
/// Whether this attribute belongs to a chain of adjacent `@available`
169+
/// attributes that were generated from a single attribute written in
170+
/// source using short form syntax, e.g.
171+
///
172+
/// @available(macOS 15, iOS 18, *)
173+
///
169174
IsGroupMember : 1,
170175

171176
/// Whether this attribute is the final one in its group.
172177
IsGroupTerminator : 1,
173178

174-
/// Whether this attribute's specification was followed by `, *` in source.
175-
IsAdjacentToWildcard : 1
179+
/// Whether any members of the group were written as a wildcard
180+
/// specification (`*`) in source.
181+
IsGroupedWithWildcard : 1
176182
);
177183

178184
SWIFT_INLINE_BITFIELD(ClangImporterSynthesizedTypeAttr, DeclAttribute, 1,
@@ -740,6 +746,7 @@ class AvailableAttr : public DeclAttribute {
740746

741747
private:
742748
friend class SemanticAvailableAttr;
749+
friend class SemanticAvailableAttrRequest;
743750

744751
AvailabilityDomainOrIdentifier DomainOrIdentifier;
745752
const SourceLoc DomainLoc;
@@ -759,18 +766,8 @@ class AvailableAttr : public DeclAttribute {
759766
/// has been resolved successfully.
760767
bool hasCachedDomain() const { return DomainOrIdentifier.isDomain(); }
761768

762-
/// Returns the `AvailabilityDomain` associated with the attribute, or
763-
/// `std::nullopt` if it has either not yet been resolved or could not be
764-
/// resolved successfully.
765-
std::optional<AvailabilityDomain> getCachedDomain() const {
766-
return DomainOrIdentifier.getAsDomain();
767-
}
768-
769-
/// If the attribute does not already have a cached `AvailabilityDomain`, this
770-
/// returns the domain identifier that was written in source, from which an
771-
/// `AvailabilityDomain` can be resolved.
772-
std::optional<Identifier> getDomainIdentifier() const {
773-
return DomainOrIdentifier.getAsIdentifier();
769+
AvailabilityDomainOrIdentifier getDomainOrIdentifier() const {
770+
return DomainOrIdentifier;
774771
}
775772

776773
SourceLoc getDomainLoc() const { return DomainLoc; }
@@ -848,12 +845,13 @@ class AvailableAttr : public DeclAttribute {
848845
}
849846
void setIsGroupTerminator() { Bits.AvailableAttr.IsGroupTerminator = true; }
850847

851-
/// Whether this attribute's specification was followed by `, *` in source.
852-
bool isAdjacentToWildcard() const {
853-
return Bits.AvailableAttr.IsAdjacentToWildcard;
848+
/// Whether any members of the group were written as a wildcard specification
849+
/// (`*`) in source.
850+
bool isGroupedWithWildcard() const {
851+
return Bits.AvailableAttr.IsGroupedWithWildcard;
854852
}
855-
void setIsAdjacentToWildcard() {
856-
Bits.AvailableAttr.IsAdjacentToWildcard = true;
853+
void setIsGroupedWithWildcard() {
854+
Bits.AvailableAttr.IsGroupedWithWildcard = true;
857855
}
858856

859857
/// Returns the kind of availability the attribute specifies.
@@ -914,11 +912,6 @@ class AvailableAttr : public DeclAttribute {
914912
private:
915913
friend class SemanticAvailableAttrRequest;
916914

917-
void setCachedDomain(AvailabilityDomain domain) {
918-
assert(!DomainOrIdentifier.isDomain());
919-
DomainOrIdentifier.setDomain(domain);
920-
}
921-
922915
bool hasComputedSemanticAttr() const {
923916
return Bits.AvailableAttr.HasComputedSemanticAttr;
924917
}
@@ -3301,12 +3294,13 @@ class SemanticAvailableAttr final {
33013294
public:
33023295
SemanticAvailableAttr(const AvailableAttr *attr) : attr(attr) {
33033296
assert(attr);
3304-
assert(attr->hasCachedDomain());
3297+
bool hasDomain = attr->getDomainOrIdentifier().isDomain();
3298+
assert(hasDomain);
33053299
}
33063300

33073301
const AvailableAttr *getParsedAttr() const { return attr; }
33083302
const AvailabilityDomain getDomain() const {
3309-
return attr->getCachedDomain().value();
3303+
return attr->getDomainOrIdentifier().getAsDomain().value();
33103304
}
33113305

33123306
/// The version tuple for the `introduced:` component.

include/swift/AST/AvailabilityDomain.h

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/AST/PlatformKind.h"
2424
#include "swift/Basic/Assertions.h"
2525
#include "swift/Basic/LLVM.h"
26+
#include "swift/Basic/SourceLoc.h"
2627
#include "llvm/ADT/FoldingSet.h"
2728
#include "llvm/ADT/PointerEmbeddedInt.h"
2829
#include "llvm/ADT/PointerUnion.h"
@@ -248,12 +249,19 @@ class AvailabilityDomain final {
248249
ID.AddPointer(getOpaqueValue());
249250
}
250251

252+
void print(llvm::raw_ostream &os) const;
253+
251254
private:
252255
friend class AvailabilityDomainOrIdentifier;
253256

254257
AvailabilityDomain copy(ASTContext &ctx) const;
255258
};
256259

260+
inline void simple_display(llvm::raw_ostream &os,
261+
const AvailabilityDomain &domain) {
262+
domain.print(os);
263+
}
264+
257265
/// Represents an availability domain that has been defined in a module.
258266
class CustomAvailabilityDomain : public ASTAllocated<CustomAvailabilityDomain> {
259267
public:
@@ -287,46 +295,71 @@ class CustomAvailabilityDomain : public ASTAllocated<CustomAvailabilityDomain> {
287295
class AvailabilityDomainOrIdentifier {
288296
friend struct llvm::PointerLikeTypeTraits<AvailabilityDomainOrIdentifier>;
289297

290-
using Storage = llvm::PointerUnion<AvailabilityDomain, Identifier>;
298+
using DomainOrIdentifier = llvm::PointerUnion<AvailabilityDomain, Identifier>;
299+
300+
/// Stores an extra bit representing whether the domain has been resolved.
301+
using Storage = llvm::PointerIntPair<DomainOrIdentifier, 1, bool>;
291302
Storage storage;
292303

293304
AvailabilityDomainOrIdentifier(Storage storage) : storage(storage) {}
294305

306+
static AvailabilityDomainOrIdentifier fromOpaque(void *opaque) {
307+
return AvailabilityDomainOrIdentifier(Storage::getFromOpaqueValue(opaque));
308+
}
309+
310+
std::optional<AvailabilityDomain>
311+
lookUpInDeclContext(SourceLoc loc, const DeclContext *declContext) const;
312+
295313
public:
296314
AvailabilityDomainOrIdentifier(Identifier identifier)
297315
: storage(identifier) {};
298316
AvailabilityDomainOrIdentifier(AvailabilityDomain domain)
299317
: storage(domain) {};
300318

301-
static AvailabilityDomainOrIdentifier fromOpaque(void *opaque) {
302-
return AvailabilityDomainOrIdentifier(Storage::getFromOpaqueValue(opaque));
319+
bool isDomain() const {
320+
return storage.getPointer().is<AvailabilityDomain>();
303321
}
304-
305-
bool isDomain() const { return storage.is<AvailabilityDomain>(); }
306-
bool isIdentifier() const { return storage.is<Identifier>(); }
322+
bool isIdentifier() const { return storage.getPointer().is<Identifier>(); }
307323

308324
/// Overwrites the existing domain or identifier with the given domain.
309325
void setDomain(AvailabilityDomain domain) { storage = Storage(domain); }
310326

311327
/// Returns the resolved domain, or `std::nullopt` if there isn't one.
312328
std::optional<AvailabilityDomain> getAsDomain() const {
313329
if (isDomain())
314-
return storage.get<AvailabilityDomain>();
330+
return storage.getPointer().get<AvailabilityDomain>();
315331
return std::nullopt;
316332
}
317333

318334
/// Returns the unresolved identifier, or `std::nullopt` if the domain has
319335
/// been resolved.
320336
std::optional<Identifier> getAsIdentifier() const {
321337
if (isIdentifier())
322-
return storage.get<Identifier>();
338+
return storage.getPointer().get<Identifier>();
323339
return std::nullopt;
324340
}
325341

342+
std::optional<AvailabilityDomain>
343+
resolveInDeclContext(SourceLoc loc, const DeclContext *declContext) {
344+
// Return the domain directly if already resolved.
345+
if (storage.getInt() || isDomain())
346+
return getAsDomain();
347+
348+
// Look up the domain and cache the result.
349+
auto result = lookUpInDeclContext(loc, declContext);
350+
if (result)
351+
storage.setPointer(*result);
352+
storage.setInt(true);
353+
354+
return result;
355+
}
356+
326357
/// Creates a new `AvailabilityDomainOrIdentifier`, defensively copying
327358
/// members of the original into the given `ASTContext` in case it is
328359
/// different than the context that the original was created for.
329360
AvailabilityDomainOrIdentifier copy(ASTContext &ctx) const;
361+
362+
void print(llvm::raw_ostream &os) const;
330363
};
331364

332365
} // end namespace swift

include/swift/AST/AvailabilitySpec.h

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ class SemanticAvailabilitySpec;
3535
/// The root class for specifications of API availability in availability
3636
/// queries.
3737
class AvailabilitySpec : public ASTAllocated<AvailabilitySpec> {
38-
using DomainStorage = llvm::PointerIntPair<AvailabilityDomainOrIdentifier, 1>;
39-
DomainStorage Storage;
38+
AvailabilityDomainOrIdentifier DomainOrIdentifier;
4039

4140
/// The range of the entire spec, including the version if there is one.
4241
SourceRange SrcRange;
@@ -51,14 +50,11 @@ class AvailabilitySpec : public ASTAllocated<AvailabilitySpec> {
5150
// Location of the availability macro expanded to create this spec.
5251
SourceLoc MacroLoc;
5352

54-
AvailabilitySpec(DomainStorage Storage, SourceRange SrcRange,
55-
llvm::VersionTuple Version, SourceLoc VersionStartLoc)
56-
: Storage(Storage), SrcRange(SrcRange), Version(Version),
57-
VersionStartLoc(VersionStartLoc) {}
58-
59-
AvailabilityDomainOrIdentifier getDomainOrIdentifier() const {
60-
return Storage.getPointer();
61-
}
53+
AvailabilitySpec(AvailabilityDomainOrIdentifier DomainOrIdentifier,
54+
SourceRange SrcRange, llvm::VersionTuple Version,
55+
SourceLoc VersionStartLoc)
56+
: DomainOrIdentifier(DomainOrIdentifier), SrcRange(SrcRange),
57+
Version(Version), VersionStartLoc(VersionStartLoc) {}
6258

6359
public:
6460
/// Creates a wildcard availability specification that guards execution
@@ -101,6 +97,10 @@ class AvailabilitySpec : public ASTAllocated<AvailabilitySpec> {
10197
return false;
10298
}
10399

100+
AvailabilityDomainOrIdentifier getDomainOrIdentifier() const {
101+
return DomainOrIdentifier;
102+
}
103+
104104
std::optional<AvailabilityDomain> getDomain() const {
105105
return getDomainOrIdentifier().getAsDomain();
106106
}
@@ -123,8 +123,15 @@ class AvailabilitySpec : public ASTAllocated<AvailabilitySpec> {
123123
// Location of the macro expanded to create this spec.
124124
SourceLoc getMacroLoc() const { return MacroLoc; }
125125
void setMacroLoc(SourceLoc loc) { MacroLoc = loc; }
126+
127+
void print(llvm::raw_ostream &os) const;
126128
};
127129

130+
inline void simple_display(llvm::raw_ostream &os,
131+
const AvailabilitySpec *spec) {
132+
spec->print(os);
133+
}
134+
128135
/// The type-checked representation of `AvailabilitySpec` which guaranatees that
129136
/// the spec has a valid `AvailabilityDomain`.
130137
class SemanticAvailabilitySpec {
@@ -153,6 +160,8 @@ class SemanticAvailabilitySpec {
153160
// This is required to support beta versions of macOS Big Sur that
154161
// report 10.16 at run time.
155162
llvm::VersionTuple getRuntimeVersion() const { return spec->getRawVersion(); }
163+
164+
void print(llvm::raw_ostream &os) const { spec->print(os); }
156165
};
157166

158167
/// Wraps an array of availability specs and provides an iterator for their

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6748,9 +6748,8 @@ WARNING(attr_availability_expected_version_spec, none,
67486748
"expected 'introduced', 'deprecated', or 'obsoleted' in '%0' attribute "
67496749
"for platform '%1'", (StringRef, StringRef))
67506750
ERROR(attr_availability_requires_custom_availability, none,
6751-
"specifying '%0' in '%1' attribute requires "
6752-
"-enable-experimental-feature CustomAvailability",
6753-
(StringRef, const DeclAttribute))
6751+
"%0 requires -enable-experimental-feature CustomAvailability",
6752+
(Identifier))
67546753
WARNING(attr_availability_unexpected_version,none,
67556754
"unexpected version number in '%0' attribute for '%1'",
67566755
(const DeclAttribute, StringRef))

lib/AST/ASTDumper.cpp

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,11 +1103,11 @@ namespace {
11031103
printRecArbitrary(
11041104
[&](Label label) {
11051105
printHead("availability_spec", PatternColor, label);
1106-
StringRef domainName =
1107-
Spec->isWildcard()
1108-
? "*"
1109-
: Spec->getDomain()->getNameForAttributePrinting();
1110-
printField(domainName, Label::always("domain"));
1106+
printFieldRaw(
1107+
[&](llvm::raw_ostream &OS) {
1108+
Spec->getDomainOrIdentifier().print(OS);
1109+
},
1110+
Label::always("domain"));
11111111
if (!Spec->getRawVersion().empty())
11121112
printFieldRaw(
11131113
[&](llvm::raw_ostream &OS) { OS << Spec->getRawVersion(); },
@@ -4944,13 +4944,8 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
49444944
void visitAvailableAttr(AvailableAttr *Attr, Label label) {
49454945
printCommon(Attr, "available_attr", label);
49464946

4947-
if (auto domain = Attr->getCachedDomain()) {
4948-
printField(domain->getNameForAttributePrinting(),
4949-
Label::always("domain"));
4950-
} else {
4951-
printField(*Attr->getDomainIdentifier(),
4952-
Label::always("domainIdentifier"));
4953-
}
4947+
printFieldRaw([&](auto &out) { Attr->getDomainOrIdentifier().print(out); },
4948+
Label::always("domain"));
49544949

49554950
switch (Attr->getKind()) {
49564951
case swift::AvailableAttr::Kind::Default:

lib/AST/Attr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2146,7 +2146,7 @@ AvailableAttr::AvailableAttr(
21462146
Bits.AvailableAttr.IsSPI = IsSPI;
21472147
Bits.AvailableAttr.IsGroupMember = false;
21482148
Bits.AvailableAttr.IsGroupTerminator = false;
2149-
Bits.AvailableAttr.IsAdjacentToWildcard = false;
2149+
Bits.AvailableAttr.IsGroupedWithWildcard = false;
21502150
}
21512151

21522152
AvailableAttr *AvailableAttr::createUniversallyUnavailable(ASTContext &C,

0 commit comments

Comments
 (0)