Skip to content

AST: Refactor AvailableAttr representation to use AvailabilityDomain #78541

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jan 11, 2025
Merged
69 changes: 28 additions & 41 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,9 @@ class DeclAttribute : public AttributeBase {
Value : 32
);

SWIFT_INLINE_BITFIELD(AvailableAttr, DeclAttribute, 8+8+1+1+1+1,
/// A `PlatformKind` value.
Platform : 8,

/// A `PlatformAgnosticAvailabilityKind` value.
PlatformAgnostic : 8,
SWIFT_INLINE_BITFIELD(AvailableAttr, DeclAttribute, 4+1+1+1+1,
/// An `AvailableAttr::Kind` value.
Kind : 4,

/// State storage for `RenamedDeclRequest`.
HasComputedRenamedDecl : 1,
Expand Down Expand Up @@ -719,38 +716,31 @@ enum class AvailableVersionComparison {
Obsoleted,
};

/// Describes the platform-agnostic availability of a declaration.
enum class PlatformAgnosticAvailabilityKind : uint8_t {
/// The associated availability attribute is not platform-agnostic.
None,
/// The declaration is deprecated, but can still be used.
Deprecated,
/// The declaration is unavailable in Swift, specifically
UnavailableInSwift,
/// The declaration is available in some but not all versions
/// of Swift, as specified by the VersionTuple members.
SwiftVersionSpecific,
/// The declaration is available in some but not all versions
/// of SwiftPM's PackageDescription library, as specified by
/// the VersionTuple members.
PackageDescriptionVersionSpecific,
/// The declaration is unavailable for other reasons.
Unavailable,
/// The declaration is unavailable from asynchronous contexts
NoAsync,
};

/// Defines the @available attribute.
class AvailableAttr : public DeclAttribute {
public:
AvailableAttr(SourceLoc AtLoc, SourceRange Range, PlatformKind Platform,
StringRef Message, StringRef Rename,
const llvm::VersionTuple &Introduced,
AvailabilityDomain Domain;

public:
enum class Kind : uint8_t {
/// The attribute does not specify `deprecated`, `unavailable`,
/// or `noasync`. Instead, it may specify `introduced:`, `deprecated:`, or
/// `obsoleted:` versions or it may simply have a `rename:` field.
Default,
/// The attribute specifies unconditional deprecation.
Deprecated,
/// The attribute specifies unconditional unavailability.
Unavailable,
/// The attribute specifies unavailability in asynchronous contexts.
NoAsync,
};

AvailableAttr(SourceLoc AtLoc, SourceRange Range,
const AvailabilityDomain &Domain, Kind Kind, StringRef Message,
StringRef Rename, const llvm::VersionTuple &Introduced,
SourceRange IntroducedRange,
const llvm::VersionTuple &Deprecated,
SourceRange DeprecatedRange,
const llvm::VersionTuple &Obsoleted, SourceRange ObsoletedRange,
PlatformAgnosticAvailabilityKind PlatformAgnostic,
bool Implicit, bool IsSPI, bool IsForEmbedded = false);

/// The optional message.
Expand Down Expand Up @@ -802,16 +792,13 @@ class AvailableAttr : public DeclAttribute {
/// Whether this attribute was spelled `@_unavailableInEmbedded`.
bool isForEmbedded() const { return Bits.AvailableAttr.IsForEmbedded; }

/// Returns the platform that the attribute applies to (may be `none`).
PlatformKind getPlatform() const {
return static_cast<PlatformKind>(Bits.AvailableAttr.Platform);
}
/// Returns the `AvailabilityDomain` associated with the attribute, or
/// `std::nullopt` if it has either not yet been resolved or could not be
/// resolved successfully.
std::optional<AvailabilityDomain> getCachedDomain() const { return Domain; }

/// Returns the platform-agnostic availability.
PlatformAgnosticAvailabilityKind getPlatformAgnosticAvailability() const {
return static_cast<PlatformAgnosticAvailabilityKind>(
Bits.AvailableAttr.PlatformAgnostic);
}
/// Returns the kind of availability the attribute specifies.
Kind getKind() const { return static_cast<Kind>(Bits.AvailableAttr.Kind); }

/// Create an `AvailableAttr` that specifies universal unavailability, e.g.
/// `@available(*, unavailable)`.
Expand Down
42 changes: 39 additions & 3 deletions include/swift/AST/AvailabilityDomain.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ class AvailabilityDomain final {
/// universally unavailable or deprecated, for example.
Universal,

/// Represents availability for a specific operating system platform.
Platform,

/// Represents availability with respect to Swift language mode.
SwiftLanguage,

/// Represents PackageDescription availability.
PackageDescription,

/// Represents availability for a specific operating system platform.
Platform,
};

private:
Expand All @@ -57,6 +57,8 @@ class AvailabilityDomain final {
};

public:
AvailabilityDomain() {}

static AvailabilityDomain forUniversal() {
return AvailabilityDomain(Kind::Universal);
}
Expand Down Expand Up @@ -96,6 +98,40 @@ class AvailabilityDomain final {

/// Returns the string to use when printing an `@available` attribute.
llvm::StringRef getNameForAttributePrinting() const;

bool operator==(const AvailabilityDomain &other) const {
if (getKind() != other.getKind())
return false;

switch (getKind()) {
case Kind::Universal:
case Kind::SwiftLanguage:
case Kind::PackageDescription:
// These availability domains are singletons.
return true;
case Kind::Platform:
return getPlatformKind() == other.getPlatformKind();
}
}

bool operator!=(const AvailabilityDomain &other) const {
return !(*this == other);
}

bool operator<(const AvailabilityDomain &other) const {
if (getKind() != other.getKind())
return getKind() < other.getKind();

switch (getKind()) {
case Kind::Universal:
case Kind::SwiftLanguage:
case Kind::PackageDescription:
// These availability domains are singletons.
return false;
case Kind::Platform:
return getPlatformKind() < other.getPlatformKind();
}
}
};

} // end namespace swift
Expand Down
26 changes: 21 additions & 5 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3892,11 +3892,23 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, StringRef>,
}
void visitAvailableAttr(AvailableAttr *Attr, StringRef label) {
printCommon(Attr, "available_attr", label);
printField(Attr->getPlatform(), "platform");
if (!Attr->Message.empty())
printFieldQuoted(Attr->Message, "message");
if (!Attr->Rename.empty())
printFieldQuoted(Attr->Rename, "rename");

if (auto domain = Attr->getCachedDomain())
printField(domain->getNameForAttributePrinting(), "platform");

switch (Attr->getKind()) {
case swift::AvailableAttr::Kind::Default:
break;
case swift::AvailableAttr::Kind::Deprecated:
printFlag("deprecated");
break;
case swift::AvailableAttr::Kind::Unavailable:
printFlag("unavailable");
break;
case swift::AvailableAttr::Kind::NoAsync:
printFlag("noasync");
break;
}
if (Attr->Introduced.has_value())
printFieldRaw(
[&](auto &out) { out << Attr->Introduced.value().getAsString(); },
Expand All @@ -3909,6 +3921,10 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, StringRef>,
printFieldRaw(
[&](auto &out) { out << Attr->Obsoleted.value().getAsString(); },
"obsoleted");
if (!Attr->Message.empty())
printFieldQuoted(Attr->Message, "message");
if (!Attr->Rename.empty())
printFieldQuoted(Attr->Rename, "rename");
printFoot();
}
void visitBackDeployedAttr(BackDeployedAttr *Attr, StringRef label) {
Expand Down
Loading