Skip to content

Commit 0dae9b3

Browse files
committed
[Runtime] Have swift_dynamicCast unwrap multiple levels of optionals in the source.
The real work is done in checkDynamicCastFromOptional. This code tried to unwrap the source and returned the payload on success. It only did this once, so a type like Optional<Optional<Int>> would come out as Optional<Int> and then a cast to Int would fail. This change makes checkDynamicCastFromOptional recursive, which makes it unwrap as many levels of Optional as it encounters. Fixes rdar://problem/40171034 and SR-7664.
1 parent c239420 commit 0dae9b3

File tree

2 files changed

+21
-1
lines changed

2 files changed

+21
-1
lines changed

stdlib/public/runtime/Casting.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1866,7 +1866,7 @@ checkDynamicCastFromOptional(OpaqueValue *dest,
18661866
// .Some
18671867
// Single payload enums are guaranteed layout compatible with their
18681868
// payload. Only the source's payload needs to be taken or destroyed.
1869-
return {false, payloadType};
1869+
return checkDynamicCastFromOptional(dest, src, payloadType, targetType, flags);
18701870
}
18711871

18721872
/******************************************************************************/

test/stdlib/Casts.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,26 @@ CastsTests.test("No overrelease of existential boxes in failed casts") {
5050

5151
extension Int : P {}
5252

53+
// Test for SR-7664: Inconsistent optional casting behaviour with generics
54+
// Runtime failed to unwrap multiple levels of Optional when casting.
55+
CastsTests.test("Multi-level optionals can be casted") {
56+
func testSuccess<From, To>(_ x: From, from: From.Type, to: To.Type) {
57+
expectNotNil(x as? To)
58+
}
59+
func testFailure<From, To>(_ x: From, from: From.Type, to: To.Type) {
60+
expectNil(x as? To)
61+
}
62+
testSuccess(42, from: Int?.self, to: Int.self)
63+
testSuccess(42, from: Int??.self, to: Int.self)
64+
testSuccess(42, from: Int???.self, to: Int.self)
65+
testSuccess(42, from: Int???.self, to: Int?.self)
66+
testSuccess(42, from: Int???.self, to: Int??.self)
67+
testSuccess(42, from: Int???.self, to: Int???.self)
68+
testFailure(42, from: Int?.self, to: String.self)
69+
testFailure(42, from: Int??.self, to: String.self)
70+
testFailure(42, from: Int???.self, to: String.self)
71+
}
72+
5373
#if _runtime(_ObjC)
5474
extension CFBitVector : P {
5575
static func makeImmutable(from values: Array<UInt8>) -> CFBitVector {

0 commit comments

Comments
 (0)