Skip to content

Commit 5bfccd0

Browse files
authored
Merge pull request #79260 from tshortli/more-availability-constraint-adoption
AST/Sema: Continue adopting AvailabilityConstraint
2 parents 5eca0fd + e804c93 commit 5bfccd0

18 files changed

+271
-306
lines changed

include/swift/AST/Attr.h

-23
Original file line numberDiff line numberDiff line change
@@ -703,23 +703,6 @@ class SwiftNativeObjCRuntimeBaseAttr : public DeclAttribute {
703703
}
704704
};
705705

706-
/// Determine the result of comparing an availability attribute to a specific
707-
/// platform or language version.
708-
enum class AvailableVersionComparison {
709-
/// The entity is guaranteed to be available.
710-
Available,
711-
712-
/// The entity is never available.
713-
Unavailable,
714-
715-
/// The entity might be unavailable at runtime, because it was introduced
716-
/// after the requested minimum platform version.
717-
PotentiallyUnavailable,
718-
719-
/// The entity has been obsoleted.
720-
Obsoleted,
721-
};
722-
723706
/// Defines the @available attribute.
724707
class AvailableAttr : public DeclAttribute {
725708
public:
@@ -3378,12 +3361,6 @@ class SemanticAvailableAttr final {
33783361
/// version for PackageDescription version-specific availability.
33793362
llvm::VersionTuple getActiveVersion(const ASTContext &ctx) const;
33803363

3381-
/// Compare this attribute's version information against the platform or
3382-
/// language version (assuming the this attribute pertains to the active
3383-
/// platform).
3384-
AvailableVersionComparison
3385-
getVersionAvailability(const ASTContext &ctx) const;
3386-
33873364
/// Returns true if this attribute is considered active in the current
33883365
/// compilation context.
33893366
bool isActive(ASTContext &ctx) const;

include/swift/AST/AvailabilityConstraint.h

+26-15
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/AvailabilityRange.h"
2323
#include "swift/AST/PlatformKind.h"
2424
#include "swift/Basic/LLVM.h"
25+
#include "swift/Basic/OptionSet.h"
2526

2627
namespace swift {
2728

@@ -33,6 +34,10 @@ class Decl;
3334
/// certain context.
3435
class AvailabilityConstraint {
3536
public:
37+
/// The reason that the availability constraint is unsatisfied.
38+
///
39+
/// NOTE: The order of this enum matters. Reasons are defined in descending
40+
/// priority order.
3641
enum class Reason {
3742
/// The declaration is referenced in a context in which it is generally
3843
/// unavailable. For example, a reference to a declaration that is
@@ -133,44 +138,50 @@ class AvailabilityConstraint {
133138
/// Returns the required range for `IntroducedInNewerVersion` requirements, or
134139
/// `std::nullopt` otherwise.
135140
std::optional<AvailabilityRange>
136-
getRequiredNewerAvailabilityRange(ASTContext &ctx) const;
141+
getRequiredNewerAvailabilityRange(const ASTContext &ctx) const;
137142

138143
/// Some availability constraints are active for type-checking but cannot
139144
/// be translated directly into an `if #available(...)` runtime query.
140-
bool isActiveForRuntimeQueries(ASTContext &ctx) const;
145+
bool isActiveForRuntimeQueries(const ASTContext &ctx) const;
141146
};
142147

143148
/// Represents a set of availability constraints that restrict use of a
144-
/// declaration in a particular context.
149+
/// declaration in a particular context. There can only be one active constraint
150+
/// for a given `AvailabilityDomain`, but there may be multiple active
151+
/// constraints from separate domains.
145152
class DeclAvailabilityConstraints {
146153
using Storage = llvm::SmallVector<AvailabilityConstraint, 4>;
147154
Storage constraints;
148155

149156
public:
150157
DeclAvailabilityConstraints() {}
158+
DeclAvailabilityConstraints(const Storage &&constraints)
159+
: constraints(constraints) {}
151160

152-
void addConstraint(const AvailabilityConstraint &constraint) {
153-
constraints.emplace_back(constraint);
154-
}
161+
/// Returns the strongest availability constraint or `std::nullopt` if empty.
162+
std::optional<AvailabilityConstraint> getPrimaryConstraint() const;
155163

156164
using const_iterator = Storage::const_iterator;
157165
const_iterator begin() const { return constraints.begin(); }
158166
const_iterator end() const { return constraints.end(); }
159167
};
160168

161-
/// Returns the `AvailabilityConstraint` that describes how \p attr restricts
162-
/// use of \p decl in \p context or `std::nullopt` if there is no restriction.
163-
std::optional<AvailabilityConstraint>
164-
getAvailabilityConstraintForAttr(const Decl *decl,
165-
const SemanticAvailableAttr &attr,
166-
const AvailabilityContext &context);
169+
enum class AvailabilityConstraintFlag : uint8_t {
170+
/// By default, the availability constraints for the members of extensions
171+
/// include the constraints for `@available` attributes that were written on
172+
/// the enclosing extension, since these members can be referred to without
173+
/// referencing the extension. When this flag is specified, though, only the
174+
/// attributes directly attached to the declaration are considered.
175+
SkipEnclosingExtension = 1 << 0,
176+
};
177+
using AvailabilityConstraintFlags = OptionSet<AvailabilityConstraintFlag>;
167178

168179
/// Returns the set of availability constraints that restrict use of \p decl
169180
/// when it is referenced from the given context. In other words, it is the
170181
/// collection of of `@available` attributes with unsatisfied conditions.
171-
DeclAvailabilityConstraints
172-
getAvailabilityConstraintsForDecl(const Decl *decl,
173-
const AvailabilityContext &context);
182+
DeclAvailabilityConstraints getAvailabilityConstraintsForDecl(
183+
const Decl *decl, const AvailabilityContext &context,
184+
AvailabilityConstraintFlags flags = std::nullopt);
174185
} // end namespace swift
175186

176187
#endif

lib/AST/Attr.cpp

-44
Original file line numberDiff line numberDiff line change
@@ -2294,50 +2294,6 @@ SemanticAvailableAttr::getActiveVersion(const ASTContext &ctx) const {
22942294
}
22952295
}
22962296

2297-
AvailableVersionComparison
2298-
SemanticAvailableAttr::getVersionAvailability(const ASTContext &ctx) const {
2299-
2300-
// Unconditional unavailability.
2301-
if (attr->isUnconditionallyUnavailable())
2302-
return AvailableVersionComparison::Unavailable;
2303-
2304-
llvm::VersionTuple queryVersion = getActiveVersion(ctx);
2305-
std::optional<llvm::VersionTuple> ObsoletedVersion = getObsoleted();
2306-
2307-
StringRef ObsoletedPlatform;
2308-
llvm::VersionTuple RemappedObsoletedVersion;
2309-
if (AvailabilityInference::updateObsoletedPlatformForFallback(
2310-
*this, ctx, ObsoletedPlatform, RemappedObsoletedVersion))
2311-
ObsoletedVersion = RemappedObsoletedVersion;
2312-
2313-
// If this entity was obsoleted before or at the query platform version,
2314-
// consider it obsolete.
2315-
if (ObsoletedVersion && *ObsoletedVersion <= queryVersion)
2316-
return AvailableVersionComparison::Obsoleted;
2317-
2318-
std::optional<llvm::VersionTuple> IntroducedVersion = getIntroduced();
2319-
StringRef IntroducedPlatform;
2320-
llvm::VersionTuple RemappedIntroducedVersion;
2321-
if (AvailabilityInference::updateIntroducedPlatformForFallback(
2322-
*this, ctx, IntroducedPlatform, RemappedIntroducedVersion))
2323-
IntroducedVersion = RemappedIntroducedVersion;
2324-
2325-
// If this entity was introduced after the query version and we're doing a
2326-
// platform comparison, true availability can only be determined dynamically;
2327-
// if we're doing a _language_ version check, the query version is a
2328-
// static requirement, so we treat "introduced later" as just plain
2329-
// unavailable.
2330-
if (IntroducedVersion && *IntroducedVersion > queryVersion) {
2331-
if (isSwiftLanguageModeSpecific() || isPackageDescriptionVersionSpecific())
2332-
return AvailableVersionComparison::Unavailable;
2333-
else
2334-
return AvailableVersionComparison::PotentiallyUnavailable;
2335-
}
2336-
2337-
// The entity is available.
2338-
return AvailableVersionComparison::Available;
2339-
}
2340-
23412297
SpecializeAttr::SpecializeAttr(SourceLoc atLoc, SourceRange range,
23422298
TrailingWhereClause *clause, bool exported,
23432299
SpecializationKind kind,

lib/AST/Availability.cpp

+6-42
Original file line numberDiff line numberDiff line change
@@ -573,49 +573,13 @@ bool Decl::isUnavailableInCurrentSwiftVersion() const {
573573
return false;
574574
}
575575

576-
std::optional<SemanticAvailableAttr> getDeclUnavailableAttr(const Decl *D) {
577-
auto &ctx = D->getASTContext();
578-
std::optional<SemanticAvailableAttr> result;
579-
auto bestActive = D->getActiveAvailableAttrForCurrentPlatform();
580-
581-
for (auto attr : D->getSemanticAvailableAttrs(/*includingInactive=*/false)) {
582-
// If this is a platform-specific attribute and it isn't the most
583-
// specific attribute for the current platform, we're done.
584-
if (attr.isPlatformSpecific() && (!bestActive || attr != bestActive))
585-
continue;
586-
587-
// Unconditional unavailable.
588-
if (attr.isUnconditionallyUnavailable())
589-
return attr;
590-
591-
switch (attr.getVersionAvailability(ctx)) {
592-
case AvailableVersionComparison::Available:
593-
case AvailableVersionComparison::PotentiallyUnavailable:
594-
break;
595-
596-
case AvailableVersionComparison::Obsoleted:
597-
case AvailableVersionComparison::Unavailable:
598-
result.emplace(attr);
599-
break;
600-
}
601-
}
602-
return result;
603-
}
604-
605576
std::optional<SemanticAvailableAttr> Decl::getUnavailableAttr() const {
606-
if (auto attr = getDeclUnavailableAttr(this))
607-
return attr;
608-
609-
// If D is an extension member, check if the extension is unavailable.
610-
//
611-
// Skip decls imported from Clang, they could be associated to the wrong
612-
// extension and inherit undesired unavailability. The ClangImporter
613-
// associates Objective-C protocol members to the first category where the
614-
// protocol is directly or indirectly adopted, no matter its availability
615-
// and the availability of other categories. rdar://problem/53956555
616-
if (!getClangNode())
617-
if (auto ext = dyn_cast<ExtensionDecl>(getDeclContext()))
618-
return ext->getUnavailableAttr();
577+
auto context = AvailabilityContext::forDeploymentTarget(getASTContext());
578+
if (auto constraint = getAvailabilityConstraintsForDecl(this, context)
579+
.getPrimaryConstraint()) {
580+
if (constraint->isUnavailable())
581+
return constraint->getAttr();
582+
}
619583

620584
return std::nullopt;
621585
}

0 commit comments

Comments
 (0)