Skip to content

Commit 80ea152

Browse files
committed
IRGen: Shuffle self value for witness method partial applications
We need to splice self inbetween the polymorphic arguments and the error argument but before the self metadata and witness table arguments. rdar://28302820
1 parent 608621f commit 80ea152

File tree

2 files changed

+35
-7
lines changed

2 files changed

+35
-7
lines changed

lib/IRGen/GenFunc.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,13 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM,
841841
(origType->hasSelfParam() &&
842842
isSelfContextParameter(origType->getSelfParameter()));
843843

844+
// Witness method calls expect self, followed by the self type followed by,
845+
// the witness table at the end of the parameter list. But polymorphic
846+
// arguments come before this.
847+
bool isWitnessMethodCallee = origType->getRepresentation() ==
848+
SILFunctionTypeRepresentation::WitnessMethod;
849+
Explosion witnessMethodSelfValue;
850+
844851
// If there's a data pointer required, but it's a swift-retainable
845852
// value being passed as the context, just forward it down.
846853
if (!layout) {
@@ -993,9 +1000,11 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM,
9931000
emitApplyArgument(subIGF, origParamInfo,
9941001
substType->getParameters()[origParamI],
9951002
param, origParam);
996-
997-
needsAllocas |=
998-
addNativeArgument(subIGF, origParam, origParamInfo, args);
1003+
bool isWitnessMethodCalleeSelf = (isWitnessMethodCallee &&
1004+
origParamI + 1 == origType->getParameters().size());
1005+
needsAllocas |= addNativeArgument(
1006+
subIGF, origParam, origParamInfo,
1007+
isWitnessMethodCalleeSelf ? witnessMethodSelfValue : args);
9991008
++origParamI;
10001009
} else {
10011010
args.add(param.claimAll());
@@ -1043,8 +1052,7 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM,
10431052
// witness table. Metadata for Self is derived inside the partial
10441053
// application thunk and doesn't need to be stored in the outer
10451054
// context.
1046-
if (origType->getRepresentation() ==
1047-
SILFunctionTypeRepresentation::WitnessMethod) {
1055+
if (isWitnessMethodCallee) {
10481056
assert(fnContext->getType() == IGM.Int8PtrTy);
10491057
llvm::Value *wtable = subIGF.Builder.CreateBitCast(
10501058
fnContext, IGM.WitnessTablePtrTy);
@@ -1061,6 +1069,11 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM,
10611069
args.add(llvm::UndefValue::get(IGM.RefCountedPtrTy));
10621070
}
10631071

1072+
// Add the witness methods self argument before the error parameter after the
1073+
// polymorphic arguments.
1074+
if (isWitnessMethodCallee)
1075+
witnessMethodSelfValue.transferInto(args, witnessMethodSelfValue.size());
1076+
10641077
// Pass down the error result.
10651078
if (origType->hasErrorResult()) {
10661079
llvm::Value *errorResultPtr = origParams.claimNext();
@@ -1070,8 +1083,7 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM,
10701083

10711084
assert(origParams.empty());
10721085

1073-
if (origType->getRepresentation() ==
1074-
SILFunctionTypeRepresentation::WitnessMethod) {
1086+
if (isWitnessMethodCallee) {
10751087
assert(witnessMetadata.SelfMetadata->getType() == IGM.TypeMetadataPtrTy);
10761088
args.add(witnessMetadata.SelfMetadata);
10771089
assert(witnessMetadata.SelfWitnessTable->getType() == IGM.WitnessTablePtrTy);

test/IRGen/partial_apply_forwarder.sil

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,22 @@ public class C : P {}
66
public class D<T : P> {}
77
class E {}
88

9+
public protocol Observable {
10+
associatedtype Result
11+
func subscribe<T: Observer>(o: T) -> ()
12+
}
13+
14+
public protocol Observer {
15+
associatedtype Result
16+
}
17+
18+
sil hidden @witness_method : $@convention(thin) <S where S : Observable><O where O : Observer, S.Result == O.Result> (@in S) -> @owned @callee_owned (@in O) -> () {
19+
bb0(%0 : $*S):
20+
%1 = witness_method $S, #Observable.subscribe!1 : $@convention(witness_method) <τ_0_0 where τ_0_0 : Observable><τ_1_0 where τ_1_0 : Observer, τ_0_0.Result == τ_1_0.Result> (@in τ_1_0, @in_guaranteed τ_0_0) -> ()
21+
%2 = partial_apply %1<S, O, S.Result>(%0) : $@convention(witness_method) <τ_0_0 where τ_0_0 : Observable><τ_1_0 where τ_1_0 : Observer, τ_0_0.Result == τ_1_0.Result> (@in τ_1_0, @in_guaranteed τ_0_0) -> ()
22+
return %2 : $@callee_owned (@in O) -> ()
23+
}
24+
925
// CHECK-LABEL: define internal %GC23partial_apply_forwarder1DCS_1C_* @_TPA_unspecialized_uncurried(%swift.refcounted*
1026
// CHECK: [[TYPE:%.*]] = call %swift.type* @_TMaC23partial_apply_forwarder1C()
1127
// CHECK: [[CAST:%.*]] = bitcast %swift.refcounted* %0 to %C23partial_apply_forwarder1E*

0 commit comments

Comments
 (0)