Skip to content

Commit cce0296

Browse files
committed
AST/SILGen: Make availability ranges stored by PoundAvailableInfo optional.
Rather than representing a missing availability range on `PoundAvailableInfo` with a default-constructed `AvailabilityRange` (empty), store the ranges as optionals instead. This allows an empty range to represent an availability condition which is known to be false at compile time, which will be necessary when generating SIL for `if #available` queries that check custom availability domains.
1 parent e943c4b commit cce0296

File tree

3 files changed

+53
-22
lines changed

3 files changed

+53
-22
lines changed

include/swift/AST/Stmt.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -482,15 +482,15 @@ class alignas(8) PoundAvailableInfo final :
482482

483483
/// The version range when this query will return true. This value is
484484
/// filled in by Sema.
485-
VersionRange AvailableRange;
485+
std::optional<VersionRange> AvailableRange;
486486

487487
/// For zippered builds, this is the version range for the target variant
488488
/// that must hold for the query to return true. For example, when
489489
/// compiling with target x86_64-macosx10.15 and target-variant
490490
/// x86_64-ios13.0 a query of #available(macOS 10.22, iOS 20.0, *) will
491491
/// have a variant range of [20.0, +inf).
492492
/// This is filled in by Sema.
493-
VersionRange VariantAvailableRange;
493+
std::optional<VersionRange> VariantAvailableRange;
494494

495495
struct {
496496
unsigned isInvalid : 1;
@@ -538,11 +538,13 @@ class alignas(8) PoundAvailableInfo final :
538538
SourceLoc getLoc() const { return PoundLoc; }
539539
SourceRange getSourceRange() const { return SourceRange(getStartLoc(),
540540
getEndLoc()); }
541-
542-
const VersionRange &getAvailableRange() const { return AvailableRange; }
541+
542+
std::optional<VersionRange> getAvailableRange() const {
543+
return AvailableRange;
544+
}
543545
void setAvailableRange(const VersionRange &Range) { AvailableRange = Range; }
544546

545-
const VersionRange &getVariantAvailableRange() const {
547+
std::optional<VersionRange> getVariantAvailableRange() const {
546548
return VariantAvailableRange;
547549
}
548550
void setVariantAvailableRange(const VersionRange &Range) {

lib/SILGen/SILGenDecl.cpp

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1939,12 +1939,23 @@ void SILGenFunction::emitStmtCondition(StmtCondition Cond, JumpDest FalseDest,
19391939
// Check the running OS version to determine whether it is in the range
19401940
// specified by elt.
19411941
PoundAvailableInfo *availability = elt.getAvailability();
1942-
VersionRange OSVersion = availability->getAvailableRange();
1942+
1943+
// Creates a boolean literal for availability conditions that have been
1944+
// evaluated at compile time. Automatically inverts the value for
1945+
// `#unavailable` queries.
1946+
auto createBooleanTestLiteral = [&](bool value) {
1947+
SILType i1 = SILType::getBuiltinIntegerType(1, getASTContext());
1948+
if (availability->isUnavailability())
1949+
value = !value;
1950+
return B.createIntegerLiteral(loc, i1, value);
1951+
};
1952+
1953+
auto versionRange = availability->getAvailableRange();
19431954

19441955
// The OS version might be left empty if availability checking was
19451956
// disabled. Treat it as always-true in that case.
1946-
assert(!OSVersion.isEmpty()
1947-
|| getASTContext().LangOpts.DisableAvailabilityChecking);
1957+
assert(versionRange.has_value() ||
1958+
getASTContext().LangOpts.DisableAvailabilityChecking);
19481959

19491960
if (getASTContext().LangOpts.TargetVariant &&
19501961
!getASTContext().LangOpts.DisableAvailabilityChecking) {
@@ -1954,25 +1965,34 @@ void SILGenFunction::emitStmtCondition(StmtCondition Cond, JumpDest FalseDest,
19541965
// into. In a macOS process it will use the macOS version; in an
19551966
// macCatalyst process it will use the iOS version.
19561967

1957-
VersionRange VariantOSVersion =
1968+
auto variantVersionRange =
19581969
elt.getAvailability()->getVariantAvailableRange();
1959-
assert(!VariantOSVersion.isEmpty());
1960-
booleanTestValue =
1961-
emitZipperedOSVersionRangeCheck(loc, OSVersion, VariantOSVersion);
1970+
assert(variantVersionRange.has_value());
1971+
1972+
if (versionRange && variantVersionRange) {
1973+
booleanTestValue = emitZipperedOSVersionRangeCheck(
1974+
loc, *versionRange, *variantVersionRange);
1975+
} else {
1976+
// Type checking did not fill in versions so as a fallback treat this
1977+
// condition as trivially true.
1978+
booleanTestValue = createBooleanTestLiteral(true);
1979+
}
19621980
break;
19631981
}
19641982

1965-
if (OSVersion.isEmpty() || OSVersion.isAll()) {
1966-
// If there's no check for the current platform, this condition is
1967-
// trivially true (or false, for unavailability).
1968-
SILType i1 = SILType::getBuiltinIntegerType(1, getASTContext());
1969-
bool value = !availability->isUnavailability();
1970-
booleanTestValue = B.createIntegerLiteral(loc, i1, value);
1983+
if (!versionRange) {
1984+
// Type checking did not fill in version so as a fallback treat this
1985+
// condition as trivially true.
1986+
booleanTestValue = createBooleanTestLiteral(true);
1987+
} else if (versionRange->isAll()) {
1988+
booleanTestValue = createBooleanTestLiteral(true);
1989+
} else if (versionRange->isEmpty()) {
1990+
booleanTestValue = createBooleanTestLiteral(false);
19711991
} else {
19721992
bool isMacCatalyst =
19731993
tripleIsMacCatalystEnvironment(getASTContext().LangOpts.Target);
1974-
booleanTestValue = emitOSVersionRangeCheck(loc, OSVersion,
1975-
isMacCatalyst);
1994+
booleanTestValue =
1995+
emitOSVersionRangeCheck(loc, versionRange.value(), isMacCatalyst);
19761996
if (availability->isUnavailability()) {
19771997
// If this is an unavailability check, invert the result
19781998
// by emitting a call to Builtin.xor_Int1(lhs, -1).

lib/Sema/MiscDiagnostics.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3656,9 +3656,18 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
36563656
auto condition = elt.getAvailability();
36573657

36583658
auto availabilityRange = condition->getAvailableRange();
3659+
3660+
// Type checking did not set a range for this query (it may be invalid).
3661+
// Treat the condition as if it were always true.
3662+
if (!availabilityRange.has_value()) {
3663+
alwaysAvailableCount++;
3664+
continue;
3665+
}
3666+
36593667
// If there is no lower endpoint it means that the condition has no
36603668
// OS version specification that matches the target platform.
3661-
if (!availabilityRange.hasLowerEndpoint()) {
3669+
// FIXME: [availability] Handle empty ranges (never available).
3670+
if (!availabilityRange->hasLowerEndpoint()) {
36623671
// An inactive #unavailable condition trivially evaluates to false.
36633672
if (condition->isUnavailability()) {
36643673
neverAvailableCount++;
@@ -3671,7 +3680,7 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
36713680
}
36723681

36733682
conditions.push_back(
3674-
{availabilityRange, condition->isUnavailability()});
3683+
{*availabilityRange, condition->isUnavailability()});
36753684
}
36763685

36773686
// If there were any conditions that were always false, then this

0 commit comments

Comments
 (0)