Skip to content

Commit a8452b4

Browse files
committed
AST: Fix crash in ProtocolConformance::subst() when specializing with dynamic Self
Looking up the conformance @dynamic_self C<T> : P simply returns the normal conformance C<T> : P. If we later apply a substitution map to the conformance to specialize T, we would call isSpecialized() on the substituted type, which would return false. We would then hit an assertion because the type type @dynamic_self C<Int> is not equal to the (erroneously unsubstituted) conformance type C<T>. Tweak the logic slightly to avoid this.
1 parent c14a4be commit a8452b4

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

lib/AST/ProtocolConformance.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -788,11 +788,16 @@ ProtocolConformance *
788788
ProtocolConformance::subst(Type substType,
789789
TypeSubstitutionFn subs,
790790
LookupConformanceFn conformances) const {
791+
// ModuleDecl::lookupConformance() strips off dynamic Self, so
792+
// we should do the same here.
793+
if (auto selfType = substType->getAs<DynamicSelfType>())
794+
substType = selfType->getSelfType();
795+
791796
if (getType()->isEqual(substType))
792797
return const_cast<ProtocolConformance *>(this);
793798

794799
switch (getKind()) {
795-
case ProtocolConformanceKind::Normal:
800+
case ProtocolConformanceKind::Normal: {
796801
if (substType->isSpecialized()) {
797802
assert(getType()->isSpecialized()
798803
&& "substitution mapped non-specialized to specialized?!");
@@ -831,10 +836,11 @@ ProtocolConformance::subst(Type substType,
831836
const_cast<ProtocolConformance *>(this),
832837
subMap);
833838
}
839+
834840
assert(substType->isEqual(getType())
835841
&& "substitution changed non-specialized type?!");
836842
return const_cast<ProtocolConformance *>(this);
837-
843+
}
838844
case ProtocolConformanceKind::Inherited: {
839845
// Substitute the base.
840846
auto inheritedConformance
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %target-swift-frontend -emit-sil -O -primary-file %s | %FileCheck %s
2+
3+
protocol P {}
4+
5+
extension P {
6+
@_semantics("optimize.sil.never") func method1() {}
7+
8+
@inline(__always) func method2() { method1() }
9+
}
10+
11+
class C<T> : P {
12+
// CHECK-LABEL: sil shared [always_inline] @_T023specialize_dynamic_self1CC11returnsSelfACyxGXDyFSi_Tg5 : $@convention(method) (@guaranteed C<Int>) -> @owned C<Int>
13+
// CHECK: [[RESULT:%.*]] = alloc_stack $C<Int>
14+
// CHECK: [[FN:%.*]] = function_ref @_T023specialize_dynamic_self1PPAAE7method1yyF : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
15+
// CHECK: apply [[FN]]<@dynamic_self C<Int>>([[RESULT]]) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
16+
// CHECK: return %0 : $C<Int>
17+
@inline(__always)
18+
final func returnsSelf() -> Self {
19+
method2()
20+
return self
21+
}
22+
}
23+
24+
// CHECK-LABEL: sil hidden [thunk] [always_inline] @_T023specialize_dynamic_self8usesCIntyAA1CCySiG1c_tF : $@convention(thin) (@owned C<Int>) -> () {
25+
// CHECK: function_ref @_T023specialize_dynamic_self1CC11returnsSelfACyxGXDyFSi_Tg5 : $@convention(method) (@guaranteed C<Int>) -> @owned C<Int>
26+
// CHECK: return
27+
func usesCInt(c: C<Int>) {
28+
_ = c.returnsSelf()
29+
}

0 commit comments

Comments
 (0)