Skip to content

Commit 56695a1

Browse files
authored
Merge pull request #30689 from slavapestov/curry-thunk-peephole
SILOptimizer: Peephole to eliminate closures which just apply a witness_method
2 parents 4a33bd1 + dcd6c6d commit 56695a1

File tree

5 files changed

+353
-3
lines changed

5 files changed

+353
-3
lines changed

lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,104 @@ static bool foldInverseReabstractionThunks(PartialApplyInst *PAI,
7878
return true;
7979
}
8080

81+
ApplyInst *getSingleApplyInBlock(SILBasicBlock &BB) {
82+
ApplyInst *Result = nullptr;
83+
84+
for (auto &I : BB) {
85+
if (isa<DebugValueAddrInst>(I) ||
86+
isa<DebugValueInst>(I))
87+
continue;
88+
89+
// FIXME: Should also support ClassMethodInst
90+
if (isa<WitnessMethodInst>(I) ||
91+
isa<ReturnInst>(I))
92+
continue;
93+
94+
if (auto *TI = dyn_cast<TupleInst>(&I))
95+
if (TI->getElements().empty())
96+
continue;
97+
98+
if (auto *AI = dyn_cast<ApplyInst>(&I)) {
99+
if (Result == nullptr) {
100+
Result = AI;
101+
continue;
102+
}
103+
}
104+
105+
return nullptr;
106+
}
107+
108+
return Result;
109+
}
110+
111+
static bool foldPartialApplyOfTrivialClosure(PartialApplyInst *PAI,
112+
SILCombiner *Combiner) {
113+
auto *FRI = dyn_cast<FunctionRefInst>(PAI->getCallee());
114+
if (FRI == nullptr)
115+
return false;
116+
117+
auto *F = FRI->getReferencedFunctionOrNull();
118+
if (F == nullptr)
119+
return false;
120+
121+
// The referenced function must consist of a single basic block.
122+
if (F->getBlocks().size() != 1)
123+
return false;
124+
125+
// The referenced function must not throw.
126+
if (F->getLoweredFunctionType()->getOptionalErrorResult())
127+
return false;
128+
129+
// The only non-trivial instructions in the function must be an apply
130+
// of a witness_method callee.
131+
auto &BB = *F->getBlocks().begin();
132+
auto *AI = getSingleApplyInBlock(BB);
133+
if (AI == nullptr)
134+
return false;
135+
136+
// The apply instruction must have the same number of arguments as the
137+
// function that contains it, and they must be passed in order.
138+
auto InnerArgs = AI->getArguments();
139+
if (InnerArgs.size() != BB.args_size())
140+
return false;
141+
142+
auto ArgsIter = BB.args_begin();
143+
for (auto Arg : InnerArgs) {
144+
if (Arg != *(ArgsIter++))
145+
return false;
146+
}
147+
148+
SILBuilderWithScope B(PAI);
149+
150+
// FIXME: Should also support ClassMethodInst
151+
auto *WMI = cast<WitnessMethodInst>(AI->getCallee());
152+
auto InnerSubs = PAI->getSubstitutionMap();
153+
auto Subs = AI->getSubstitutionMap().subst(InnerSubs);
154+
auto *NewCallee = B.createWitnessMethod(
155+
WMI->getLoc(),
156+
WMI->getLookupType().subst(InnerSubs)->getCanonicalType(),
157+
WMI->getConformance().subst(WMI->getLookupType(), InnerSubs),
158+
WMI->getMember(),
159+
WMI->getType().subst(F->getModule().Types, InnerSubs));
160+
161+
SmallVector<SILValue, 8> NewArgs;
162+
auto Args = PAI->getArguments();
163+
NewArgs.append(Args.begin(), Args.end());
164+
165+
auto *NewPAI = B.createPartialApply(
166+
PAI->getLoc(),
167+
NewCallee,
168+
Subs,
169+
NewArgs,
170+
PAI->getType().getAs<SILFunctionType>()->getCalleeConvention(),
171+
PAI->isOnStack());
172+
173+
assert(PAI->getType() == NewPAI->getType());
174+
PAI->replaceAllUsesWith(NewPAI);
175+
Combiner->eraseInstFromFunction(*PAI);
176+
return true;
177+
}
178+
81179
SILInstruction *SILCombiner::visitPartialApplyInst(PartialApplyInst *PAI) {
82180
if (PAI->getFunction()->hasOwnership())
83181
return nullptr;
@@ -109,6 +207,11 @@ SILInstruction *SILCombiner::visitPartialApplyInst(PartialApplyInst *PAI) {
109207
if (foldInverseReabstractionThunks(PAI, this))
110208
return nullptr;
111209

210+
// partial_apply %function_ref => partial_apply %witness_method if
211+
// the body of the function_ref is just an apply %witness_method
212+
if (foldPartialApplyOfTrivialClosure(PAI, this))
213+
return nullptr;
214+
112215
bool argsAreKeptAlive = tryOptimizeApplyOfPartialApply(
113216
PAI, Builder.getBuilderContext(), getInstModCallbacks());
114217
if (argsAreKeptAlive)

lib/SILOptimizer/Utils/Devirtualize.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,8 @@ replacePartialApplyInst(SILBuilder &builder, SILLocation loc,
589589
auto convention =
590590
oldPAI->getType().getAs<SILFunctionType>()->getCalleeConvention();
591591
auto *newPAI =
592-
builder.createPartialApply(loc, newFn, newSubs, newArgs, convention);
592+
builder.createPartialApply(loc, newFn, newSubs, newArgs, convention,
593+
oldPAI->isOnStack());
593594

594595
// Check if any casting is required for the partially-applied function.
595596
SILValue resultValue = castValueToABICompatibleType(
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -sil-combine | %FileCheck %s
2+
3+
sil_stage canonical
4+
5+
import Builtin
6+
import Swift
7+
import SwiftShims
8+
9+
public protocol P {
10+
}
11+
12+
public struct S : P {
13+
init()
14+
}
15+
16+
public protocol Curryable {
17+
func concreteRequirement()
18+
func genericRequirement<T>(_: T) where T : P
19+
func concreteRequirementSelf() -> Self
20+
func genericRequirementSelf<T>(_: T) -> Self where T : P
21+
func concreteRequirementInt() -> Int
22+
func genericRequirementInt<T>(_: T) -> Int where T : P
23+
}
24+
25+
public protocol Q {
26+
associatedtype S : Curryable
27+
associatedtype U : P
28+
}
29+
30+
// CHECK-LABEL: sil @$concrete_closure : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> () {
31+
// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.concreteRequirement : <Self where Self : Curryable> (Self) -> () -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> ()
32+
// CHECK: partial_apply [callee_guaranteed] [[FN]]<T.S>(%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> ()
33+
// CHECK: return
34+
sil @$concrete_closure : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> () {
35+
bb0(%0 : $*T.S):
36+
%fn = function_ref @$concrete_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> ()
37+
%closure = partial_apply [callee_guaranteed] %fn<T>(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> ()
38+
return %closure : $@callee_guaranteed () -> ()
39+
}
40+
41+
sil private @$concrete_closure_inner : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> () {
42+
bb0(%0 : $*T.S):
43+
%fn = witness_method $T.S, #Curryable.concreteRequirement : <Self where Self : Curryable> (Self) -> () -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> ()
44+
%result = apply %fn<T.S>(%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> ()
45+
%void = tuple ()
46+
return %void : $()
47+
}
48+
49+
// CHECK-LABEL: sil @$generic_closure : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <T.U> {
50+
// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.genericRequirement : <Self where Self : Curryable><T where T : P> (Self) -> (T) -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> ()
51+
// CHECK: partial_apply [callee_guaranteed] [[FN]]<T.S, T.U>(%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> ()
52+
// CHECK: return
53+
sil @$generic_closure : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <T.U> {
54+
bb0(%0 : $*T.S):
55+
%fn = function_ref @$generic_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> ()
56+
%closure = partial_apply [callee_guaranteed] %fn<T>(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> ()
57+
%converted = convert_function %closure : $@callee_guaranteed (@in_guaranteed T.U) -> () to $@callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <T.U>
58+
return %converted : $@callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <T.U>
59+
}
60+
61+
sil private @$generic_closure_inner : $@convention(thin) <T where T : Q> (@in_guaranteed T.U, @in_guaranteed T.S) -> () {
62+
bb0(%0 : $*T.U, %1 : $*T.S):
63+
%fn = witness_method $T.S, #Curryable.genericRequirement : <Self where Self : Curryable><T where T : P> (Self) -> (T) -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> ()
64+
%result = apply %fn<T.S, T.U>(%0, %1) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> ()
65+
%void = tuple ()
66+
return %void : $()
67+
}
68+
69+
// CHECK-LABEL: sil @$concrete_self_closure : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <T.S> {
70+
// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.concreteRequirementSelf : <Self where Self : Curryable> (Self) -> () -> Self : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> @out τ_0_0
71+
// CHECK: partial_apply [callee_guaranteed] [[FN]]<T.S>(%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> @out τ_0_0
72+
// CHECK: return
73+
sil @$concrete_self_closure : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <T.S> {
74+
bb0(%0 : $*T.S):
75+
%fn = function_ref @$concrete_self_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> @out τ_0_0.S
76+
%closure = partial_apply [callee_guaranteed] %fn<T>(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> @out τ_0_0.S
77+
%converted = convert_function %closure : $@callee_guaranteed () -> @out T.S to $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <T.S>
78+
return %converted : $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <T.S>
79+
}
80+
81+
sil private @$concrete_self_closure_inner : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> @out T.S {
82+
bb0(%0 : $*T.S, %1 : $*T.S):
83+
%fn = witness_method $T.S, #Curryable.concreteRequirementSelf : <Self where Self : Curryable> (Self) -> () -> Self : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> @out τ_0_0
84+
%result = apply %fn<T.S>(%0, %1) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> @out τ_0_0
85+
%void = tuple ()
86+
return %result : $()
87+
}
88+
89+
// CHECK-LABEL: sil @$generic_self_closure : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <T.U, T.S> {
90+
// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.genericRequirementSelf : <Self where Self : Curryable><T where T : P> (Self) -> (T) -> Self : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> @out τ_0_0
91+
// CHECK: partial_apply [callee_guaranteed] [[FN]]<T.S, T.U>(%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> @out τ_0_0
92+
// CHECK: return
93+
sil @$generic_self_closure : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <T.U, T.S> {
94+
bb0(%0 : $*T.S):
95+
%fn = function_ref @$generic_self_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> @out τ_0_0.S
96+
%closure = partial_apply [callee_guaranteed] %fn<T>(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> @out τ_0_0.S
97+
%converted = convert_function %closure : $@callee_guaranteed (@in_guaranteed T.U) -> @out T.S to $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <T.U, T.S>
98+
return %converted : $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <T.U, T.S>
99+
}
100+
101+
sil private @$generic_self_closure_inner : $@convention(thin) <T where T : Q> (@in_guaranteed T.U, @in_guaranteed T.S) -> @out T.S {
102+
bb0(%0 : $*T.S, %1 : $*T.U, %2 : $*T.S):
103+
%fn = witness_method $T.S, #Curryable.genericRequirementSelf : <Self where Self : Curryable><T where T : P> (Self) -> (T) -> Self : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> @out τ_0_0
104+
%result = apply %fn<T.S, T.U>(%0, %1, %2) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> @out τ_0_0
105+
%void = tuple ()
106+
return %void : $()
107+
}
108+
109+
// CHECK-LABEL: sil @$concrete_int_closure : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> Int {
110+
// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.concreteRequirementInt : <Self where Self : Curryable> (Self) -> () -> Int : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> Int
111+
// CHECK: partial_apply [callee_guaranteed] [[FN]]<T.S>(%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> Int
112+
// CHECK: return
113+
sil @$concrete_int_closure : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> Int {
114+
bb0(%0 : $*T.S):
115+
%fn = function_ref @$concrete_int_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> Int
116+
%closure = partial_apply [callee_guaranteed] %fn<T>(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> Int
117+
return %closure : $@callee_guaranteed () -> Int
118+
}
119+
120+
sil private @$concrete_int_closure_inner : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> Int {
121+
bb0(%0 : $*T.S):
122+
%fn = witness_method $T.S, #Curryable.concreteRequirementInt : <Self where Self : Curryable> (Self) -> () -> Int : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> Int
123+
%result = apply %fn<T.S>(%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> Int
124+
return %result : $Int
125+
}
126+
127+
// CHECK-LABEL: sil @$generic_int_closure : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Int for <T.U> {
128+
// CHECK: [[FN:%.*]] = witness_method $T.S, #Curryable.genericRequirementInt : <Self where Self : Curryable><T where T : P> (Self) -> (T) -> Int : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> Int
129+
// CHECK: partial_apply [callee_guaranteed] [[FN]]<T.S, T.U>(%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> Int
130+
// CHECK: return
131+
sil @$generic_int_closure : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> @owned @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Int for <T.U> {
132+
bb0(%0 : $*T.S):
133+
%fn = function_ref @$generic_int_closure_inner : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> Int
134+
%closure = partial_apply [callee_guaranteed] %fn<T>(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.U, @in_guaranteed τ_0_0.S) -> Int
135+
%converted = convert_function %closure : $@callee_guaranteed (@in_guaranteed T.U) -> Int to $@callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Int for <T.U>
136+
return %converted : $@callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Int for <T.U>
137+
}
138+
139+
sil private @$generic_int_closure_inner : $@convention(thin) <T where T : Q> (@in_guaranteed T.U, @in_guaranteed T.S) -> Int {
140+
bb0(%0 : $*T.U, %1 : $*T.S):
141+
%fn = witness_method $T.S, #Curryable.genericRequirementInt : <Self where Self : Curryable><T where T : P> (Self) -> (T) -> Int : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> Int
142+
%result = apply %fn<T.S, T.U>(%0, %1) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable><τ_1_0 where τ_1_0 : P> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> Int
143+
return %result : $Int
144+
}
145+
146+
// CHECK-LABEL: sil @$concrete_closure_throws : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> @error Error {
147+
// CHECK: [[FN:%.*]] = function_ref @$concrete_closure_inner_throws
148+
// CHECK: partial_apply [callee_guaranteed] [[FN]]<T>(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> @error Error
149+
// CHECK: return
150+
sil @$concrete_closure_throws : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> @owned @callee_guaranteed () -> @error Error {
151+
bb0(%0 : $*T.S):
152+
%fn = function_ref @$concrete_closure_inner_throws : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> (@error Error)
153+
%closure = partial_apply [callee_guaranteed] %fn<T>(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : Q> (@in_guaranteed τ_0_0.S) -> (@error Error)
154+
return %closure : $@callee_guaranteed () -> (@error Swift.Error)
155+
}
156+
157+
sil private @$concrete_closure_inner_throws : $@convention(thin) <T where T : Q> (@in_guaranteed T.S) -> @error Swift.Error {
158+
bb0(%0 : $*T.S):
159+
%fn = witness_method $T.S, #Curryable.concreteRequirement : <Self where Self : Curryable> (Self) -> () -> () : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> ()
160+
%result = apply %fn<T.S>(%0) : $@convention(witness_method: Curryable) <τ_0_0 where τ_0_0 : Curryable> (@in_guaranteed τ_0_0) -> ()
161+
%void = tuple ()
162+
return %void : $()
163+
}
164+
165+
sil_witness_table [serialized] S: P module sil_combine_curry_thunk {
166+
}

0 commit comments

Comments
 (0)