Skip to content

Commit 8dc43e6

Browse files
authored
Merge pull request swiftlang#27572 from mikeash/protocol-existential-crisis
[Runtime] Handle existential target types in swift_dynamicCastMetatypeImpl
2 parents ece5ab7 + b05e009 commit 8dc43e6

File tree

3 files changed

+96
-2
lines changed

3 files changed

+96
-2
lines changed

stdlib/public/runtime/Casting.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ static bool _conformsToProtocols(const OpaqueValue *value,
403403
for (auto protocol : existentialType->getProtocols()) {
404404
if (!_conformsToProtocol(value, type, protocol, conformances))
405405
return false;
406-
if (protocol.needsWitnessTable()) {
406+
if (conformances != nullptr && protocol.needsWitnessTable()) {
407407
assert(*conformances != nullptr);
408408
++conformances;
409409
}
@@ -1115,6 +1115,13 @@ swift_dynamicCastMetatypeImpl(const Metadata *sourceType,
11151115
}
11161116
break;
11171117

1118+
case MetadataKind::Existential: {
1119+
auto targetTypeAsExistential = static_cast<const ExistentialTypeMetadata *>(targetType);
1120+
if (!_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr))
1121+
return nullptr;
1122+
return origSourceType;
1123+
}
1124+
11181125
default:
11191126
// The cast succeeds only if the metadata pointers are statically
11201127
// equivalent.

test/Interpreter/generic_casts.swift

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
// RUN: %target-run-simple-swift | %FileCheck %s
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -Onone %s -o %t/a.out
3+
// RUN: %target-run %t/a.out | %FileCheck --check-prefix CHECK --check-prefix CHECK-ONONE %s
24
// RUN: %target-build-swift -O %s -o %t/a.out.optimized
35
// RUN: %target-codesign %t/a.out.optimized
46
// RUN: %target-run %t/a.out.optimized | %FileCheck %s
@@ -131,6 +133,58 @@ anyClassToCOrE(C()).print() // CHECK: C!
131133
anyClassToCOrE(D()).print() // CHECK: D!
132134
anyClassToCOrE(X()).print() // CHECK: E!
133135

136+
protocol P {}
137+
struct PS: P {}
138+
enum PE: P {}
139+
class PC: P {}
140+
class PCSub: PC {}
141+
142+
func nongenericAnyIsP(type: Any.Type) -> Bool {
143+
return type is P.Type
144+
}
145+
func nongenericAnyIsPAndAnyObject(type: Any.Type) -> Bool {
146+
return type is (P & AnyObject).Type
147+
}
148+
func nongenericAnyIsPAndPCSub(type: Any.Type) -> Bool {
149+
return type is (P & PCSub).Type
150+
}
151+
func genericAnyIs<T>(type: Any.Type, to: T.Type) -> Bool {
152+
return type is T.Type
153+
}
154+
// CHECK-LABEL: casting types to protocols with generics:
155+
print("casting types to protocols with generics:")
156+
print(nongenericAnyIsP(type: PS.self)) // CHECK: true
157+
print(genericAnyIs(type: PS.self, to: P.self)) // CHECK-ONONE: true
158+
print(nongenericAnyIsP(type: PE.self)) // CHECK: true
159+
print(genericAnyIs(type: PE.self, to: P.self)) // CHECK-ONONE: true
160+
print(nongenericAnyIsP(type: PC.self)) // CHECK: true
161+
print(genericAnyIs(type: PC.self, to: P.self)) // CHECK-ONONE: true
162+
print(nongenericAnyIsP(type: PCSub.self)) // CHECK: true
163+
print(genericAnyIs(type: PCSub.self, to: P.self)) // CHECK-ONONE: true
164+
165+
// CHECK-LABEL: casting types to protocol & AnyObject existentials:
166+
print("casting types to protocol & AnyObject existentials:")
167+
print(nongenericAnyIsPAndAnyObject(type: PS.self)) // CHECK: false
168+
print(genericAnyIs(type: PS.self, to: (P & AnyObject).self)) // CHECK: false
169+
print(nongenericAnyIsPAndAnyObject(type: PE.self)) // CHECK: false
170+
print(genericAnyIs(type: PE.self, to: (P & AnyObject).self)) // CHECK: false
171+
print(nongenericAnyIsPAndAnyObject(type: PC.self)) // CHECK: true
172+
print(genericAnyIs(type: PC.self, to: (P & AnyObject).self)) // CHECK-ONONE: true
173+
print(nongenericAnyIsPAndAnyObject(type: PCSub.self)) // CHECK: true
174+
print(genericAnyIs(type: PCSub.self, to: (P & AnyObject).self)) // CHECK-ONONE: true
175+
176+
// CHECK-LABEL: casting types to protocol & class existentials:
177+
print("casting types to protocol & class existentials:")
178+
print(nongenericAnyIsPAndPCSub(type: PS.self)) // CHECK: false
179+
print(genericAnyIs(type: PS.self, to: (P & PCSub).self)) // CHECK: false
180+
print(nongenericAnyIsPAndPCSub(type: PE.self)) // CHECK: false
181+
print(genericAnyIs(type: PE.self, to: (P & PCSub).self)) // CHECK: false
182+
//print(nongenericAnyIsPAndPCSub(type: PC.self)) // CHECK-SR-11565: false -- FIXME: reenable this when SR-11565 is fixed
183+
print(genericAnyIs(type: PC.self, to: (P & PCSub).self)) // CHECK: false
184+
print(nongenericAnyIsPAndPCSub(type: PCSub.self)) // CHECK: true
185+
print(genericAnyIs(type: PCSub.self, to: (P & PCSub).self)) // CHECK-ONONE: true
186+
187+
134188
// CHECK-LABEL: type comparisons:
135189
print("type comparisons:\n")
136190
print(allMetasToAllMetas(Int.self, Int.self)) // CHECK: true
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %target-run-simple-swift | %FileCheck --check-prefix CHECK --check-prefix CHECK-ONONE --dump-input fail %s
2+
// RUN: %target-build-swift -O %s -o %t/a.out.optimized
3+
// RUN: %target-codesign %t/a.out.optimized
4+
// RUN: %target-run %t/a.out.optimized | %FileCheck %s
5+
// REQUIRES: executable_test
6+
// REQUIRES: objc_interop
7+
8+
import Foundation
9+
10+
protocol P {}
11+
@objc protocol PObjC {}
12+
struct PS: P {}
13+
enum PE: P {}
14+
class PC: P, PObjC {}
15+
class PCSub: PC {}
16+
17+
func nongenericAnyIsPObjC(type: Any.Type) -> Bool {
18+
return type is PObjC.Type
19+
}
20+
func genericAnyIs<T>(type: Any.Type, to: T.Type) -> Bool {
21+
return type is T.Type
22+
}
23+
24+
// CHECK-LABEL: casting types to ObjC protocols with generics:
25+
print("casting types to ObjC protocols with generics:")
26+
print(nongenericAnyIsPObjC(type: PS.self)) // CHECK: false
27+
print(genericAnyIs(type: PS.self, to: PObjC.self)) // CHECK: false
28+
print(nongenericAnyIsPObjC(type: PE.self)) // CHECK: false
29+
print(genericAnyIs(type: PE.self, to: PObjC.self)) // CHECK: false
30+
print(nongenericAnyIsPObjC(type: PC.self)) // CHECK: true
31+
print(genericAnyIs(type: PC.self, to: PObjC.self)) // CHECK-ONONE: true
32+
print(nongenericAnyIsPObjC(type: PCSub.self)) // CHECK: true
33+
print(genericAnyIs(type: PCSub.self, to: PObjC.self)) // CHECK-ONONE: true

0 commit comments

Comments
 (0)