Skip to content

Commit 993dfca

Browse files
committed
SR-12161 Casting P.self to P.Type regressed in iOS13.4 beta
An earlier fix for certain protocol casts inadvertently disabled the check for a protocol being cast to its own metatype. This rearranges the code so that identical types always succeed. It also updates swift_dynamicCastMetatypeUnconditional to include recent changes to swift_dynamicCastMetatype. Note: These fixes only apply to debug/non-optimized builds. Cast optimizations still break a lot of these cases.
1 parent fd192f4 commit 993dfca

File tree

2 files changed

+115
-21
lines changed

2 files changed

+115
-21
lines changed

stdlib/public/runtime/Casting.cpp

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,10 @@ swift_dynamicCastMetatypeImpl(const Metadata *sourceType,
10461046
const Metadata *targetType) {
10471047
auto origSourceType = sourceType;
10481048

1049+
// Identical types always succeed
1050+
if (sourceType == targetType)
1051+
return origSourceType;
1052+
10491053
switch (targetType->getKind()) {
10501054
case MetadataKind::ObjCClassWrapper:
10511055
// Get the actual class object.
@@ -1111,17 +1115,13 @@ swift_dynamicCastMetatypeImpl(const Metadata *sourceType,
11111115

11121116
case MetadataKind::Existential: {
11131117
auto targetTypeAsExistential = static_cast<const ExistentialTypeMetadata *>(targetType);
1114-
if (!_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr))
1115-
return nullptr;
1116-
return origSourceType;
1118+
if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr))
1119+
return origSourceType;
1120+
return nullptr;
11171121
}
11181122

11191123
default:
1120-
// The cast succeeds only if the metadata pointers are statically
1121-
// equivalent.
1122-
if (sourceType != targetType)
1123-
return nullptr;
1124-
return origSourceType;
1124+
return nullptr;
11251125
}
11261126

11271127
swift_runtime_unreachable("Unhandled MetadataKind in switch.");
@@ -1133,6 +1133,10 @@ swift_dynamicCastMetatypeUnconditionalImpl(const Metadata *sourceType,
11331133
const char *file, unsigned line, unsigned column) {
11341134
auto origSourceType = sourceType;
11351135

1136+
// Identical types always succeed
1137+
if (sourceType == targetType)
1138+
return origSourceType;
1139+
11361140
switch (targetType->getKind()) {
11371141
case MetadataKind::ObjCClassWrapper:
11381142
// Get the actual class object.
@@ -1199,12 +1203,16 @@ swift_dynamicCastMetatypeUnconditionalImpl(const Metadata *sourceType,
11991203
swift_dynamicCastFailure(sourceType, targetType);
12001204
}
12011205
break;
1206+
1207+
case MetadataKind::Existential: {
1208+
auto targetTypeAsExistential = static_cast<const ExistentialTypeMetadata *>(targetType);
1209+
if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr))
1210+
return origSourceType;
1211+
swift_dynamicCastFailure(sourceType, targetType);
1212+
}
1213+
12021214
default:
1203-
// The cast succeeds only if the metadata pointers are statically
1204-
// equivalent.
1205-
if (sourceType != targetType)
1206-
swift_dynamicCastFailure(sourceType, targetType);
1207-
return origSourceType;
1215+
swift_dynamicCastFailure(sourceType, targetType);
12081216
}
12091217
}
12101218

test/Interpreter/generic_casts.swift

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,12 @@ enum PE: P {}
139139
class PC: P {}
140140
class PCSub: PC {}
141141

