Skip to content

Commit dc8a0ac

Browse files
authored
Merge pull request #19217 from hamishknight/optional-to-archetype-swift5
[Sema] Restrict new optional-to-archetype casting behaviour to Swift 5 mode
2 parents 8ab8e75 + 6380a42 commit dc8a0ac

File tree

4 files changed

+112
-3
lines changed

4 files changed

+112
-3
lines changed

CHANGELOG.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,46 @@ CHANGELOG
2424
Swift 5.0
2525
---------
2626

27+
* [SR-7251][]:
28+
29+
In Swift 5 mode, attempting to declare a static property with the same name as a
30+
nested type is now always correctly rejected. Previously, it was possible to
31+
perform such a redeclaration in an extension of a generic type.
32+
33+
For example:
34+
```swift
35+
struct Foo<T> {}
36+
extension Foo {
37+
struct i {}
38+
39+
// compiler error: Invalid redeclaration of 'i'
40+
// (prior to Swift 5, this did not produce an error)
41+
static var i: Int { return 0 }
42+
}
43+
```
44+
45+
* [SR-4248][]:
46+
47+
In Swift 5 mode, when casting an optional value to a generic placeholder type,
48+
the compiler will be more conservative with the unwrapping of the value. The
49+
result of such a cast now more closely matches the result you would get in a
50+
non-generic context.
51+
52+
For example:
53+
```swift
54+
func forceCast<U>(_ value: Any?, to type: U.Type) -> U {
55+
return value as! U
56+
}
57+
58+
let value: Any? = 42
59+
print(forceCast(value, to: Any.self))
60+
// prints: Optional(42)
61+
// (prior to Swift 5, this would print: 42)
62+
63+
print(value as! Any)
64+
// prints: Optional(42)
65+
```
66+
2767
* [SE-0227][]:
2868

2969
Key paths now support the `\.self` keypath, which is a `WritableKeyPath`
@@ -7190,3 +7230,5 @@ Swift 1.0
71907230
[SR-2388]: <https://bugs.swift.org/browse/SR-2388>
71917231
[SR-2394]: <https://bugs.swift.org/browse/SR-2394>
71927232
[SR-2608]: <https://bugs.swift.org/browse/SR-2608>
7233+
[SR-4248]: <https://bugs.swift.org/browse/SR-4248>
7234+
[SR-7251]: <https://bugs.swift.org/browse/SR-7251>

lib/Sema/CSApply.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3400,8 +3400,11 @@ namespace {
34003400
// If the destination value type is 'AnyObject' when performing a
34013401
// bridging operation, or if the destination value type could dynamically
34023402
// be an optional type, leave any extra optionals on the source in place.
3403-
if (isBridgeToAnyObject || destValueType->canDynamicallyBeOptionalType(
3404-
/* includeExistential */ false)) {
3403+
// Only apply the latter condition in Swift 5 mode to best preserve
3404+
// compatibility with Swift 4.1's casting behaviour.
3405+
if (isBridgeToAnyObject || (tc.Context.isSwiftVersionAtLeast(5) &&
3406+
destValueType->canDynamicallyBeOptionalType(
3407+
/*includeExistential*/ false))) {
34053408
auto destOptionalsCount = destOptionals.size() - destExtraOptionals;
34063409
if (srcOptionals.size() > destOptionalsCount) {
34073410
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-emit-silgen -module-name generic_casts -Xllvm -sil-full-demangle -enable-sil-ownership %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-runtime %s
2+
// RUN: %target-swift-emit-silgen -swift-version 5 -module-name generic_casts -Xllvm -sil-full-demangle -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-emit-silgen -swift-version 4 -module-name generic_casts -Xllvm -sil-full-demangle -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)