Skip to content

Commit 9a4abf4

Browse files
Merge pull request #27622 from aschwaighofer/irgen_fix_protocol_any_object_to_protocol_composition_with_superclass
IRGen: Fix cast of existential type with anyobject to super class constraint existential
2 parents 3bfe8a6 + e4e162d commit 9a4abf4

File tree

3 files changed

+73
-1
lines changed

3 files changed

+73
-1
lines changed

lib/IRGen/GenCast.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,8 +638,12 @@ void irgen::emitScalarExistentialDowncast(IRGenFunction &IGF,
638638
bool checkSuperclassConstraint = false;
639639
if (hasSuperclassConstraint) {
640640
Type srcSuperclassType = srcInstanceType;
641-
if (srcSuperclassType->isExistentialType())
641+
if (srcSuperclassType->isExistentialType()) {
642642
srcSuperclassType = srcSuperclassType->getSuperclass();
643+
// Look for an AnyObject superclass (getSuperclass() returns nil).
644+
if (!srcSuperclassType && srcInstanceType->isClassExistentialType())
645+
checkSuperclassConstraint = true;
646+
}
643647
if (srcSuperclassType) {
644648
checkSuperclassConstraint =
645649
!destInstanceType->getSuperclass()->isExactSuperclassOf(

test/IRGen/casts.sil

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,3 +359,51 @@ entry(%a : $OA):
359359
%b = unconditional_checked_cast %a : $OA to $OB
360360
return %b : $OB
361361
}
362+
363+
protocol P {}
364+
protocol PAnyObject: AnyObject {}
365+
class C {}
366+
sil_vtable C {}
367+
368+
// CHECK-LABEL: define{{.*}} @cast_protocol_composition_with_anyobject
369+
// CHECK: [[C:%.*]] = call swiftcc %swift.metadata_response @"$s5casts1CCMa"
370+
// CHECK: [[C_META:%.*]] = extractvalue %swift.metadata_response [[C]], 0
371+
// CHECK: call { i8*, i8** } @dynamic_cast_existential_1_superclass_conditional({{.*}}, %swift.type* [[C_META]], %swift.protocol* {{.*}}@"$s5casts1PMp"
372+
373+
sil @cast_protocol_composition_with_anyobject : $@convention(thin) (@owned P & AnyObject ) -> @owned Optional<C & P> {
374+
bb0(%0: $P & AnyObject):
375+
checked_cast_br %0 : $P & AnyObject to $C & P, bb1, bb2
376+
377+
bb1(%2 : $C & P):
378+
%3 = enum $Optional<C & P>, #Optional.some!enumelt.1, %2 : $C & P
379+
br bb3(%3 : $Optional<C & P>)
380+
381+
bb2:
382+
strong_release %0 : $P & AnyObject
383+
%6 = enum $Optional<C & P>, #Optional.none!enumelt
384+
br bb3(%6 : $Optional<C & P>)
385+
386+
bb3(%11 : $Optional<C & P>):
387+
return %11 : $Optional<C & P>
388+
}
389+
390+
// CHECK-LABEL: define{{.*}} @cast_protocol_with_anyobject
391+
// CHECK: [[C:%.*]] = call swiftcc %swift.metadata_response @"$s5casts1CCMa"
392+
// CHECK: [[C_META:%.*]] = extractvalue %swift.metadata_response [[C]], 0
393+
// CHECK: call { i8*, i8** } @dynamic_cast_existential_1_superclass_conditional({{.*}}, %swift.type* [[C_META]], %swift.protocol* {{.*}}@"$s5casts10PAnyObjectMp"
394+
sil @cast_protocol_with_anyobject : $@convention(thin) (@owned PAnyObject ) -> @owned Optional<C & PAnyObject> {
395+
bb0(%0: $PAnyObject):
396+
checked_cast_br %0 : $PAnyObject to $C & PAnyObject, bb1, bb2
397+
398+
bb1(%2 : $C & PAnyObject):
399+
%3 = enum $Optional<C & PAnyObject>, #Optional.some!enumelt.1, %2 : $C & PAnyObject
400+
br bb3(%3 : $Optional<C & PAnyObject>)
401+
402+
bb2:
403+
strong_release %0 : $PAnyObject
404+
%6 = enum $Optional<C & PAnyObject>, #Optional.none!enumelt
405+
br bb3(%6 : $Optional<C & PAnyObject>)
406+
407+
bb3(%11 : $Optional<C & PAnyObject>):
408+
return %11 : $Optional<C & PAnyObject>
409+
}

test/Interpreter/casts.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,23 @@ Casts.test("testConditionalBridgedCastFromSwiftToNSObjectDerivedClass") {
122122
}
123123
expectEqual(0, LifetimeTracked.instances)
124124
}
125+
126+
protocol Q {}
127+
class K { }
128+
class D: Q {}
129+
typealias AnyQ = Q & AnyObject
130+
typealias KQ = K & Q
131+
132+
Casts.test("testCastProtocolCompoWithAnyObjectToProtocolCompoTypeSuperclass") {
133+
let shouldBeNil = (D() as AnyQ) as? KQ
134+
expectNil(shouldBeNil)
135+
}
136+
137+
protocol QAny: AnyObject {}
138+
typealias KQAny = K & QAny
139+
class F: QAny {}
140+
141+
Casts.test("testCastProtocolWithAnyObjectToProtocolCompoTypeSuperclass") {
142+
let shouldBeNil = (F() as QAny) as? KQAny
143+
expectNil(shouldBeNil)
144+
}

0 commit comments

Comments
 (0)