Skip to content

Commit c7c298d

Browse files
committed
[Sema] Restrict new optional-to-archetype casting behaviour to Swift 5 mode
In swiftlang#13910, the behaviour of optional-to-archetype casts changed such that we're now more conservative with the unwrapping of the operand at compile time in order to account for the fact that an optional type could be substituted at runtime. This brought such casting behaviour inline with that in a non-generic context, however it wasn't properly gated by Swift version, leading to compatibility issues. This commit restricts the new behaviour to Swift 5 mode and above. Resolves SR-8704.
1 parent f4134eb commit c7c298d

File tree

3 files changed

+70
-3
lines changed

3 files changed

+70
-3
lines changed

lib/Sema/CSApply.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3509,8 +3509,11 @@ namespace {
35093509
// If the destination value type is 'AnyObject' when performing a
35103510
// bridging operation, or if the destination value type could dynamically
35113511
// be an optional type, leave any extra optionals on the source in place.
3512-
if (isBridgeToAnyObject || destValueType->canDynamicallyBeOptionalType(
3513-
/* includeExistential */ false)) {
3512+
// Only apply the latter condition in Swift 5 mode to best preserve
3513+
// compatibility with Swift 4.1's casting behaviour.
3514+
if (isBridgeToAnyObject || (tc.Context.isSwiftVersionAtLeast(5) &&
3515+
destValueType->canDynamicallyBeOptionalType(
3516+
/*includeExistential*/ false))) {
35143517
auto destOptionalsCount = destOptionals.size() - destExtraOptionals;
35153518
if (srcOptionals.size() > destOptionalsCount) {
35163519
srcType = srcOptionals[destOptionalsCount];

test/SILGen/generic_casts.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
// RUN: %target-swift-frontend -module-name generic_casts -Xllvm -sil-full-demangle -emit-silgen -enable-sil-ownership %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-runtime %s
2+
// RUN: %target-swift-frontend -swift-version 5 -module-name generic_casts -Xllvm -sil-full-demangle -emit-silgen -enable-sil-ownership %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-runtime %s
33

44
protocol ClassBound : class {}
55
protocol NotClassBound {}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
2+
// RUN: %target-swift-frontend -swift-version 4 -module-name generic_casts -Xllvm -sil-full-demangle -emit-silgen -enable-sil-ownership %s | %FileCheck %s
3+
4+
// The below tests are to ensure we maintain compatibility with Swift 4.1's
5+
// behaviour when casting to an archetype – the compiler assumes a non-optional
6+
// archetype is non-optional, and therefore can unwrap the source.
7+
8+
// CHECK-LABEL: sil hidden @$S13generic_casts32optional_any_to_opaque_archetype{{[_0-9a-zA-Z]*}}F
9+
func optional_any_to_opaque_archetype<T>(_ x: Any?) -> T {
10+
return x as! T
11+
// CHECK: bb0([[RET:%.*]] : @trivial $*T, {{%.*}} : @trivial $*Optional<Any>):
12+
// CHECK: unconditional_checked_cast_addr Any in {{%.*}} : $*Any to T in [[RET]] : $*T
13+
}
14+
15+
// CHECK-LABEL: sil hidden @$S13generic_casts46optional_any_conditionally_to_opaque_archetype{{[_0-9a-zA-Z]*}}F
16+
func optional_any_conditionally_to_opaque_archetype<T>(_ x: Any?) -> T? {
17+
return x as? T
18+
// CHECK: checked_cast_addr_br take_always Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
19+
}
20+
21+
// CHECK-LABEL: sil hidden @$S13generic_casts32optional_any_is_opaque_archetype{{[_0-9a-zA-Z]*}}F
22+
func optional_any_is_opaque_archetype<T>(_ x: Any?, _: T) -> Bool {
23+
return x is T
24+
// CHECK: checked_cast_addr_br take_always Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
25+
}
26+
27+
// CHECK-LABEL: sil hidden @$S13generic_casts016optional_any_to_C17_opaque_archetype{{[_0-9a-zA-Z]*}}F
28+
func optional_any_to_optional_opaque_archetype<T>(_ x: Any?) -> T? {
29+
return x as! T?
30+
// CHECK: unconditional_checked_cast_addr Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
31+
}
32+
33+
// CHECK-LABEL: sil hidden @$S13generic_casts030optional_any_conditionally_to_C17_opaque_archetype{{[_0-9a-zA-Z]*}}F
34+
func optional_any_conditionally_to_optional_opaque_archetype<T>(_ x: Any?) -> T?? {
35+
return x as? T?
36+
// CHECK: checked_cast_addr_br take_always Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
37+
}
38+
39+
// CHECK-LABEL: sil hidden @$S13generic_casts016optional_any_is_C17_opaque_archetype{{[_0-9a-zA-Z]*}}F
40+
func optional_any_is_optional_opaque_archetype<T>(_ x: Any?, _: T) -> Bool {
41+
return x is T?
42+
// Because the levels of optional are the same, 'is' doesn't transform into an 'as?',
43+
// so we just cast directly without digging into the optional operand.
44+
// CHECK: checked_cast_addr_br take_always Optional<Any> in {{%.*}} : $*Optional<Any> to Optional<T> in {{%.*}} : $*Optional<T>
45+
}
46+
47+
// CHECK-LABEL: sil hidden @$S13generic_casts31optional_any_to_class_archetype{{[_0-9a-zA-Z]*}}F
48+
func optional_any_to_class_archetype<T : AnyObject>(_ x: Any?) -> T {
49+
return x as! T
50+
// CHECK: unconditional_checked_cast_addr Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
51+
}
52+
53+
// CHECK-LABEL: sil hidden @$S13generic_casts45optional_any_conditionally_to_class_archetype{{[_0-9a-zA-Z]*}}F
54+
func optional_any_conditionally_to_class_archetype<T : AnyObject>(_ x: Any?) -> T? {
55+
return x as? T
56+
// CHECK: checked_cast_addr_br take_always Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
57+
}
58+
59+
// CHECK-LABEL: sil hidden @$S13generic_casts31optional_any_is_class_archetype{{[_0-9a-zA-Z]*}}F
60+
func optional_any_is_class_archetype<T : AnyObject>(_ x: Any?, _: T) -> Bool {
61+
return x is T
62+
// CHECK: checked_cast_addr_br take_always Any in {{%.*}} : $*Any to T in {{%.*}} : $*T
63+
}
64+

0 commit comments

Comments
 (0)