Skip to content

Commit d56173e

Browse files
committed
[Runtime] Handle existential target types in swift_dynamicCastMetatypeImpl.
This fixes cases like `type is T.Type` when T is generic specialized to a protocol type. Note: the compiler can still optimize these checks away and will optimize this check down to `false` in some cases. We'll want to fix that as well. rdar://problem/56044443
1 parent a947f34 commit d56173e

File tree

2 files changed

+27
-1
lines changed

2 files changed

+27
-1
lines changed

stdlib/public/runtime/Casting.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,14 @@ swift_dynamicCastMetatypeImpl(const Metadata *sourceType,
11151115
}
11161116
break;
11171117

1118+
case MetadataKind::Existential: {
1119+
auto targetTypeAsExistential = static_cast<const ExistentialTypeMetadata *>(targetType);
1120+
for (auto protocol : targetTypeAsExistential->getProtocols())
1121+
if (!swift_conformsToProtocol(sourceType, protocol.getSwiftProtocol()))
1122+
return nullptr;
1123+
return origSourceType;
1124+
}
1125+
11181126
default:
11191127
// The cast succeeds only if the metadata pointers are statically
11201128
// equivalent.

test/Interpreter/generic_casts.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-run-simple-swift | %FileCheck %s
1+
// RUN: %target-run-simple-swift | %FileCheck --check-prefix CHECK --check-prefix CHECK-ONONE %s
22
// RUN: %target-build-swift -O %s -o %t/a.out.optimized
33
// RUN: %target-codesign %t/a.out.optimized
44
// RUN: %target-run %t/a.out.optimized | %FileCheck %s
@@ -101,6 +101,24 @@ func allMetasToAllMetas<T, U>(_: T.Type, _: U.Type) -> Bool {
101101
return T.self is U.Type
102102
}
103103

104+
protocol P {}
105+
struct PS: P {}
106+
enum PE: P {}
107+
class PC: P {}
108+
109+
func nongenericAnyIsP(type: Any.Type) -> Bool {
110+
return type is P.Type
111+
}
112+
func genericAnyIs<T>(type: Any.Type, to: T.Type) -> Bool {
113+
return type is T.Type
114+
}
115+
print("nongenericAnyIsP(type: PS.self)", nongenericAnyIsP(type: PS.self)) // CHECK: nongenericAnyIsP(type: PS.self) true
116+
print("genericAnyIs(type: PS.self, to: P.self)", genericAnyIs(type: PS.self, to: P.self)) // CHECK-ONONE: genericAnyIs(type: PS.self, to: P.self) true
117+
print("nongenericAnyIsP(type: PE.self)", nongenericAnyIsP(type: PE.self)) // CHECK: nongenericAnyIsP(type: PE.self) true
118+
print("genericAnyIs(type: PE.self, to: P.self)", genericAnyIs(type: PE.self, to: P.self)) // CHECK-ONONE: genericAnyIs(type: PE.self, to: P.self) true
119+
print("nongenericAnyIsP(type: PC.self)", nongenericAnyIsP(type: PC.self)) // CHECK: nongenericAnyIsP(type: PC.self) true
120+
print("genericAnyIs(type: PC.self, to: P.self)", genericAnyIs(type: PC.self, to: P.self)) // CHECK-ONONE: genericAnyIs(type: PC.self, to: P.self) true
121+
104122
print(allToInt(22)) // CHECK: 22
105123
print(anyToInt(44)) // CHECK: 44
106124
allToC(C()).print() // CHECK: C!

0 commit comments

Comments
 (0)