Skip to content

Commit 78f50ba

Browse files
committed
AST: Refactor ConditionallyAvailableSubstitutions to use AvailabilityQuery.
Conditionally available opaque return types should support availability conditions that are evaluated in any availability domain. Update `ConditionallyAvailableSubstitutions` to model its conditions with `AvailabilityQuery` instead of assuming that conditions are always a single version query for the current platform.
1 parent cadae7d commit 78f50ba

File tree

7 files changed

+75
-62
lines changed

7 files changed

+75
-62
lines changed

include/swift/AST/AvailabilityQuery.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,15 @@ class AvailabilityQuery final {
6262
isUnavailable, std::nullopt, std::nullopt);
6363
}
6464

65+
/// Returns an `AvailabilityQuery` for a query that evaluates to true or
66+
/// false at compile-time in the universal availability domain.
67+
static AvailabilityQuery universallyConstant(bool isUnavailable, bool value) {
68+
return AvailabilityQuery(AvailabilityDomain::forUniversal(),
69+
value ? ResultKind::ConstTrue
70+
: ResultKind::ConstFalse,
71+
isUnavailable, std::nullopt, std::nullopt);
72+
}
73+
6574
/// Returns an `AvailabilityQuery` for a query that must be evaluated at
6675
/// runtime with the given arguments, which may be zero, one, or two version
6776
/// tuples that should be passed to the query function.

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/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/Sema/MiscDiagnostics.cpp

Lines changed: 7 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,20 @@ 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,
3791+
{AvailabilityQuery::universallyConstant(/*isUnavailable=*/false,
3792+
/*value=*/true)},
37973793
universalSubstMap.mapReplacementTypesOutOfContext()));
37983794

37993795
OpaqueDecl->setConditionallyAvailableSubstitutions(

lib/Serialization/Deserialization.cpp

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4558,13 +4558,17 @@ class DeclDeserializer {
45584558
return deserializeAnyFunc(scratch, blobData, /*isAccessor*/true);
45594559
}
45604560

4561-
void deserializeConditionalSubstitutionConditions(
4562-
SmallVectorImpl<OpaqueTypeDecl::AvailabilityCondition> &conditions) {
4561+
void deserializeConditionalSubstitutionAvailabilityQueries(
4562+
SmallVectorImpl<AvailabilityQuery> &queries) {
45634563
using namespace decls_block;
45644564

45654565
SmallVector<uint64_t, 4> scratch;
45664566
StringRef blobData;
45674567

4568+
// FIXME: [availability] Support arbitrary domains (rdar://156513787).
4569+
auto domain = ctx.getTargetAvailabilityDomain();
4570+
ASSERT(domain.isPlatform());
4571+
45684572
while (true) {
45694573
llvm::BitstreamEntry entry =
45704574
MF.fatalIfUnexpected(MF.DeclTypeCursor.advance(AF_DontPopBlockAtEnd));
@@ -4579,16 +4583,16 @@ class DeclDeserializer {
45794583
break;
45804584

45814585
bool isUnavailability;
4582-
DEF_VER_TUPLE_PIECES(condition);
4586+
DEF_VER_TUPLE_PIECES(version);
45834587

45844588
ConditionalSubstitutionConditionLayout::readRecord(
4585-
scratch, isUnavailability, LIST_VER_TUPLE_PIECES(condition));
4589+
scratch, isUnavailability, LIST_VER_TUPLE_PIECES(version));
45864590

4587-
llvm::VersionTuple condition;
4588-
DECODE_VER_TUPLE(condition);
4591+
llvm::VersionTuple version;
4592+
DECODE_VER_TUPLE(version);
45894593

4590-
conditions.push_back(std::make_pair(VersionRange::allGTE(condition),
4591-
isUnavailability));
4594+
queries.push_back(AvailabilityQuery::dynamic(
4595+
domain, isUnavailability, AvailabilityRange(version), std::nullopt));
45924596
}
45934597
}
45944598

@@ -4615,10 +4619,10 @@ class DeclDeserializer {
46154619
decls_block::ConditionalSubstitutionLayout::readRecord(
46164620
scratch, substitutionMapRef);
46174621

4618-
SmallVector<OpaqueTypeDecl::AvailabilityCondition, 2> conditions;
4619-
deserializeConditionalSubstitutionConditions(conditions);
4622+
SmallVector<AvailabilityQuery, 2> queries;
4623+
deserializeConditionalSubstitutionAvailabilityQueries(queries);
46204624

4621-
if (conditions.empty())
4625+
if (queries.empty())
46224626
return MF.diagnoseAndConsumeFatal();
46234627

46244628
auto subMapOrError = MF.getSubstitutionMapChecked(substitutionMapRef);
@@ -4627,7 +4631,7 @@ class DeclDeserializer {
46274631

46284632
limitedAvailability.push_back(
46294633
OpaqueTypeDecl::ConditionallyAvailableSubstitutions::get(
4630-
ctx, conditions, subMapOrError.get()));
4634+
ctx, queries, subMapOrError.get()));
46314635
}
46324636
}
46334637

@@ -4725,7 +4729,9 @@ class DeclDeserializer {
47254729
} else {
47264730
limitedAvailability.push_back(
47274731
OpaqueTypeDecl::ConditionallyAvailableSubstitutions::get(
4728-
ctx, {{VersionRange::all(), /*unavailability=*/false}},
4732+
ctx,
4733+
{AvailabilityQuery::universallyConstant(
4734+
/*isUnavailable=*/false, /*value=*/true)},
47294735
subMapOrError.get()));
47304736

47314737
opaqueDecl->setConditionallyAvailableSubstitutions(limitedAvailability);

lib/Serialization/Serialization.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4905,12 +4905,18 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
49054905

49064906
unsigned condAbbrCode =
49074907
S.DeclTypeAbbrCodes[ConditionalSubstitutionConditionLayout::Code];
4908-
for (const auto &condition : subs->getAvailability()) {
4909-
ENCODE_VER_TUPLE(osVersion, std::optional<llvm::VersionTuple>(
4910-
condition.first.getLowerEndpoint()));
4908+
for (const auto &query : subs->getAvailabilityQueries()) {
4909+
// FIXME: [availability] Support arbitrary domains (rdar://156513787).
4910+
DEBUG_ASSERT(query.getDomain().isPlatform());
4911+
4912+
auto availableRange = query.getPrimaryRange().value_or(
4913+
AvailabilityRange::alwaysAvailable());
4914+
4915+
ENCODE_VER_TUPLE(osVersion,
4916+
std::optional<llvm::VersionTuple>(
4917+
availableRange.getRawMinimumVersion()));
49114918
ConditionalSubstitutionConditionLayout::emitRecord(
4912-
S.Out, S.ScratchRecord, condAbbrCode,
4913-
/*isUnavailable=*/condition.second,
4919+
S.Out, S.ScratchRecord, condAbbrCode, query.isUnavailability(),
49144920
LIST_VER_TUPLE_PIECES(osVersion));
49154921
}
49164922
}

0 commit comments

Comments
 (0)