142+
// `is` checks
142143
func nongenericAnyIsP(type: Any.Type) -> Bool {
143-
return type is P.Type
144+
return type is P.Protocol
144145
}
145146
func nongenericAnyIsPAndAnyObject(type: Any.Type) -> Bool {
146-
return type is (P & AnyObject).Type
147+
return type is (P & AnyObject).Protocol
147148
}
148149
func nongenericAnyIsPAndPCSub(type: Any.Type) -> Bool {
149150
return type is (P & PCSub).Type
@@ -157,27 +158,104 @@ func genericAnyIs<T>(type: Any.Type, to: T.Type, expected: Bool) -> Bool {
157158
return expected
158159
}
159160
}
161+
// `as?` checks
162+
func nongenericAnyAsConditionalP(type: Any.Type) -> Bool {
163+
return (type as? P.Protocol) != nil
164+
}
165+
func nongenericAnyAsConditionalPAndAnyObject(type: Any.Type) -> Bool {
166+
return (type as? (P & AnyObject).Protocol) != nil
167+
}
168+
func nongenericAnyAsConditionalPAndPCSub(type: Any.Type) -> Bool {
169+
return (type as? (P & PCSub).Type) != nil
170+
}
171+
func genericAnyAsConditional<T>(type: Any.Type, to: T.Type, expected: Bool) -> Bool {
172+
// If we're testing against a runtime that doesn't have the fix this tests,
173+
// just pretend we got it right.
174+
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
175+
return (type as? T.Type) != nil
176+
} else {
177+
return expected
178+
}
179+
}
180+
// `as!` checks
181+
func blackhole<T>(_ : T) { }
182+
183+
func nongenericAnyAsUnconditionalP(type: Any.Type) -> Bool {
184+
blackhole(type as! P.Protocol)
185+
return true
186+
}
187+
func nongenericAnyAsUnconditionalPAndAnyObject(type: Any.Type) -> Bool {
188+
blackhole(type as! (P & AnyObject).Protocol)
189+
return true
190+
}
191+
func nongenericAnyAsUnconditionalPAndPCSub(type: Any.Type) -> Bool {
192+
blackhole(type as! (P & PCSub).Type)
193+
return true
194+
}
195+
func genericAnyAsUnconditional<T>(type: Any.Type, to: T.Type, expected: Bool) -> Bool {
196+
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
197+
blackhole(type as! T.Type)
198+
}
199+
return true
200+
}
201+
160202
// CHECK-LABEL: casting types to protocols with generics:
161203
print("casting types to protocols with generics:")
162-
print(nongenericAnyIsP(type: PS.self)) // CHECK: true
204+
print(nongenericAnyIsP(type: P.self)) // CHECK: true
205+
print(genericAnyIs(type: P.self, to: P.self, expected: true)) // CHECK: true
206+
print(nongenericAnyIsP(type: PS.self)) // CHECK-ONONE: true
163207
print(genericAnyIs(type: PS.self, to: P.self, expected: true)) // CHECK-ONONE: true
164-
print(nongenericAnyIsP(type: PE.self)) // CHECK: true
208+
print(nongenericAnyIsP(type: PE.self)) // CHECK-ONONE: true
165209
print(genericAnyIs(type: PE.self, to: P.self, expected: true)) // CHECK-ONONE: true
166-
print(nongenericAnyIsP(type: PC.self)) // CHECK: true
210+
print(nongenericAnyIsP(type: PC.self)) // CHECK-ONONE: true
167211
print(genericAnyIs(type: PC.self, to: P.self, expected: true)) // CHECK-ONONE: true
168-
print(nongenericAnyIsP(type: PCSub.self)) // CHECK: true
212+
print(nongenericAnyIsP(type: PCSub.self)) // CHECK-ONONE: true
169213
print(genericAnyIs(type: PCSub.self, to: P.self, expected: true)) // CHECK-ONONE: true
170214

