Skip to content

Commit 498721c

Browse files
committed
[TypeChecker] SE-360: Add support for if #unavailable
Lift a temporary restriction and make `if #available` and `if #unavailable` behave consistently.
1 parent 225341e commit 498721c

File tree

5 files changed

+29
-11
lines changed

5 files changed

+29
-11
lines changed

lib/IRGen/GenMeta.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2335,6 +2335,7 @@ namespace {
23352335

23362336
assert(condition.first.hasLowerEndpoint());
23372337

2338+
bool isUnavailability = condition.second;
23382339
auto version = condition.first.getLowerEndpoint();
23392340
auto *major = getInt32Constant(version.getMajor());
23402341
auto *minor = getInt32Constant(version.getMinor());
@@ -2348,6 +2349,13 @@ namespace {
23482349
auto success = IGF.Builder.CreateICmpNE(
23492350
isAtLeast, llvm::Constant::getNullValue(IGM.Int32Ty));
23502351

2352+
if (isUnavailability) {
2353+
// Invert the result of "at least" check by xor'ing resulting
2354+
// boolean with `-1`.
2355+
success =
2356+
IGF.Builder.CreateXor(success, IGF.Builder.getIntN(1, -1));
2357+
}
2358+
23512359
auto nextCondOrRet = condIndex == conditions.size() - 1
23522360
? returnTypeBB
23532361
: conditionBlocks[condIndex + 1];

lib/Sema/MiscDiagnostics.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2886,12 +2886,10 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
28862886
return {true, S};
28872887
}
28882888

2889-
// If this is `if #available` statement with no other dynamic
2889+
// If this is `if #(un)available` statement with no other dynamic
28902890
// conditions, let's check if it returns opaque type directly.
28912891
if (llvm::all_of(If->getCond(), [&](const auto &condition) {
2892-
return condition.getKind() ==
2893-
StmtConditionElement::CK_Availability &&
2894-
!condition.getAvailability()->isUnavailability();
2892+
return condition.getKind() == StmtConditionElement::CK_Availability;
28952893
})) {
28962894
// Check return statement directly with availability context set.
28972895
if (auto *Then = dyn_cast<BraceStmt>(If->getThenStmt())) {

test/Serialization/Inputs/opaque_with_limited_availability.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ public func test() -> some P {
5252
return Empty()
5353
}
5454

55+
public func testUnavailable() -> some P {
56+
if #unavailable(macOS 100.0.1) {
57+
return Tuple<(Int, Int)>((0, 1))
58+
}
59+
60+
return Empty()
61+
}
62+
5563
public func test_return_from_conditional() -> some P {
5664
if #available(macOS 10.15, *) {
5765
return Named()

test/Serialization/opaque_with_availability_cross_module.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,7 @@ Test().sayHello()
4545
let conditionalR = LimitedAvailOpaque.test_return_from_conditional()
4646
conditionalR.hello()
4747
// CHECK: Hello from Named
48+
49+
let unavailableTest = LimitedAvailOpaque.testUnavailable()
50+
unavailableTest.hello()
51+
// CHECK: Hello from Tuple

test/type/opaque_with_conditional_availability.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,14 @@ func test_fail_without_universally_available_type() -> some P {
107107
}
108108
}
109109

110-
// Treat `if #unavailable` like regular conditions.
111-
func test_fail_with_unavailability_condition() -> some P {
112-
// expected-error@-1 {{function declares an opaque return type 'some P', but the return statements in its body do not have matching underlying types}}
113-
// expected-note@-2 {{add @available attribute to enclosing global function}}
110+
func test_unavailability_condition() -> some P {
114111
if #unavailable(macOS 12) {
115-
return X() // expected-error {{'X' is only available in macOS 11.0 or newer}} expected-note {{return statement has underlying type 'X'}}
116-
// expected-note@-1 {{add 'if #available' version check}}
112+
return Y()
117113
}
118114

119-
return Y() // expected-note {{return statement has underlying type 'Y'}}
115+
if #available(macOS 16, *) {
116+
return X()
117+
}
118+
119+
return Z()
120120
}

0 commit comments

Comments
 (0)