Skip to content

Commit 34fab9f

Browse files
committed
AST: Implement Decl::isUnreachableAtRuntime() using a request.
1 parent 75b2750 commit 34fab9f

File tree

3 files changed

+71
-18
lines changed

3 files changed

+71
-18
lines changed

include/swift/AST/TypeCheckRequests.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4141,6 +4141,40 @@ class SemanticUnavailableAttrRequest
41414141
bool isCached() const { return true; }
41424142
};
41434143

4144+
enum class SemanticDeclAvailability : uint8_t {
4145+
/// The decl is potentially available in some contexts and/or under certain
4146+
/// deployment conditions.
4147+
PotentiallyAvailable,
4148+
4149+
/// The decl is always unavailable in the current compilation context.
4150+
/// However, it may still be used at runtime by other modules with different
4151+
/// settings. For example a decl that is obsolete in Swift 5 is still
4152+
/// available to other modules compiled for an earlier language mode.
4153+
ConditionallyUnavailable,
4154+
4155+
/// The decl is universally unavailable. For example, when compiling for macOS
4156+
/// a decl with `@available(macOS, unavailable)` can never be used (except in
4157+
/// contexts that are also completely unavailable on macOS).
4158+
CompletelyUnavailable,
4159+
};
4160+
4161+
class SemanticDeclAvailabilityRequest
4162+
: public SimpleRequest<SemanticDeclAvailabilityRequest,
4163+
SemanticDeclAvailability(const Decl *decl),
4164+
RequestFlags::Cached> {
4165+
public:
4166+
using SimpleRequest::SimpleRequest;
4167+
4168+
private:
4169+
friend SimpleRequest;
4170+
4171+
SemanticDeclAvailability evaluate(Evaluator &evaluator,
4172+
const Decl *decl) const;
4173+
4174+
public:
4175+
bool isCached() const { return true; }
4176+
};
4177+
41444178
class ClosureEffectsRequest
41454179
: public SimpleRequest<ClosureEffectsRequest,
41464180
FunctionType::ExtInfo(ClosureExpr *),

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,9 @@ SWIFT_REQUEST(TypeChecker, SemanticAvailableRangeAttrRequest,
475475
SWIFT_REQUEST(TypeChecker, SemanticUnavailableAttrRequest,
476476
Optional<AvailableAttrDeclPair>(const Decl *),
477477
Cached, NoLocationInfo)
478+
SWIFT_REQUEST(TypeChecker, SemanticDeclAvailabilityRequest,
479+
SemanticDeclAvailability(const Decl *),
480+
Cached, NoLocationInfo)
478481
SWIFT_REQUEST(TypeChecker, ClosureEffectsRequest,
479482
FunctionType::ExtInfo(ClosureExpr *),
480483
Cached, NoLocationInfo)

lib/AST/Availability.cpp

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -711,18 +711,13 @@ Decl::getSemanticUnavailableAttr(bool ignoreAppExtensions) const {
711711
std::nullopt);
712712
}
713713

714-
bool Decl::isUnreachableAtRuntime() const {
714+
static bool isDeclCompletelyUnavailable(const Decl *decl) {
715715
// Don't trust unavailability on declarations from clang modules.
716-
if (isa<ClangModuleUnit>(getDeclContext()->getModuleScopeContext()))
716+
if (isa<ClangModuleUnit>(decl->getDeclContext()->getModuleScopeContext()))
717717
return false;
718718

719-
if (auto *parent =
720-
AvailabilityInference::parentDeclForInferredAvailability(this)) {
721-
if (parent->isUnreachableAtRuntime())
722-
return true;
723-
}
724-
725-
auto *unavailableAttr = getUnavailableAttr(/*ignoreAppExtensions=*/true);
719+
auto *unavailableAttr =
720+
decl->getUnavailableAttr(/*ignoreAppExtensions=*/true);
726721
if (!unavailableAttr)
727722
return false;
728723

@@ -733,27 +728,48 @@ bool Decl::isUnreachableAtRuntime() const {
733728
if (!unavailableAttr->isUnconditionallyUnavailable())
734729
return false;
735730

736-
// getUnavailableAttr() can return an @available attribute that makes its
737-
// declaration unavailable conditionally due to deployment target. Only
738-
// stub or skip a declaration that is unavailable regardless of deployment
739-
// target.
740-
if (!unavailableAttr->isUnconditionallyUnavailable())
741-
return false;
742-
743-
// Universally unavailable declarations are always unreachable.
731+
// Universally unavailable declarations are always completely unavailable.
744732
if (unavailableAttr->getPlatform() == PlatformKind::none)
745733
return true;
746734

747735
// FIXME: Support zippered frameworks (rdar://125371621)
748736
// If we have a target variant (e.g. we're building a zippered macOS
749737
// framework) then the decl is only unreachable if it is unavailable for both
750738
// the primary target and the target variant.
751-
if (getASTContext().LangOpts.TargetVariant.has_value())
739+
if (decl->getASTContext().LangOpts.TargetVariant.has_value())
752740
return false;
753741

754742
return true;
755743
}
756744

745+
SemanticDeclAvailability
746+
SemanticDeclAvailabilityRequest::evaluate(Evaluator &evaluator,
747+
const Decl *decl) const {
748+
auto inherited = SemanticDeclAvailability::PotentiallyAvailable;
749+
if (auto *parent =
750+
AvailabilityInference::parentDeclForInferredAvailability(decl)) {
751+
inherited = evaluateOrDefault(
752+
evaluator, SemanticDeclAvailabilityRequest{parent}, inherited);
753+
}
754+
755+
if (inherited == SemanticDeclAvailability::CompletelyUnavailable ||
756+
isDeclCompletelyUnavailable(decl))
757+
return SemanticDeclAvailability::CompletelyUnavailable;
758+
759+
if (inherited == SemanticDeclAvailability::ConditionallyUnavailable ||
760+
decl->isUnavailable())
761+
return SemanticDeclAvailability::ConditionallyUnavailable;
762+
763+
return SemanticDeclAvailability::PotentiallyAvailable;
764+
}
765+
766+
bool Decl::isUnreachableAtRuntime() const {
767+
auto availability = evaluateOrDefault(
768+
getASTContext().evaluator, SemanticDeclAvailabilityRequest{this},
769+
SemanticDeclAvailability::PotentiallyAvailable);
770+
return availability == SemanticDeclAvailability::CompletelyUnavailable;
771+
}
772+
757773
static UnavailableDeclOptimization
758774
getEffectiveUnavailableDeclOptimization(ASTContext &ctx) {
759775
if (ctx.LangOpts.UnavailableDeclOptimizationMode.has_value())

0 commit comments

Comments
 (0)