Skip to content

Commit 0247760

Browse files
authored
Merge pull request #83580 from tshortli/refactor-opaque-type-availability
AST: Refactor `ConditionallyAvailableSubstitutions` to use `AvailabilityQuery`
2 parents 7acd104 + b4fb7c8 commit 0247760

File tree

10 files changed

+105
-88
lines changed

10 files changed

+105
-88
lines changed

include/swift/AST/AvailabilityQuery.h

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,31 +46,50 @@ class AvailabilityQuery final {
4646
bool unavailable;
4747

4848
AvailabilityQuery(AvailabilityDomain domain, ResultKind kind,
49-
bool isUnavailable,
5049
const std::optional<AvailabilityRange> &primaryRange,
5150
const std::optional<AvailabilityRange> &variantRange)
5251
: domain(domain), primaryRange(primaryRange), variantRange(variantRange),
53-
kind(kind), unavailable(isUnavailable) {};
52+
kind(kind), unavailable(false) {};
5453

5554
public:
5655
/// Returns an `AvailabilityQuery` for a query that evaluates to true or
5756
/// false at compile-time.
58-
static AvailabilityQuery constant(AvailabilityDomain domain,
59-
bool isUnavailable, bool value) {
57+
static AvailabilityQuery constant(AvailabilityDomain domain, bool value) {
6058
return AvailabilityQuery(
6159
domain, value ? ResultKind::ConstTrue : ResultKind::ConstFalse,
62-
isUnavailable, std::nullopt, std::nullopt);
60+
std::nullopt, std::nullopt);
61+
}
62+
63+
/// Returns an `AvailabilityQuery` for a query that evaluates to true or
64+
/// false at compile-time in the universal availability domain.
65+
static AvailabilityQuery universallyConstant(bool value) {
66+
return AvailabilityQuery(AvailabilityDomain::forUniversal(),
67+
value ? ResultKind::ConstTrue
68+
: ResultKind::ConstFalse,
69+
std::nullopt, std::nullopt);
6370
}
6471

6572
/// Returns an `AvailabilityQuery` for a query that must be evaluated at
6673
/// runtime with the given arguments, which may be zero, one, or two version
6774
/// tuples that should be passed to the query function.
6875
static AvailabilityQuery
69-
dynamic(AvailabilityDomain domain, bool isUnavailable,
76+
dynamic(AvailabilityDomain domain,
7077
const std::optional<AvailabilityRange> &primaryRange,
7178
const std::optional<AvailabilityRange> &variantRange) {
72-
return AvailabilityQuery(domain, ResultKind::Dynamic, isUnavailable,
73-
primaryRange, variantRange);
79+
return AvailabilityQuery(domain, ResultKind::Dynamic, primaryRange,
80+
variantRange);
81+
}
82+
83+
/// Returns a copy of the `AvailabilityQuery` that has been modified to
84+
/// represent an `if #unavailable` query if `isUnavailability` is true, or an
85+
/// `if #available` query otherwise.
86+
AvailabilityQuery asUnavailable(bool isUnavailability) const {
87+
if (isUnavailability != unavailable) {
88+
AvailabilityQuery copy = *this;
89+
copy.unavailable = isUnavailability;
90+
return copy;
91+
}
92+
return *this;
7493
}
7594

7695
/// Returns the domain that the query applies to.

include/swift/AST/Decl.h

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "swift/AST/AccessScope.h"
2121
#include "swift/AST/Attr.h"
22+
#include "swift/AST/AvailabilityQuery.h"
2223
#include "swift/AST/AvailabilityRange.h"
2324
#include "swift/AST/CaptureInfo.h"
2425
#include "swift/AST/ClangNode.h"
@@ -3697,40 +3698,37 @@ class OpaqueTypeDecl final :
36973698
return false;
36983699
}
36993700

3700-
using AvailabilityCondition = std::pair<VersionRange, bool>;
3701-
37023701
class ConditionallyAvailableSubstitutions final
3703-
: private llvm::TrailingObjects<
3704-
ConditionallyAvailableSubstitutions,
3705-
AvailabilityCondition> {
3702+
: private llvm::TrailingObjects<ConditionallyAvailableSubstitutions,
3703+
AvailabilityQuery> {
37063704
friend TrailingObjects;
37073705

3708-
unsigned NumAvailabilityConditions;
3706+
unsigned NumAvailabilityQueries;
37093707

37103708
SubstitutionMap Substitutions;
37113709

37123710
/// A type with limited availability described by the provided set
37133711
/// of availability conditions (with `and` relationship).
37143712
ConditionallyAvailableSubstitutions(
3715-
ArrayRef<AvailabilityCondition> availabilityContext,
3713+
ArrayRef<AvailabilityQuery> availabilityQueries,
37163714
SubstitutionMap substitutions)
3717-
: NumAvailabilityConditions(availabilityContext.size()),
3715+
: NumAvailabilityQueries(availabilityQueries.size()),
37183716
Substitutions(substitutions) {
3719-
assert(!availabilityContext.empty());
3720-
std::uninitialized_copy(availabilityContext.begin(),
3721-
availabilityContext.end(),
3722-
getTrailingObjects<AvailabilityCondition>());
3717+
assert(!availabilityQueries.empty());
3718+
std::uninitialized_copy(availabilityQueries.begin(),
3719+
availabilityQueries.end(),
3720+
getTrailingObjects<AvailabilityQuery>());
37233721
}
37243722

37253723
public:
3726-
ArrayRef<AvailabilityCondition> getAvailability() const {
3727-
return {getTrailingObjects<AvailabilityCondition>(), NumAvailabilityConditions};
3724+
ArrayRef<AvailabilityQuery> getAvailabilityQueries() const {
3725+
return {getTrailingObjects<AvailabilityQuery>(), NumAvailabilityQueries};
37283726
}
37293727

37303728
SubstitutionMap getSubstitutions() const { return Substitutions; }
37313729

37323730
static ConditionallyAvailableSubstitutions *
3733-
get(ASTContext &ctx, ArrayRef<AvailabilityCondition> availabilityContext,
3731+
get(ASTContext &ctx, ArrayRef<AvailabilityQuery> availabilityContext,
37343732
SubstitutionMap substitutions);
37353733
};
37363734
};

lib/AST/AvailabilityScopeBuilder.cpp

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -816,8 +816,7 @@ class AvailabilityScopeBuilder : private ASTWalker {
816816

817817
AvailabilityQuery buildAvailabilityQuery(
818818
const SemanticAvailabilitySpec spec,
819-
const std::optional<SemanticAvailabilitySpec> &variantSpec,
820-
bool isUnavailability) {
819+
const std::optional<SemanticAvailabilitySpec> &variantSpec) {
821820
auto domain = spec.getDomain();
822821

823822
// Variant availability specfications are only supported for platform
@@ -850,37 +849,34 @@ class AvailabilityScopeBuilder : private ASTWalker {
850849
// If all of the specs that matched are '*', then the query trivially
851850
// evaluates to "true" at compile time.
852851
if (!variantRange)
853-
return AvailabilityQuery::constant(domain, isUnavailability, true);
852+
return AvailabilityQuery::constant(domain, true);
854853

855854
// Otherwise, generate a dynamic query for the variant spec. For example,
856855
// when compiling zippered for macOS, this should generate a query that
857856
// just checks the iOS version at runtime:
858857
//
859858
// if #available(iOS 18, *) { ... }
860859
//
861-
return AvailabilityQuery::dynamic(variantSpec->getDomain(),
862-
isUnavailability, primaryRange,
860+
return AvailabilityQuery::dynamic(variantSpec->getDomain(), primaryRange,
863861
variantRange);
864862

865863
case AvailabilityDomain::Kind::Platform:
866864
// Platform checks are always dynamic. The SIL optimizer is responsible
867865
// eliminating these checks when it can prove that they can never fail
868866
// (due to the deployment target). We can't perform that analysis here
869867
// because it may depend on inlining.
870-
return AvailabilityQuery::dynamic(domain, isUnavailability, primaryRange,
871-
variantRange);
868+
return AvailabilityQuery::dynamic(domain, primaryRange, variantRange);
872869
case AvailabilityDomain::Kind::Custom:
873870
auto customDomain = domain.getCustomDomain();
874871
ASSERT(customDomain);
875872

876873
switch (customDomain->getKind()) {
877874
case CustomAvailabilityDomain::Kind::Enabled:
878-
return AvailabilityQuery::constant(domain, isUnavailability, true);
875+
return AvailabilityQuery::constant(domain, true);
879876
case CustomAvailabilityDomain::Kind::Disabled:
880-
return AvailabilityQuery::constant(domain, isUnavailability, false);
877+
return AvailabilityQuery::constant(domain, false);
881878
case CustomAvailabilityDomain::Kind::Dynamic:
882-
return AvailabilityQuery::dynamic(domain, isUnavailability,
883-
primaryRange, variantRange);
879+
return AvailabilityQuery::dynamic(domain, primaryRange, variantRange);
884880
}
885881
}
886882
}
@@ -1053,8 +1049,9 @@ class AvailabilityScopeBuilder : private ASTWalker {
10531049
? bestActiveSpecForQuery(query, /*ForTargetVariant*/ true)
10541050
: std::nullopt;
10551051

1056-
query->setAvailabilityQuery(buildAvailabilityQuery(
1057-
*spec, variantSpec, query->isUnavailability()));
1052+
query->setAvailabilityQuery(
1053+
buildAvailabilityQuery(*spec, variantSpec)
1054+
.asUnavailable(query->isUnavailability()));
10581055

10591056
// Wildcards are expected to be "useless". There may be other specs in
10601057
// this query that are useful when compiling for other platforms.

lib/AST/Decl.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10881,14 +10881,12 @@ void OpaqueTypeDecl::setConditionallyAvailableSubstitutions(
1088110881

1088210882
OpaqueTypeDecl::ConditionallyAvailableSubstitutions *
1088310883
OpaqueTypeDecl::ConditionallyAvailableSubstitutions::get(
10884-
ASTContext &ctx,
10885-
ArrayRef<AvailabilityCondition> availabilityContext,
10884+
ASTContext &ctx, ArrayRef<AvailabilityQuery> availabilityQueries,
1088610885
SubstitutionMap substitutions) {
10887-
auto size =
10888-
totalSizeToAlloc<AvailabilityCondition>(availabilityContext.size());
10886+
auto size = totalSizeToAlloc<AvailabilityQuery>(availabilityQueries.size());
1088910887
auto mem = ctx.Allocate(size, alignof(ConditionallyAvailableSubstitutions));
1089010888
return new (mem)
10891-
ConditionallyAvailableSubstitutions(availabilityContext, substitutions);
10889+
ConditionallyAvailableSubstitutions(availabilityQueries, substitutions);
1089210890
}
1089310891

1089410892
bool AbstractFunctionDecl::hasInlinableBodyText() const {

lib/IRGen/GenMeta.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2704,30 +2704,30 @@ namespace {
27042704

27052705
// Emit a #available condition check, if it's `false` -
27062706
// jump to the next conditionally available type.
2707-
auto conditions = underlyingTy->getAvailability();
2707+
auto queries = underlyingTy->getAvailabilityQueries();
27082708

27092709
SmallVector<llvm::BasicBlock *, 4> conditionBlocks;
2710-
for (unsigned condIndex : indices(conditions)) {
2710+
for (unsigned queryIndex : indices(queries)) {
27112711
// cond-<type_idx>-<cond_index>
27122712
conditionBlocks.push_back(IGF.createBasicBlock(
2713-
"cond-" + llvm::utostr(i) + "-" + llvm::utostr(condIndex)));
2713+
"cond-" + llvm::utostr(i) + "-" + llvm::utostr(queryIndex)));
27142714
}
27152715

27162716
// Jump to the first condition.
27172717
IGF.Builder.CreateBr(conditionBlocks.front());
27182718

2719-
for (unsigned condIndex : indices(conditions)) {
2720-
const auto &condition = conditions[condIndex];
2719+
for (unsigned queryIndex : indices(queries)) {
2720+
const auto &query = queries[queryIndex];
27212721

2722-
assert(condition.first.hasLowerEndpoint());
2722+
assert(query.getPrimaryArgument());
27232723

2724-
bool isUnavailability = condition.second;
2725-
auto version = condition.first.getLowerEndpoint();
2724+
bool isUnavailability = query.isUnavailability();
2725+
auto version = query.getPrimaryArgument().value();
27262726
auto *major = getInt32Constant(version.getMajor());
27272727
auto *minor = getInt32Constant(version.getMinor());
27282728
auto *patch = getInt32Constant(version.getSubminor());
27292729

2730-
IGF.Builder.emitBlock(conditionBlocks[condIndex]);
2730+
IGF.Builder.emitBlock(conditionBlocks[queryIndex]);
27312731

27322732
auto isAtLeast =
27332733
IGF.emitTargetOSVersionAtLeastCall(major, minor, patch);
@@ -2742,9 +2742,9 @@ namespace {
27422742
IGF.Builder.CreateXor(success, IGF.Builder.getIntN(1, -1));
27432743
}
27442744

2745-
auto nextCondOrRet = condIndex == conditions.size() - 1
2745+
auto nextCondOrRet = queryIndex == queries.size() - 1
27462746
? returnTypeBB
2747-
: conditionBlocks[condIndex + 1];
2747+
: conditionBlocks[queryIndex + 1];
27482748

27492749
IGF.Builder.CreateCondBr(success, nextCondOrRet,
27502750
conditionalTypes[i + 1]);
@@ -2761,8 +2761,8 @@ namespace {
27612761
IGF.Builder.emitBlock(conditionalTypes.back());
27622762
auto universal = substitutionSet.back();
27632763

2764-
assert(universal->getAvailability().size() == 1 &&
2765-
universal->getAvailability()[0].first.isAll());
2764+
assert(universal->getAvailabilityQueries().size() == 1 &&
2765+
universal->getAvailabilityQueries()[0].isConstant());
27662766

27672767
IGF.Builder.CreateRet(
27682768
getResultValue(IGF, genericEnv, universal->getSubstitutions()));

lib/SILGen/SILGenAvailability.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,14 +131,13 @@ getAvailabilityQueryForBackDeployment(AbstractFunctionDecl *AFD) {
131131
variantRange = variantAttrAndRange->second;
132132

133133
return AvailabilityQuery::dynamic(attr->getAvailabilityDomain(),
134-
/*isUnavailable=*/false, primaryRange,
135-
variantRange);
134+
primaryRange, variantRange);
136135
}
137136

138137
if (auto primaryAttrAndRange = AFD->getBackDeployedAttrAndRange(ctx))
139138
return AvailabilityQuery::dynamic(
140139
primaryAttrAndRange->first->getAvailabilityDomain(),
141-
/*isUnavailable=*/false, primaryAttrAndRange->second, std::nullopt);
140+
primaryAttrAndRange->second, std::nullopt);
142141

143142
return std::nullopt;
144143
}

lib/Sema/DerivedConformance/DerivedConformanceRawRepresentable.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,7 @@ struct RuntimeVersionCheck {
218218
// This won't be filled in by TypeCheckAvailability because we have
219219
// invalid SourceLocs in this area of the AST.
220220
availableInfo->setAvailabilityQuery(AvailabilityQuery::dynamic(
221-
domain, /*isUnavailable=*/false, AvailabilityRange(getVersionRange()),
222-
std::nullopt));
221+
domain, AvailabilityRange(getVersionRange()), std::nullopt));
223222

224223
// earlyReturnBody = "{ return nil }"
225224
auto earlyReturn = new (C) FailStmt(SourceLoc(), SourceLoc());

lib/Sema/MiscDiagnostics.cpp

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3721,8 +3721,6 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
37213721
// There is no clear winner here since there are candidates within
37223722
// limited availability contexts.
37233723
void finalizeOpaque(const Candidate &universallyAvailable) {
3724-
using AvailabilityCondition = OpaqueTypeDecl::AvailabilityCondition;
3725-
37263724
SmallVector<OpaqueTypeDecl::ConditionallyAvailableSubstitutions *, 4>
37273725
conditionalSubstitutions;
37283726
SubstitutionMap universalSubstMap = std::get<1>(universallyAvailable);
@@ -3735,7 +3733,7 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
37353733
continue;
37363734

37373735
unsigned neverAvailableCount = 0, alwaysAvailableCount = 0;
3738-
SmallVector<AvailabilityCondition, 4> conditions;
3736+
SmallVector<AvailabilityQuery, 4> queries;
37393737

37403738
for (const auto &elt : stmt->getCond()) {
37413739
auto availabilityQuery = elt.getAvailability()->getAvailabilityQuery();
@@ -3762,11 +3760,7 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
37623760
auto domain = availabilityQuery->getDomain();
37633761
ASSERT(domain.isPlatform());
37643762

3765-
auto availabilityRange = availabilityQuery->getPrimaryRange();
3766-
ASSERT(availabilityRange);
3767-
3768-
conditions.push_back({availabilityRange->getRawVersionRange(),
3769-
availabilityQuery->isUnavailability()});
3763+
queries.push_back(*availabilityQuery);
37703764
}
37713765

37723766
// If there were any conditions that were always false, then this
@@ -3782,18 +3776,18 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
37823776
break;
37833777
}
37843778

3785-
ASSERT(conditions.size() > 0);
3779+
ASSERT(queries.size() > 0);
37863780

37873781
conditionalSubstitutions.push_back(
37883782
OpaqueTypeDecl::ConditionallyAvailableSubstitutions::get(
3789-
Ctx, conditions,
3783+
Ctx, queries,
37903784
std::get<1>(candidate).mapReplacementTypesOutOfContext()));
37913785
}
37923786

37933787
// Add universally available choice as the last one.
37943788
conditionalSubstitutions.push_back(
37953789
OpaqueTypeDecl::ConditionallyAvailableSubstitutions::get(
3796-
Ctx, {{VersionRange::all(), /*unavailable=*/false}},
3790+
Ctx, {AvailabilityQuery::universallyConstant(true)},
37973791
universalSubstMap.mapReplacementTypesOutOfContext()));
37983792

37993793
OpaqueDecl->setConditionallyAvailableSubstitutions(

0 commit comments

Comments
 (0)