diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 3523c04f5b3eb..cce4c9c2d318d 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -151,10 +151,14 @@ class DeclAttribute : public AttributeBase { Value : 32 ); - SWIFT_INLINE_BITFIELD(AvailableAttr, DeclAttribute, 4+1+1+1, + SWIFT_INLINE_BITFIELD(AvailableAttr, DeclAttribute, 4+1+1+1+1+1, /// An `AvailableAttr::Kind` value. Kind : 4, + /// State storage for `SemanticAvailableAttrRequest`. + HasComputedSemanticAttr : 1, + HasDomain : 1, + /// State storage for `RenamedDeclRequest`. HasComputedRenamedDecl : 1, HasRenamedDecl : 1, @@ -750,26 +754,32 @@ class AvailableAttr : public DeclAttribute { const StringRef Message; const StringRef Rename; - const std::optional Introduced; + const llvm::VersionTuple Introduced; const SourceRange IntroducedRange; - const std::optional Deprecated; + const llvm::VersionTuple Deprecated; const SourceRange DeprecatedRange; - const std::optional Obsoleted; + const llvm::VersionTuple Obsoleted; const SourceRange ObsoletedRange; public: /// Returns the parsed version for `introduced:`. std::optional getRawIntroduced() const { + if (Introduced.empty()) + return std::nullopt; return Introduced; } /// Returns the parsed version for `deprecated:`. std::optional getRawDeprecated() const { + if (Deprecated.empty()) + return std::nullopt; return Deprecated; } /// Returns the parsed version for `obsoleted:`. std::optional getRawObsoleted() const { + if (Obsoleted.empty()) + return std::nullopt; return Obsoleted; } @@ -806,14 +816,15 @@ class AvailableAttr : public DeclAttribute { /// 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 getCachedDomain() const { return Domain; } + std::optional getCachedDomain() const { + if (hasCachedDomain()) + return Domain; + return std::nullopt; + } /// Returns true if the `AvailabilityDomain` associated with the attribute /// has been resolved successfully. - bool hasCachedDomain() const { - // For now, domains are always set on construction of the attribute. - return true; - } + bool hasCachedDomain() const { return Bits.AvailableAttr.HasDomain; } /// Returns the kind of availability the attribute specifies. Kind getKind() const { return static_cast(Bits.AvailableAttr.Kind); } @@ -873,6 +884,17 @@ class AvailableAttr : public DeclAttribute { Bits.AvailableAttr.HasComputedRenamedDecl = true; Bits.AvailableAttr.HasRenamedDecl = hasRenamedDecl; } + +private: + friend class SemanticAvailableAttrRequest; + + bool hasComputedSemanticAttr() const { + return Bits.AvailableAttr.HasComputedSemanticAttr; + } + + void setComputedSemanticAttr() { + Bits.AvailableAttr.HasComputedSemanticAttr = true; + } }; /// Indicates that the given declaration is visible to Objective-C. @@ -3252,7 +3274,7 @@ class SemanticAvailableAttr final { /// The version tuple written in source for the `introduced:` component. std::optional getIntroduced() const { - return attr->Introduced; + return attr->getRawIntroduced(); } /// The source range of the `introduced:` component. @@ -3264,12 +3286,12 @@ class SemanticAvailableAttr final { /// The version tuple written in source for the `deprecated:` component. std::optional getDeprecated() const { - return attr->Deprecated; + return attr->getRawDeprecated(); } /// The version tuple written in source for the `obsoleted:` component. std::optional getObsoleted() const { - return attr->Obsoleted; + return attr->getRawObsoleted(); } /// Returns the `message:` field of the attribute, or an empty string. @@ -3302,7 +3324,8 @@ class SemanticAvailableAttr final { /// Whether this attribute has an introduced, deprecated, or obsoleted /// version. bool isVersionSpecific() const { - return attr->Introduced || attr->Deprecated || attr->Obsoleted; + return getIntroduced().has_value() || getDeprecated().has_value() || + getObsoleted().has_value(); } /// Whether this is a language mode specific attribute. diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 0fddd90a1614a..36161d468b10c 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -5225,6 +5225,27 @@ class CustomDerivativesRequest bool isCached() const { return true; } }; +class SemanticAvailableAttrRequest + : public SimpleRequest( + const AvailableAttr *, const Decl *), + RequestFlags::SeparatelyCached> { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + std::optional evaluate(Evaluator &evaluator, + const AvailableAttr *attr, + const Decl *decl) const; + +public: + bool isCached() const { return true; } + std::optional> getCachedResult() const; + void cacheResult(std::optional value) const; +}; + #define SWIFT_TYPEID_ZONE TypeChecker #define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def" #include "swift/Basic/DefineTypeIDZone.h" diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 7caaebc740b8e..cd2e22f845269 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -614,3 +614,8 @@ SWIFT_REQUEST(TypeChecker, CustomDerivativesRequest, SWIFT_REQUEST(TypeChecker, GenericTypeParamDeclGetValueTypeRequest, Type(GenericTypeParamDecl *), Cached, NoLocationInfo) + +SWIFT_REQUEST(TypeChecker, SemanticAvailableAttrRequest, + std::optional + (const AvailableAttr *, const Decl *), + SeparatelyCached, NoLocationInfo) diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 2d3bd310250b6..3b48deb966b7e 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -2108,8 +2108,6 @@ Type RawLayoutAttr::getResolvedCountType(StructDecl *sd) const { ErrorType::get(ctx)); } -#define INIT_VER_TUPLE(X) X(X.empty() ? std::optional() : X) - AvailableAttr::AvailableAttr( SourceLoc AtLoc, SourceRange Range, const AvailabilityDomain &Domain, Kind Kind, StringRef Message, StringRef Rename, @@ -2118,18 +2116,18 @@ AvailableAttr::AvailableAttr( const llvm::VersionTuple &Obsoleted, SourceRange ObsoletedRange, bool Implicit, bool IsSPI) : DeclAttribute(DeclAttrKind::Available, AtLoc, Range, Implicit), - Domain(Domain), Message(Message), Rename(Rename), - INIT_VER_TUPLE(Introduced), IntroducedRange(IntroducedRange), - INIT_VER_TUPLE(Deprecated), DeprecatedRange(DeprecatedRange), - INIT_VER_TUPLE(Obsoleted), ObsoletedRange(ObsoletedRange) { + Domain(Domain), Message(Message), Rename(Rename), Introduced(Introduced), + IntroducedRange(IntroducedRange), Deprecated(Deprecated), + DeprecatedRange(DeprecatedRange), Obsoleted(Obsoleted), + ObsoletedRange(ObsoletedRange) { Bits.AvailableAttr.Kind = static_cast(Kind); + Bits.AvailableAttr.HasComputedSemanticAttr = false; + Bits.AvailableAttr.HasDomain = true; Bits.AvailableAttr.HasComputedRenamedDecl = false; Bits.AvailableAttr.HasRenamedDecl = false; Bits.AvailableAttr.IsSPI = IsSPI; } -#undef INIT_VER_TUPLE - AvailableAttr *AvailableAttr::createUniversallyUnavailable(ASTContext &C, StringRef Message, StringRef Rename) { @@ -2197,12 +2195,9 @@ bool BackDeployedAttr::isActivePlatform(const ASTContext &ctx, AvailableAttr *AvailableAttr::clone(ASTContext &C, bool implicit) const { return new (C) AvailableAttr( implicit ? SourceLoc() : AtLoc, implicit ? SourceRange() : getRange(), - Domain, getKind(), Message, Rename, - Introduced ? *Introduced : llvm::VersionTuple(), - implicit ? SourceRange() : IntroducedRange, - Deprecated ? *Deprecated : llvm::VersionTuple(), - implicit ? SourceRange() : DeprecatedRange, - Obsoleted ? *Obsoleted : llvm::VersionTuple(), + Domain, getKind(), Message, Rename, Introduced, + implicit ? SourceRange() : IntroducedRange, Deprecated, + implicit ? SourceRange() : DeprecatedRange, Obsoleted, implicit ? SourceRange() : ObsoletedRange, implicit, isSPI()); } @@ -2292,7 +2287,7 @@ SemanticAvailableAttr::getVersionAvailability(const ASTContext &ctx) const { return AvailableVersionComparison::Unavailable; llvm::VersionTuple queryVersion = getActiveVersion(ctx); - std::optional ObsoletedVersion = attr->Obsoleted; + std::optional ObsoletedVersion = getObsoleted(); StringRef ObsoletedPlatform; llvm::VersionTuple RemappedObsoletedVersion; @@ -2305,7 +2300,7 @@ SemanticAvailableAttr::getVersionAvailability(const ASTContext &ctx) const { if (ObsoletedVersion && *ObsoletedVersion <= queryVersion) return AvailableVersionComparison::Obsoleted; - std::optional IntroducedVersion = attr->Introduced; + std::optional IntroducedVersion = getIntroduced(); StringRef IntroducedPlatform; llvm::VersionTuple RemappedIntroducedVersion; if (AvailabilityInference::updateIntroducedPlatformForFallback( diff --git a/lib/AST/Availability.cpp b/lib/AST/Availability.cpp index 6963b0f405271..89c698d67ee7e 100644 --- a/lib/AST/Availability.cpp +++ b/lib/AST/Availability.cpp @@ -447,7 +447,9 @@ Decl::getSemanticAvailableAttrs(bool includeInactive) const { std::optional Decl::getSemanticAvailableAttr(const AvailableAttr *attr) const { - return SemanticAvailableAttr(attr); + return evaluateOrDefault(getASTContext().evaluator, + SemanticAvailableAttrRequest{attr, this}, + std::nullopt); } std::optional @@ -792,10 +794,10 @@ SemanticAvailableAttr::getIntroducedRange(const ASTContext &Ctx) const { assert(getDomain().isActive(Ctx)); auto *attr = getParsedAttr(); - if (!attr->Introduced.has_value()) + if (!attr->getRawIntroduced().has_value()) return AvailabilityRange::alwaysAvailable(); - llvm::VersionTuple IntroducedVersion = attr->Introduced.value(); + llvm::VersionTuple IntroducedVersion = attr->getRawIntroduced().value(); StringRef Platform; llvm::VersionTuple RemappedIntroducedVersion; if (AvailabilityInference::updateIntroducedPlatformForFallback( diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 3cb245426e256..6b9c5d5fa37ca 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -2730,3 +2730,26 @@ void IsUnsafeRequest::cacheResult(bool value) const { auto *decl = std::get<0>(getStorage()); decl->setUnsafe(value); } + +//----------------------------------------------------------------------------// +// SemanticAvailableAttrRequest computation. +//----------------------------------------------------------------------------// + +std::optional> +SemanticAvailableAttrRequest::getCachedResult() const { + const AvailableAttr *attr = std::get<0>(getStorage()); + if (!attr->hasComputedSemanticAttr()) + return std::nullopt; + + if (!attr->hasCachedDomain()) { + return std::optional{}; + } + + return SemanticAvailableAttr(attr); +} + +void SemanticAvailableAttrRequest::cacheResult( + std::optional value) const { + AvailableAttr *attr = const_cast(std::get<0>(getStorage())); + attr->setComputedSemanticAttr(); +} diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 72c4e5918c230..9d9ceaacd6f14 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -8252,6 +8252,13 @@ ValueDecl *RenamedDeclRequest::evaluate(Evaluator &evaluator, return renamedDecl; } +std::optional +SemanticAvailableAttrRequest::evaluate(swift::Evaluator &evaluator, + const AvailableAttr *attr, + const Decl *decl) const { + return SemanticAvailableAttr(attr); +} + template static void forEachCustomAttribute( Decl *decl,