Skip to content

Commit bca63b4

Browse files
authored
Merge pull request #4886 from aschwaighofer/fix_irgen_partial_apply_of_generic_witness_swift3
IRGen: Shuffle self value for witness method partial applications
2 parents 0ca72a4 + 27d47a9 commit bca63b4

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, O.Result == S.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, τ_1_0.Result == τ_0_0.Result> (@in τ_1_0, @in_guaranteed τ_0_0) -> ()
21+
%2 = partial_apply %1<S, S.Result, O>(%0) : $@convention(witness_method) <τ_0_0 where τ_0_0 : Observable><τ_1_0 where τ_1_0 : Observer, τ_1_0.Result == τ_0_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)