Skip to content

AST: Introduce SemanticAvailableAttr #78284

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 7 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 90 additions & 17 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "swift/AST/ASTAllocated.h"
#include "swift/AST/AttrKind.h"
#include "swift/AST/AutoDiff.h"
#include "swift/AST/AvailabilityDomain.h"
#include "swift/AST/ConcreteDeclRef.h"
#include "swift/AST/DeclNameLoc.h"
#include "swift/AST/Identifier.h"
Expand Down Expand Up @@ -782,12 +783,6 @@ class AvailableAttr : public DeclAttribute {
/// Indicates where the Obsoleted version was specified.
const SourceRange ObsoletedRange;

/// Whether this is a language-version-specific entity.
bool isLanguageVersionSpecific() const;

/// Whether this is a PackageDescription version specific entity.
bool isPackageDescriptionVersionSpecific() const;

/// Whether this is an unconditionally unavailable entity.
bool isUnconditionallyUnavailable() const;

Expand Down Expand Up @@ -831,17 +826,6 @@ class AvailableAttr : public DeclAttribute {
/// Returns true if this attribute is active given the current platform.
bool isActivePlatform(const ASTContext &ctx) const;

/// Returns the active version from the AST context corresponding to
/// the available kind. For example, this will return the effective language
/// version for swift version-specific availability kind, PackageDescription
/// version for PackageDescription version-specific availability.
llvm::VersionTuple getActiveVersion(const ASTContext &ctx) const;

/// Compare this attribute's version information against the platform or
/// language version (assuming the this attribute pertains to the active
/// platform).
AvailableVersionComparison getVersionAvailability(const ASTContext &ctx) const;

/// Create an AvailableAttr that indicates specific availability
/// for all platforms.
static AvailableAttr *
Expand Down Expand Up @@ -3190,6 +3174,95 @@ class ParsedDeclAttributes {
}
};

/// A wrapper for `AvailableAttr` that is enriched with additional semantic
/// informaton, like its corresponding `AvailabilityDomain`.
class SemanticAvailableAttr final {
const AvailableAttr *attr;
const AvailabilityDomain domain;

public:
SemanticAvailableAttr(const AvailableAttr *attr, AvailabilityDomain domain)
: attr(attr), domain(domain) {
assert(attr);
}

const AvailableAttr *getParsedAttr() const { return attr; }
const AvailabilityDomain getDomain() const { return domain; }

/// Returns the platform kind that the attribute applies to, or
/// `PlatformKind::none` if the attribute is not platform specific.
bool isPlatformSpecific() const { return domain.isPlatform(); }

/// Returns the platform kind that the attribute applies to, or
/// `PlatformKind::none` if the attribute is not platform specific.
PlatformKind getPlatformKind() const { return domain.getPlatformKind(); }

/// Whether this attribute has an introduced, deprecated, or obsoleted
/// version.
bool isVersionSpecific() const {
return attr->Introduced || attr->Deprecated || attr->Obsoleted;
}

/// Whether this is a language mode specific attribute.
bool isSwiftLanguageModeSpecific() const {
return domain.isSwiftLanguage() && isVersionSpecific();
}

/// Whether this is a PackageDescription version specific attribute.
bool isPackageDescriptionVersionSpecific() const {
return domain.isPackageDescription() && isVersionSpecific();
}

/// Returns the active version from the AST context corresponding to
/// the available kind. For example, this will return the effective language
/// version for swift version-specific availability kind, PackageDescription
/// version for PackageDescription version-specific availability.
llvm::VersionTuple getActiveVersion(const ASTContext &ctx) const;

/// Compare this attribute's version information against the platform or
/// language version (assuming the this attribute pertains to the active
/// platform).
AvailableVersionComparison
getVersionAvailability(const ASTContext &ctx) const;

/// Returns true if this attribute is considered active in the current
/// compilation context.
bool isActive(ASTContext &ctx) const;
};

/// An iterable range of `SemanticAvailableAttr`s.
class SemanticAvailableAttributes {
public:
class Filter final {
const Decl *decl;
bool includeInactive;

public:
Filter(const Decl *decl, bool includeInactive)
: decl(decl), includeInactive(includeInactive) {}

std::optional<SemanticAvailableAttr>
operator()(const DeclAttribute *attr) const;
};

using Range =
OptionalTransformRange<iterator_range<DeclAttributes::const_iterator>,
Filter>;

private:
Range attrRange;

public:
SemanticAvailableAttributes(const DeclAttributes &attrs, const Decl *decl,
bool includeInactive = false)
: attrRange(make_range(attrs.begin(), attrs.end()),
Filter(decl, includeInactive)) {}

Range::iterator begin() const { return attrRange.begin(); }
Range::iterator end() const { return attrRange.end(); }
bool empty() const { return attrRange.empty(); }
};

class alignas(1 << AttrAlignInBits) TypeAttribute
: public ASTAllocated<TypeAttribute> {
protected:
Expand Down
3 changes: 2 additions & 1 deletion include/swift/AST/Availability.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,8 @@ class AvailabilityInference {
annotatedAvailableRange(const Decl *D);

static AvailabilityRange
annotatedAvailableRangeForAttr(const SpecializeAttr *attr, ASTContext &ctx);
annotatedAvailableRangeForAttr(const Decl *D, const SpecializeAttr *attr,
ASTContext &ctx);

/// For the attribute's introduction version, update the platform and version
/// values to the re-mapped platform's, if using a fallback platform.
Expand Down
10 changes: 6 additions & 4 deletions include/swift/AST/AvailabilityDomain.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "swift/Basic/LLVM.h"

namespace swift {
class ASTContext;

/// Represents a dimension of availability (e.g. macOS platform or Swift
/// language mode).
Expand Down Expand Up @@ -83,10 +84,11 @@ class AvailabilityDomain final {
bool isPackageDescription() const { return kind == Kind::PackageDescription; }

/// Returns the platform kind for this domain if applicable.
PlatformKind getPlatformKind() const {
assert(kind == Kind::Platform);
return platform;
}
PlatformKind getPlatformKind() const { return platform; }

/// Returns true if this domain is considered active in the current
/// compilation context.
bool isActive(ASTContext &ctx) const;

/// Returns the string to use in diagnostics to identify the domain. May
/// return an empty string.
Expand Down
15 changes: 12 additions & 3 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1395,9 +1395,18 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
/// and its DeclContext does not.
bool isOutermostPrivateOrFilePrivateScope() const;

/// Returns the availability domain associated with the given `AvailableAttr`
/// that is attached to this decl.
AvailabilityDomain getDomainForAvailableAttr(const AvailableAttr *attr) const;
/// Returns an iterable list of the valid `AvailableAttr` and
/// `AvailabilityDomain` pairs. Unless \p includeInactive is true, attributes
/// that are considered inactive for the compilation context are filtered out.
SemanticAvailableAttributes
getSemanticAvailableAttrs(bool includeInactive = true) const;

/// Returns the SemanticAvailableAttr associated with the given
/// `AvailableAttr` that is attached to this decl. Returns `std::nullopt` if a
/// valid semantic version of the attribute cannot be constructed (e.g. the
/// domain cannot be resolved).
std::optional<SemanticAvailableAttr>
getSemanticAvailableAttr(const AvailableAttr *attr) const;

/// Returns the active platform-specific `@available` attribute for this decl.
/// There may be multiple `@available` attributes that are relevant to the
Expand Down
3 changes: 0 additions & 3 deletions include/swift/AST/PrintOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,9 +341,6 @@ struct PrintOptions {
/// Whether to print the internal layout name instead of AnyObject, etc.
bool PrintInternalLayoutName = false;

/// Suppress emitting @available(*, noasync)
bool SuppressNoAsyncAvailabilityAttr = false;

/// Suppress emitting isolated or async deinit, and emit open containing class
/// as public
bool SuppressIsolatedDeinit = false;
Expand Down
35 changes: 19 additions & 16 deletions lib/APIDigester/ModuleAnalyzerNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1339,14 +1339,16 @@ std::optional<uint8_t> SDKContext::getFixedBinaryOrder(ValueDecl *VD) const {
// check for if it has @available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
static bool isABIPlaceHolder(Decl *D) {
llvm::SmallSet<PlatformKind, 4> Platforms;
for (auto *ATT: D->getAttrs()) {
if (auto *AVA = dyn_cast<AvailableAttr>(ATT)) {
if (AVA->getPlatform() != PlatformKind::none && AVA->Introduced &&
AVA->Introduced->getMajor() == 9999) {
Platforms.insert(AVA->getPlatform());
}
for (auto semanticAttr : D->getSemanticAvailableAttrs()) {
auto attr = semanticAttr.getParsedAttr();
auto domain = semanticAttr.getDomain();
if (domain.isPlatform() && attr->Introduced &&
attr->Introduced->getMajor() == 9999) {
Platforms.insert(attr->getPlatform());
}
}

// FIXME: This probably isn't correct anymore, now that visionOS exists
return Platforms.size() == 4;
}

Expand All @@ -1361,11 +1363,11 @@ static bool isABIPlaceholderRecursive(Decl *D) {
StringRef SDKContext::getPlatformIntroVersion(Decl *D, PlatformKind Kind) {
if (!D)
return StringRef();
for (auto *ATT: D->getAttrs()) {
if (auto *AVA = dyn_cast<AvailableAttr>(ATT)) {
if (AVA->getPlatform() == Kind && AVA->Introduced) {
return buffer(AVA->Introduced->getAsString());
}
for (auto semanticAttr : D->getSemanticAvailableAttrs()) {
auto attr = semanticAttr.getParsedAttr();
auto domain = semanticAttr.getDomain();
if (domain.getPlatformKind() == Kind && attr->Introduced) {
return buffer(attr->Introduced->getAsString());
}
}
return StringRef();
Expand All @@ -1374,11 +1376,12 @@ StringRef SDKContext::getPlatformIntroVersion(Decl *D, PlatformKind Kind) {
StringRef SDKContext::getLanguageIntroVersion(Decl *D) {
if (!D)
return StringRef();
for (auto *ATT: D->getAttrs()) {
if (auto *AVA = dyn_cast<AvailableAttr>(ATT)) {
if (AVA->isLanguageVersionSpecific() && AVA->Introduced) {
return buffer(AVA->Introduced->getAsString());
}
for (auto semanticAttr : D->getSemanticAvailableAttrs()) {
auto attr = semanticAttr.getParsedAttr();
auto domain = semanticAttr.getDomain();

if (domain.isSwiftLanguage() && attr->Introduced) {
return buffer(attr->Introduced->getAsString());
}
}
return getLanguageIntroVersion(D->getDeclContext()->getAsDecl());
Expand Down
Loading