Skip to content

Commit 4a7b710

Browse files
authored
Merge pull request #58673 from jckarter/closure-literal-function-conversion-throws-5.7
[5.7] SILGen: Emit a closure literal in a function conversion as the converted type.
2 parents 9edb00e + 0fab361 commit 4a7b710

13 files changed

+309
-79
lines changed

lib/IRGen/LoadableByAddress.cpp

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1894,8 +1894,8 @@ static void allocateAndSetAll(StructLoweringState &pass,
18941894
}
18951895
}
18961896

1897-
static void castTupleInstr(SingleValueInstruction *instr, IRGenModule &Mod,
1898-
LargeSILTypeMapper &Mapper) {
1897+
static void retypeTupleInstr(SingleValueInstruction *instr, IRGenModule &Mod,
1898+
LargeSILTypeMapper &Mapper) {
18991899
SILType currSILType = instr->getType();
19001900
auto funcType = getInnerFunctionType(currSILType);
19011901
assert(funcType && "Expected a function Type");
@@ -1910,25 +1910,31 @@ static void castTupleInstr(SingleValueInstruction *instr, IRGenModule &Mod,
19101910

19111911
auto II = instr->getIterator();
19121912
++II;
1913-
SILBuilderWithScope castBuilder(II);
1914-
SingleValueInstruction *castInstr = nullptr;
1913+
SILBuilderWithScope Builder(II);
1914+
SingleValueInstruction *newInstr = nullptr;
19151915
switch (instr->getKind()) {
19161916
// Add cast to the new sil function type:
19171917
case SILInstructionKind::TupleExtractInst: {
1918-
castInstr = castBuilder.createUncheckedReinterpretCast(
1919-
instr->getLoc(), instr, newSILType.getObjectType());
1918+
auto extractInst = cast<TupleExtractInst>(instr);
1919+
newInstr = Builder.createTupleExtract(
1920+
extractInst->getLoc(), extractInst->getOperand(),
1921+
extractInst->getFieldIndex(),
1922+
newSILType.getObjectType());
19201923
break;
19211924
}
19221925
case SILInstructionKind::TupleElementAddrInst: {
1923-
castInstr = castBuilder.createUncheckedAddrCast(
1924-
instr->getLoc(), instr, newSILType.getAddressType());
1926+
auto elementAddrInst = cast<TupleElementAddrInst>(instr);
1927+
newInstr = Builder.createTupleElementAddr(
1928+
elementAddrInst->getLoc(), elementAddrInst->getOperand(),
1929+
elementAddrInst->getFieldIndex(),
1930+
newSILType.getAddressType());
19251931
break;
19261932
}
19271933
default:
19281934
llvm_unreachable("Unexpected instruction inside tupleInstsToMod");
19291935
}
1930-
instr->replaceAllUsesWith(castInstr);
1931-
castInstr->setOperand(0, instr);
1936+
instr->replaceAllUsesWith(newInstr);
1937+
instr->eraseFromParent();
19321938
}
19331939

19341940
static SILValue createCopyOfEnum(StructLoweringState &pass,
@@ -2090,7 +2096,7 @@ static void rewriteFunction(StructLoweringState &pass,
20902096
}
20912097

20922098
for (SingleValueInstruction *instr : pass.tupleInstsToMod) {
2093-
castTupleInstr(instr, pass.Mod, pass.Mapper);
2099+
retypeTupleInstr(instr, pass.Mod, pass.Mapper);
20942100
}
20952101

20962102
while (!pass.allocStackInstsToMod.empty()) {

lib/SIL/IR/SILBuilder.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,18 @@ SILBuilder::createUncheckedReinterpretCast(SILLocation Loc, SILValue Op,
154154
if (SILType::canRefCast(Op->getType(), Ty, getModule()))
155155
return createUncheckedRefCast(Loc, Op, Ty);
156156

157+
// If the source and destination types are functions with the same
158+
// kind of representation, then do a function conversion.
159+
if (Op->getType().isObject() && Ty.isObject()) {
160+
if (auto OpFnTy = Op->getType().getAs<SILFunctionType>()) {
161+
if (auto DestFnTy = Ty.getAs<SILFunctionType>()) {
162+
if (OpFnTy->getRepresentation() == DestFnTy->getRepresentation()) {
163+
return createConvertFunction(Loc, Op, Ty, /*withoutActuallyEscaping*/ false);
164+
}
165+
}
166+
}
167+
}
168+
157169
// The destination type is nontrivial, and may be smaller than the source
158170
// type, so RC identity cannot be assumed.
159171
return insert(UncheckedBitwiseCastInst::create(
@@ -175,6 +187,18 @@ SILBuilder::createUncheckedBitCast(SILLocation Loc, SILValue Op, SILType Ty) {
175187
if (SILType::canRefCast(Op->getType(), Ty, getModule()))
176188
return createUncheckedRefCast(Loc, Op, Ty);
177189

190+
// If the source and destination types are functions with the same
191+
// kind of representation, then do a function conversion.
192+
if (Op->getType().isObject() && Ty.isObject()) {
193+
if (auto OpFnTy = Op->getType().getAs<SILFunctionType>()) {
194+
if (auto DestFnTy = Ty.getAs<SILFunctionType>()) {
195+
if (OpFnTy->getRepresentation() == DestFnTy->getRepresentation()) {
196+
return createConvertFunction(Loc, Op, Ty, /*withoutActuallyEscaping*/ false);
197+
}
198+
}
199+
}
200+
}
201+
178202
// The destination type is nontrivial, and may be smaller than the source
179203
// type, so RC identity cannot be assumed.
180204
return createUncheckedValueCast(Loc, Op, Ty);

lib/SILGen/SILGenExpr.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1714,6 +1714,26 @@ static ManagedValue convertFunctionRepresentation(SILGenFunction &SGF,
17141714
llvm_unreachable("bad representation");
17151715
}
17161716

1717+
// Ideally our prolog/epilog emission would be able to handle all possible
1718+
// reabstractions and conversions. Until then, this returns true if a closure
1719+
// literal of type `literalType` can be directly emitted by SILGen as
1720+
// `convertedType`.
1721+
static bool canPeepholeLiteralClosureConversion(Type literalType,
1722+
Type convertedType) {
1723+
auto literalFnType = literalType->getAs<FunctionType>();
1724+
auto convertedFnType = convertedType->getAs<FunctionType>();
1725+
1726+
if (!literalFnType || !convertedFnType)
1727+
return false;
1728+
1729+
// Does the conversion only add `throws`?
1730+
if (literalFnType->isEqual(convertedFnType->getWithoutThrowing())) {
1731+
return true;
1732+
}
1733+
1734+
return false;
1735+
}
1736+
17171737
RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e,
17181738
SGFContext C)
17191739
{
@@ -1748,6 +1768,38 @@ RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e,
17481768
return RValue(SGF, e, result);
17491769
}
17501770

1771+
// If the function being converted is a closure literal, then the only use
1772+
// of the closure should be as the destination type of the conversion. Rather
1773+
// than emit the closure as is and convert it, see if we can emit the closure
1774+
// directly as the desired type.
1775+
//
1776+
// TODO: Move this up when we can emit closures directly with C calling
1777+
// convention.
1778+
auto subExpr = e->getSubExpr()->getSemanticsProvidingExpr();
1779+
if (isa<AbstractClosureExpr>(subExpr)
1780+
&& canPeepholeLiteralClosureConversion(subExpr->getType(),
1781+
e->getType())) {
1782+
// If we're emitting into a context with a preferred abstraction pattern
1783+
// already, carry that along.
1784+
auto origType = C.getAbstractionPattern();
1785+
// If not, use the conversion type as the desired abstraction pattern.
1786+
if (!origType) {
1787+
origType = AbstractionPattern(e->getType()->getCanonicalType());
1788+
}
1789+
1790+
auto substType = subExpr->getType()->getCanonicalType();
1791+
1792+
auto conversion = Conversion::getSubstToOrig(*origType, substType,
1793+
SGF.getLoweredType(*origType, substType));
1794+
ConvertingInitialization convertingInit(conversion, SGFContext());
1795+
auto closure = SGF.emitRValue(subExpr,
1796+
SGFContext(&convertingInit))
1797+
.getAsSingleValue(SGF, e);
1798+
closure = SGF.emitSubstToOrigValue(e, closure, *origType, substType);
1799+
1800+
return RValue(SGF, e, closure);
1801+
}
1802+
17511803
// Handle a reference to a "thin" native Swift function that only changes
17521804
// representation and refers to an inherently thin function reference.
17531805
if (destRepTy->getRepresentation() == FunctionTypeRepresentation::Thin) {

lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp

Lines changed: 66 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -146,42 +146,20 @@ SILCombiner::optimizeApplyOfConvertFunctionInst(FullApplySite AI,
146146
if (SubstCalleeTy->hasArchetype() || ConvertCalleeTy->hasArchetype())
147147
return nullptr;
148148

149-
// Indirect results are not currently handled.
150-
if (AI.hasIndirectSILResults())
151-
return nullptr;
152-
153-
// Bail if the result type of the converted callee is different from the callee's
154-
// result type of the apply instruction.
155-
if (SubstCalleeTy->getAllResultsSubstType(
156-
AI.getModule(), AI.getFunction()->getTypeExpansionContext()) !=
157-
ConvertCalleeTy->getAllResultsSubstType(
158-
AI.getModule(), AI.getFunction()->getTypeExpansionContext())) {
159-
return nullptr;
160-
}
161-
162149
// Ok, we can now perform our transformation. Grab AI's operands and the
163150
// relevant types from the ConvertFunction function type and AI.
164151
Builder.setCurrentDebugScope(AI.getDebugScope());
165-
OperandValueArrayRef Ops = AI.getArgumentsWithoutIndirectResults();
152+
OperandValueArrayRef Ops = AI.getArguments();
166153
SILFunctionConventions substConventions(SubstCalleeTy, FRI->getModule());
167154
SILFunctionConventions convertConventions(ConvertCalleeTy, FRI->getModule());
168155
auto context = AI.getFunction()->getTypeExpansionContext();
169-
auto oldOpTypes = substConventions.getParameterSILTypes(context);
170-
auto newOpTypes = convertConventions.getParameterSILTypes(context);
171-
172-
assert(Ops.size() == SubstCalleeTy->getNumParameters()
173-
&& "Ops and op types must have same size.");
174-
assert(Ops.size() == ConvertCalleeTy->getNumParameters()
175-
&& "Ops and op types must have same size.");
156+
auto oldOpRetTypes = substConventions.getIndirectSILResultTypes(context);
157+
auto newOpRetTypes = convertConventions.getIndirectSILResultTypes(context);
158+
auto oldOpParamTypes = substConventions.getParameterSILTypes(context);
159+
auto newOpParamTypes = convertConventions.getParameterSILTypes(context);
176160

177161
llvm::SmallVector<SILValue, 8> Args;
178-
auto newOpI = newOpTypes.begin();
179-
auto oldOpI = oldOpTypes.begin();
180-
for (unsigned i = 0, e = Ops.size(); i != e; ++i, ++newOpI, ++oldOpI) {
181-
SILValue Op = Ops[i];
182-
SILType OldOpType = *oldOpI;
183-
SILType NewOpType = *newOpI;
184-
162+
auto convertOp = [&](SILValue Op, SILType OldOpType, SILType NewOpType) {
185163
// Convert function takes refs to refs, address to addresses, and leaves
186164
// other types alone.
187165
if (OldOpType.isAddress()) {
@@ -190,17 +168,68 @@ SILCombiner::optimizeApplyOfConvertFunctionInst(FullApplySite AI,
190168
Args.push_back(UAC);
191169
} else if (OldOpType.getASTType() != NewOpType.getASTType()) {
192170
auto URC =
193-
Builder.createUncheckedReinterpretCast(AI.getLoc(), Op, NewOpType);
171+
Builder.createUncheckedBitCast(AI.getLoc(), Op, NewOpType);
194172
Args.push_back(URC);
195173
} else {
196174
Args.push_back(Op);
197175
}
176+
};
177+
178+
unsigned OpI = 0;
179+
180+
auto newRetI = newOpRetTypes.begin();
181+
auto oldRetI = oldOpRetTypes.begin();
182+
183+
for (auto e = newOpRetTypes.end(); newRetI != e;
184+
++OpI, ++newRetI, ++oldRetI) {
185+
convertOp(Ops[OpI], *oldRetI, *newRetI);
186+
}
187+
188+
auto newParamI = newOpParamTypes.begin();
189+
auto oldParamI = oldOpParamTypes.begin();
190+
for (auto e = newOpParamTypes.end(); newParamI != e;
191+
++OpI, ++newParamI, ++oldParamI) {
192+
convertOp(Ops[OpI], *oldParamI, *newParamI);
198193
}
199194

195+
// Convert the direct results if they changed.
196+
auto oldResultTy = SubstCalleeTy
197+
->getDirectFormalResultsType(AI.getModule(),
198+
AI.getFunction()->getTypeExpansionContext());
199+
auto newResultTy = ConvertCalleeTy
200+
->getDirectFormalResultsType(AI.getModule(),
201+
AI.getFunction()->getTypeExpansionContext());
202+
200203
// Create the new apply inst.
201204
if (auto *TAI = dyn_cast<TryApplyInst>(AI)) {
205+
// If the results need to change, create a new landing block to do that
206+
// conversion.
207+
auto normalBB = TAI->getNormalBB();
208+
if (oldResultTy != newResultTy) {
209+
normalBB = AI.getFunction()->createBasicBlockBefore(TAI->getNormalBB());
210+
Builder.setInsertionPoint(normalBB);
211+
SmallVector<SILValue, 4> branchArgs;
212+
213+
auto oldOpResultTypes = substConventions.getDirectSILResultTypes(context);
214+
auto newOpResultTypes = convertConventions.getDirectSILResultTypes(context);
215+
216+
auto oldRetI = oldOpResultTypes.begin();
217+
auto newRetI = newOpResultTypes.begin();
218+
auto origArgs = TAI->getNormalBB()->getArguments();
219+
auto origArgI = origArgs.begin();
220+
for (auto e = newOpResultTypes.end(); newRetI != e;
221+
++oldRetI, ++newRetI, ++origArgI) {
222+
auto arg = normalBB->createPhiArgument(*newRetI, (*origArgI)->getOwnershipKind());
223+
auto converted = Builder.createUncheckedBitCast(AI.getLoc(),
224+
arg, *oldRetI);
225+
branchArgs.push_back(converted);
226+
}
227+
228+
Builder.createBranch(AI.getLoc(), TAI->getNormalBB(), branchArgs);
229+
}
230+
202231
return Builder.createTryApply(AI.getLoc(), FRI, SubstitutionMap(), Args,
203-
TAI->getNormalBB(), TAI->getErrorBB(),
232+
normalBB, TAI->getErrorBB(),
204233
TAI->getApplyOptions());
205234
}
206235

@@ -213,12 +242,13 @@ SILCombiner::optimizeApplyOfConvertFunctionInst(FullApplySite AI,
213242
Options |= ApplyFlags::DoesNotThrow;
214243
ApplyInst *NAI = Builder.createApply(AI.getLoc(), FRI, SubstitutionMap(),
215244
Args, Options);
216-
assert(FullApplySite(NAI).getSubstCalleeType()->getAllResultsSubstType(
217-
AI.getModule(), AI.getFunction()->getTypeExpansionContext()) ==
218-
AI.getSubstCalleeType()->getAllResultsSubstType(
219-
AI.getModule(), AI.getFunction()->getTypeExpansionContext()) &&
220-
"Function types should be the same");
221-
return NAI;
245+
SILInstruction *result = NAI;
246+
247+
if (oldResultTy != newResultTy) {
248+
result = Builder.createUncheckedBitCast(AI.getLoc(), NAI, oldResultTy);
249+
}
250+
251+
return result;
222252
}
223253

224254
/// Try to optimize a keypath application with an apply instruction.

test/AutoDiff/SILOptimizer/activity_analysis.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -552,14 +552,13 @@ func testTryApply(_ x: Float) -> Float {
552552
// CHECK: bb0:
553553
// CHECK: [ACTIVE] %0 = argument of bb0 : $Float
554554
// CHECK: [NONE] // function_ref closure #1 in testTryApply(_:)
555-
// CHECK: [NONE] %3 = convert_function %2 : $@convention(thin) () -> () to $@convention(thin) @noescape () -> ()
556-
// CHECK: [NONE] %4 = thin_to_thick_function %3 : $@convention(thin) @noescape () -> () to $@noescape @callee_guaranteed () -> ()
557-
// CHECK: [NONE] %5 = convert_function %4 : $@noescape @callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> @error Error
555+
// CHECK: [NONE] %3 = convert_function %2 :
556+
// CHECK: [NONE] %4 = thin_to_thick_function %3 :
558557
// CHECK: [NONE] // function_ref rethrowing(_:)
559558
// CHECK: bb1:
560-
// CHECK: [NONE] %8 = argument of bb1 : $()
559+
// CHECK: [NONE] %7 = argument of bb1 : $()
561560
// CHECK: bb2:
562-
// CHECK: [NONE] %10 = argument of bb2 : $Error
561+
// CHECK: [NONE] %9 = argument of bb2 : $Error
563562

564563
//===----------------------------------------------------------------------===//
565564
// Coroutine differentiation (`begin_apply`)

test/DebugInfo/patternvars.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public func mangle(s: [UnicodeScalar]) -> [UnicodeScalar] {
3535
// Do we care to expose these via lldb?
3636

3737
// CHECK: define {{.*}}@"$s11patternvars6mangle1sSayAA13UnicodeScalarVGAF_tFA2EXEfU_"
38-
// CHECK: %[[VAL:[0-9]+]] = call swiftcc i32 @"$s11patternvars13UnicodeScalarV5values6UInt32Vvg"(i32 %0)
38+
// CHECK: %[[VAL:[0-9]+]] = call swiftcc i32 @"$s11patternvars13UnicodeScalarV5values6UInt32Vvg"(
3939
// CHECK: {{[0-9]+}}:
4040
// CHECK-NOT: call void @llvm.dbg.value
4141
// CHECK-NOT: call void asm sideeffect "", "r"

test/IRGen/big_types_corner_cases.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ public func testGetFunc() {
203203
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} hidden swiftcc void @"$s22big_types_corner_cases7TestBigC4testyyF"(%T22big_types_corner_cases7TestBigC* swiftself %0)
204204
// CHECK: [[CALL1:%.*]] = call {{.*}} @__swift_instantiateConcreteTypeFromMangledName({{.*}} @"$sSayy22big_types_corner_cases9BigStructVcSgGMD"
205205
// CHECK: [[CALL2:%.*]] = call i8** @"$sSayy22big_types_corner_cases9BigStructVcSgGSayxGSlsWl
206-
// CHECK: call swiftcc void @"$sSlsE10firstIndex5where0B0QzSgSb7ElementQzKXE_tKF"(%swift.opaque* noalias nocapture sret({{.*}}) %{{[0-9]+}}, i8* bitcast ({{.*}}* @"$s22big_types_corner_cases9BigStruct{{.*}}_TRTA{{(\.ptrauth)?}}" to i8*), %swift.opaque* %{{[0-9]+}}, %swift.type* %{{[0-9]+}}, i8** [[CALL2]]
206+
// CHECK: call swiftcc void @"$sSlsE10firstIndex5where0B0QzSgSb7ElementQzKXE_tKF"(%swift.opaque* noalias nocapture sret({{.*}}) %{{[0-9]+}}, i8* bitcast ({{.*}}* @"$s22big_types_corner_cases7TestBig{{.*}}" to i8*), %swift.opaque* null, %swift.type* %{{[0-9]+}}, i8** [[CALL2]]
207207
class TestBig {
208208
typealias Handler = (BigStruct) -> Void
209209

test/Profiler/coverage_closure_returns_never.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
// CHECK-LABEL: closure #1 (Swift.Never) -> Swift.Never in coverage_closure_returns_never.closure_with_fatal_error(Swift.Array<Swift.Never>) -> ()
44
// CHECK: builtin "int_instrprof_increment"
5-
// CHECK-NEXT: debug_value {{.*}} : $Never
5+
// CHECK-NEXT: [[LOAD:%.*]] = load {{.*}} : $*Never
6+
// CHECK-NEXT: debug_value [[LOAD]] : $Never
67
// CHECK-NEXT: unreachable
78

89
func closure_with_fatal_error(_ arr: [Never]) {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %target-swift-frontend -emit-silgen %s -disable-availability-checking | %FileCheck %s
2+
// REQUIRES: concurrency
3+
4+
@_silgen_name("takeThrowingAsyncClosure")
5+
func takeThrowingAsyncClosure<T>(_: () async throws -> T)
6+
7+
// CHECK-LABEL: sil {{.*}} @{{.*}}34passNonthrowingAsyncClosureLiteral
8+
func passNonthrowingAsyncClosureLiteral() {
9+
// Check that the literal closure was emitted directly with an error return,
10+
// without a reabstraction thunk to convert from nonthrowing.
11+
// CHECK: [[INVOKE_FN:%.*]] = function_ref
12+
// CHECK: [[CONVERT_NOESCAPE:%.*]] = convert_function [[INVOKE_FN]]
13+
// CHECK: [[CLOSURE:%.*]] = thin_to_thick_function [[CONVERT_NOESCAPE]]
14+
// CHECK: [[CALLEE:%.*]] = function_ref @takeThrowingAsyncClosure
15+
// CHECK: apply [[CALLEE]]<Int>([[CLOSURE]])
16+
takeThrowingAsyncClosure { return 42 }
17+
}

test/SILGen/rethrows.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,11 @@ func test2() {
7171
}
7272

7373
// CHECK-LABEL: sil hidden @$s8rethrows5test3yyF : $@convention(thin) () -> () {
74-
// CHECK: [[CLOSURE:%.*]] = function_ref @$s8rethrows5test3yyFSiyXEfU_ : $@convention(thin) () -> Int
75-
// CHECK: [[CVT:%.*]] = convert_function [[CLOSURE]] : $@convention(thin) () -> Int to $@convention(thin) @noescape () -> Int
74+
// CHECK: [[CLOSURE:%.*]] = function_ref @$s8rethrows5test3yyFSiyXEfU_ :
75+
// CHECK: [[CVT:%.*]] = convert_function [[CLOSURE]] :
7676
// CHECK: [[T0:%.*]] = thin_to_thick_function [[CVT]]
77-
// CHECK: [[T1:%.*]] = convert_function [[T0]] : $@noescape @callee_guaranteed () -> Int to $@noescape @callee_guaranteed () -> (Int, @error Error)
78-
// CHECK: [[RETHROWER:%.*]] = function_ref @$s8rethrows9rethroweryS2iyKXEKF : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error)
79-
// CHECK: try_apply [[RETHROWER]]([[T1]]) : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error), normal [[NORMAL:bb1]], error [[ERROR:bb2]]
77+
// CHECK: [[RETHROWER:%.*]] = function_ref @$s8rethrows9rethroweryS2iyKXEKF :
78+
// CHECK: try_apply [[RETHROWER]]([[T0]]) :
8079
// CHECK: [[NORMAL]]({{%.*}} : $Int):
8180
// CHECK-NEXT: [[RESULT:%.*]] = tuple ()
8281
// CHECK-NEXT: return [[RESULT]]

test/SILGen/type_lowering_subst_function_type_conditional_conformance.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ struct S4<Base> where Base : P1, Base.Element: P1 {
6464
// CHECK-LABEL: {{^}}sil {{.*}} @${{.*}}2S4{{.*}}3foo{{.*}}F :
6565
// CHECK: @callee_guaranteed @substituted <τ_0_0, τ_0_1 where τ_0_0 : P1, τ_0_0 == τ_0_1, τ_0_0.Element : P1> (@in_guaranteed S3<τ_0_0>) -> () for <Base, Base>
6666
func foo(index: S3<Base>?) {
67-
_ = index.map({ _ = $0 })
67+
let f: (S3<Base>) -> () = { _ = $0 }
68+
_ = index.map(f)
6869
}
6970
}
7071

0 commit comments

Comments
 (0)