Skip to content

Commit 3ff277d

Browse files
committed
[Runtime] Use _conformsToProtocols instead of manually checking protocol conformance.
This is cleaner and it fixes a bunch of cases the old code didn't handle: @objc protocols, class bounds, and superclass constraints. rdar://problem/56044443
1 parent d56173e commit 3ff277d

File tree

2 files changed

+70
-22
lines changed

2 files changed

+70
-22
lines changed

stdlib/public/runtime/Casting.cpp

+3-4
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
}
@@ -1117,9 +1117,8 @@ swift_dynamicCastMetatypeImpl(const Metadata *sourceType,
11171117

11181118
case MetadataKind::Existential: {
11191119
auto targetTypeAsExistential = static_cast<const ExistentialTypeMetadata *>(targetType);
1120-
for (auto protocol : targetTypeAsExistential->getProtocols())
1121-
if (!swift_conformsToProtocol(sourceType, protocol.getSwiftProtocol()))
1122-
return nullptr;
1120+
if (!_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr))
1121+
return nullptr;
11231122
return origSourceType;
11241123
}
11251124

test/Interpreter/generic_casts.swift

+67-18
Original file line numberDiff line numberDiff line change
@@ -101,24 +101,6 @@ 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-
122104
print(allToInt(22)) // CHECK: 22
123105
print(anyToInt(44)) // CHECK: 44
124106
allToC(C()).print() // CHECK: C!
@@ -149,6 +131,73 @@ anyClassToCOrE(C()).print() // CHECK: C!
149131
anyClassToCOrE(D()).print() // CHECK: D!
150132
anyClassToCOrE(X()).print() // CHECK: E!
151133

134+
protocol P {}
135+
@objc protocol PObjC {}
136+
struct PS: P {}
137+
enum PE: P {}
138+
class PC: P, PObjC {}
139+
class PCSub: PC {}
140+
141+
func nongenericAnyIsP(type: Any.Type) -> Bool {
142+
return type is P.Type
143+
}
144+
func nongenericAnyIsPObjC(type: Any.Type) -> Bool {
145+
return type is PObjC.Type
146+
}
147+
func nongenericAnyIsPAndAnyObject(type: Any.Type) -> Bool {
148+
return type is (P & AnyObject).Type
149+
}
150+
func nongenericAnyIsPAndPCSub(type: Any.Type) -> Bool {
151+
return type is (P & PCSub).Type
152+
}
153+
func genericAnyIs<T>(type: Any.Type, to: T.Type) -> Bool {
154+
return type is T.Type
155+
}
156+
// CHECK-LABEL: casting types to protocols with generics:
157+
print("casting types to protocols with generics:")
158+
print(nongenericAnyIsP(type: PS.self)) // CHECK: true
159+
print(genericAnyIs(type: PS.self, to: P.self)) // CHECK-ONONE: true
160+
print(nongenericAnyIsP(type: PE.self)) // CHECK: true
161+
print(genericAnyIs(type: PE.self, to: P.self)) // CHECK-ONONE: true
162+
print(nongenericAnyIsP(type: PC.self)) // CHECK: true
163+
print(genericAnyIs(type: PC.self, to: P.self)) // CHECK-ONONE: true
164+
print(nongenericAnyIsP(type: PCSub.self)) // CHECK: true
165+
print(genericAnyIs(type: PCSub.self, to: P.self)) // CHECK-ONONE: true
166+
167+
// CHECK-LABEL: casting types to ObjC protocols with generics:
168+
print("casting types to ObjC protocols with generics:")
169+
print(nongenericAnyIsPObjC(type: PS.self)) // CHECK: false
170+
print(genericAnyIs(type: PS.self, to: PObjC.self)) // CHECK: false
171+
print(nongenericAnyIsPObjC(type: PE.self)) // CHECK: false
172+
print(genericAnyIs(type: PE.self, to: PObjC.self)) // CHECK: false
173+
print(nongenericAnyIsPObjC(type: PC.self)) // CHECK: true
174+
print(genericAnyIs(type: PC.self, to: PObjC.self)) // CHECK-ONONE: true
175+
print(nongenericAnyIsPObjC(type: PCSub.self)) // CHECK: true
176+
print(genericAnyIs(type: PCSub.self, to: PObjC.self)) // CHECK-ONONE: true
177+
178+
// CHECK-LABEL: casting types to protocol & AnyObject existentials:
179+
print("casting types to protocol & AnyObject existentials:")
180+
print(nongenericAnyIsPAndAnyObject(type: PS.self)) // CHECK: false
181+
print(genericAnyIs(type: PS.self, to: (P & AnyObject).self)) // CHECK: false
182+
print(nongenericAnyIsPAndAnyObject(type: PE.self)) // CHECK: false
183+
print(genericAnyIs(type: PE.self, to: (P & AnyObject).self)) // CHECK: false
184+
print(nongenericAnyIsPAndAnyObject(type: PC.self)) // CHECK: true
185+
print(genericAnyIs(type: PC.self, to: (P & AnyObject).self)) // CHECK-ONONE: true
186+
print(nongenericAnyIsPAndAnyObject(type: PCSub.self)) // CHECK: true
187+
print(genericAnyIs(type: PCSub.self, to: (P & AnyObject).self)) // CHECK-ONONE: true
188+
189+
// CHECK-LABEL: casting types to protocol & class existentials:
190+
print("casting types to protocol & class existentials:")
191+
print(nongenericAnyIsPAndPCSub(type: PS.self)) // CHECK: false
192+
print(genericAnyIs(type: PS.self, to: (P & PCSub).self)) // CHECK: false
193+
print(nongenericAnyIsPAndPCSub(type: PE.self)) // CHECK: false
194+
print(genericAnyIs(type: PE.self, to: (P & PCSub).self)) // CHECK: false
195+
//print(nongenericAnyIsPAndPCSub(type: PC.self)) // CHECK-SR-11565: false -- FIXME: reenable this when SR-11565 is fixed
196+
print(genericAnyIs(type: PC.self, to: (P & PCSub).self)) // CHECK: false
197+
print(nongenericAnyIsPAndPCSub(type: PCSub.self)) // CHECK: true
198+
print(genericAnyIs(type: PCSub.self, to: (P & PCSub).self)) // CHECK-ONONE: true
199+
200+
152201
// CHECK-LABEL: type comparisons:
153202
print("type comparisons:\n")
154203
print(allMetasToAllMetas(Int.self, Int.self)) // CHECK: true

0 commit comments

Comments
 (0)