215+
// CHECK-LABEL: conditionally casting types to protocols with generics:
216+
print("conditionally casting types to protocols with generics:")
217+
print(nongenericAnyAsConditionalP(type: P.self)) // CHECK: true
218+
print(genericAnyAsConditional(type: P.self, to: P.self, expected: true)) // CHECK-ONONE: true
219+
print(nongenericAnyAsConditionalP(type: PS.self)) // CHECK: true
220+
print(genericAnyAsConditional(type: PS.self, to: P.self, expected: true)) // CHECK-ONONE: true
221+
print(nongenericAnyAsConditionalP(type: PE.self)) // CHECK-ONONE: true
222+
print(genericAnyAsConditional(type: PE.self, to: P.self, expected: true)) // CHECK-ONONE: true
223+
print(nongenericAnyAsConditionalP(type: PC.self)) // CHECK-ONONE: true
224+
print(genericAnyAsConditional(type: PC.self, to: P.self, expected: true)) // CHECK-ONONE: true
225+
print(nongenericAnyAsConditionalP(type: PCSub.self)) // CHECK-ONONE: true
226+
print(genericAnyAsConditional(type: PCSub.self, to: P.self, expected: true)) // CHECK-ONONE: true
227+
228+
// CHECK-LABEL: unconditionally casting types to protocols with generics:
229+
print("unconditionally casting types to protocols with generics:")
230+
print(nongenericAnyAsUnconditionalP(type: P.self)) // CHECK: true
231+
print(genericAnyAsUnconditional(type: P.self, to: P.self, expected: true)) // CHECK: true
232+
print(nongenericAnyAsUnconditionalP(type: PS.self)) // CHECK: true
233+
print(genericAnyAsUnconditional(type: PS.self, to: P.self, expected: true)) // CHECK: true
234+
print(nongenericAnyAsUnconditionalP(type: PE.self)) // CHECK: true
235+
print(genericAnyAsUnconditional(type: PE.self, to: P.self, expected: true)) // CHECK: true
236+
print(nongenericAnyAsUnconditionalP(type: PC.self)) // CHECK: true
237+
print(genericAnyAsUnconditional(type: PC.self, to: P.self, expected: true)) // CHECK: true
238+
print(nongenericAnyAsUnconditionalP(type: PCSub.self)) // CHECK: true
239+
print(genericAnyAsUnconditional(type: PCSub.self, to: P.self, expected: true)) // CHECK: true
240+
171241
// CHECK-LABEL: casting types to protocol & AnyObject existentials:
172242
print("casting types to protocol & AnyObject existentials:")
173243
print(nongenericAnyIsPAndAnyObject(type: PS.self)) // CHECK: false
174244
print(genericAnyIs(type: PS.self, to: (P & AnyObject).self, expected: false)) // CHECK: false
175245
print(nongenericAnyIsPAndAnyObject(type: PE.self)) // CHECK: false
176246
print(genericAnyIs(type: PE.self, to: (P & AnyObject).self, expected: false)) // CHECK: false
177-
print(nongenericAnyIsPAndAnyObject(type: PC.self)) // CHECK: true
247+
print(nongenericAnyIsPAndAnyObject(type: PC.self)) // CHECK-ONONE: true
178248
print(genericAnyIs(type: PC.self, to: (P & AnyObject).self, expected: true)) // CHECK-ONONE: true
179-
print(nongenericAnyIsPAndAnyObject(type: PCSub.self)) // CHECK: true
249+
print(nongenericAnyIsPAndAnyObject(type: PCSub.self)) // CHECK-ONONE: true
180250
print(genericAnyIs(type: PCSub.self, to: (P & AnyObject).self, expected: true)) // CHECK-ONONE: true
251+
print(nongenericAnyAsConditionalPAndAnyObject(type: PS.self)) // CHECK: false
252+
print(genericAnyAsConditional(type: PS.self, to: (P & AnyObject).self, expected: false)) // CHECK: false
253+
print(nongenericAnyAsConditionalPAndAnyObject(type: PE.self)) // CHECK: false
254+
print(genericAnyAsConditional(type: PE.self, to: (P & AnyObject).self, expected: false)) // CHECK: false
255+
print(nongenericAnyAsConditionalPAndAnyObject(type: PC.self)) // CHECK-ONONE: true
256+
print(genericAnyAsConditional(type: PC.self, to: (P & AnyObject).self, expected: true)) // CHECK-ONONE: true
257+
print(nongenericAnyAsConditionalPAndAnyObject(type: PCSub.self)) // CHECK-ONONE: true
258+
print(genericAnyAsConditional(type: PCSub.self, to: (P & AnyObject).self, expected: true)) // CHECK-ONONE: true
181259

182260
// CHECK-LABEL: casting types to protocol & class existentials:
183261
print("casting types to protocol & class existentials:")
@@ -189,6 +267,14 @@ print(genericAnyIs(type: PE.self, to: (P & PCSub).self, expected: false)) // CHE
189267
print(genericAnyIs(type: PC.self, to: (P & PCSub).self, expected: false)) // CHECK: false
190268
print(nongenericAnyIsPAndPCSub(type: PCSub.self)) // CHECK: true
191269
print(genericAnyIs(type: PCSub.self, to: (P & PCSub).self, expected: true)) // CHECK-ONONE: true
270+
print(nongenericAnyAsConditionalPAndPCSub(type: PS.self)) // CHECK: false
271+
print(genericAnyAsConditional(type: PS.self, to: (P & PCSub).self, expected: false)) // CHECK: false
272+
print(nongenericAnyAsConditionalPAndPCSub(type: PE.self)) // CHECK: false
273+
print(genericAnyAsConditional(type: PE.self, to: (P & PCSub).self, expected: false)) // CHECK: false
274+
//print(nongenericAnyAsConditionalPAndPCSub(type: PC.self)) // CHECK-SR-11565: false -- FIXME: reenable this when SR-11565 is fixed
275+
print(genericAnyAsConditional(type: PC.self, to: (P & PCSub).self, expected: false)) // CHECK: false
276+
print(nongenericAnyAsConditionalPAndPCSub(type: PCSub.self)) // CHECK: true
277+
print(genericAnyAsConditional(type: PCSub.self, to: (P & PCSub).self, expected: true)) // CHECK-ONONE: true
192278

193279

194280
// CHECK-LABEL: type comparisons:

0 commit comments

Comments
 (0)