Skip to content

Commit a5fc7ea

Browse files
committed
SIL: Use correct generic signature when computing yield types for witness thunks
Yield types are not represented in the AST FunctionType, so when we compute the lowered type of a witness thunk for a 'modify' or 'read' coroutine, we have to compute the yield type from scratch. We do this by applying the witness substitutions computed by Sema to the storage type, and then canonicalizing the resulting substituted type with respect to the storage's own generic signature. However, the right hand sides of the witness substitutions are written with respect to the conformance context, which might be a subclass of the class that the storage is originally defined in. By not using the generic signature of this subclass, we could miss associated types of generic parameters of the base class which were made concrete in the subclass using a 'where' clause. Instead, let's pass down the generic signature of the witness thunk, ensuring we always compute the correct canonical type. Fixes rdar://problem/77737914.
1 parent d93e5a3 commit a5fc7ea

File tree

2 files changed

+34
-3
lines changed

2 files changed

+34
-3
lines changed

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1988,6 +1988,7 @@ static void destructureYieldsForCoroutine(TypeConverter &TC,
19881988
Optional<SILDeclRef> origConstant,
19891989
Optional<SILDeclRef> constant,
19901990
Optional<SubstitutionMap> reqtSubs,
1991+
Optional<GenericSignature> genericSig,
19911992
SmallVectorImpl<SILYieldInfo> &yields,
19921993
SILCoroutineKind &coroutineKind,
19931994
SubstFunctionTypeCollector &subst) {
@@ -2012,12 +2013,14 @@ static void destructureYieldsForCoroutine(TypeConverter &TC,
20122013

20132014
auto storage = accessor->getStorage();
20142015
auto valueType = storage->getValueInterfaceType();
2016+
20152017
if (reqtSubs) {
20162018
valueType = valueType.subst(*reqtSubs);
20172019
}
20182020

2019-
auto canValueType = valueType->getCanonicalType(
2020-
accessor->getGenericSignature());
2021+
auto canValueType = (genericSig
2022+
? valueType->getCanonicalType(*genericSig)
2023+
: valueType->getCanonicalType());
20212024

20222025
// 'modify' yields an inout of the target type.
20232026
if (accessor->getAccessorKind() == AccessorKind::Modify) {
@@ -2178,7 +2181,8 @@ static CanSILFunctionType getSILFunctionType(
21782181
SILCoroutineKind coroutineKind = SILCoroutineKind::None;
21792182
SmallVector<SILYieldInfo, 8> yields;
21802183
destructureYieldsForCoroutine(TC, expansionContext, origConstant, constant,
2181-
reqtSubs, yields, coroutineKind, subst);
2184+
reqtSubs, genericSig, yields, coroutineKind,
2185+
subst);
21822186

21832187
// Destructure the result tuple type.
21842188
SmallVector<SILResultInfo, 8> results;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
2+
3+
public protocol P {
4+
associatedtype A
5+
}
6+
7+
public class Base<T: P> {
8+
public var foo: T.A?
9+
}
10+
11+
public struct S {}
12+
13+
public protocol Q {
14+
var foo: S? {set get}
15+
}
16+
17+
public class Derived<T: P> : Base<T>, Q where T.A == S {}
18+
19+
// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] [ossa] @$s4main7DerivedCyxGAA1QA2aEP3fooAA1SVSgvgTW : $@convention(witness_method: Q) <τ_0_0 where τ_0_0 : P, τ_0_0.A == S> (@in_guaranteed Derived<τ_0_0>) -> Optional<S> {
20+
// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] [ossa] @$s4main7DerivedCyxGAA1QA2aEP3fooAA1SVSgvsTW : $@convention(witness_method: Q) <τ_0_0 where τ_0_0 : P, τ_0_0.A == S> (Optional<S>, @inout Derived<τ_0_0>) -> () {
21+
// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] [ossa] @$s4main7DerivedCyxGAA1QA2aEP3fooAA1SVSgvMTW : $@yield_once @convention(witness_method: Q) <τ_0_0 where τ_0_0 : P, τ_0_0.A == S> @substituted <τ_0_0> (@inout τ_0_0) -> @yields @inout Optional<S> for <Derived<τ_0_0>> {
22+
23+
// CHECK-LABEL: sil_witness_table [serialized] <T where T : P, T.A == S> Derived<T>: Q module main {
24+
// CHECK-NEXT: method #Q.foo!getter: <Self where Self : Q> (Self) -> () -> S? : @$s4main7DerivedCyxGAA1QA2aEP3fooAA1SVSgvgTW
25+
// CHECK-NEXT: method #Q.foo!setter: <Self where Self : Q> (inout Self) -> (S?) -> () : @$s4main7DerivedCyxGAA1QA2aEP3fooAA1SVSgvsTW
26+
// CHECK-NEXT: method #Q.foo!modify: <Self where Self : Q> (inout Self) -> () -> () : @$s4main7DerivedCyxGAA1QA2aEP3fooAA1SVSgvMTW
27+
// CHECK-NEXT: }

0 commit comments

Comments
 (0)