Skip to content

Commit 4bfc784

Browse files
committed
SILGen: Add support for direct calls to local generic functions with captures
Fixes <rdar://problem/22051279>.
1 parent ac110c0 commit 4bfc784

File tree

2 files changed

+35
-23
lines changed

2 files changed

+35
-23
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,30 +1157,22 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
11571157

11581158
// Otherwise, we have a statically-dispatched call.
11591159
CanFunctionType substFnType = getSubstFnType();
1160-
ArrayRef<Substitution> subs;
1161-
1160+
11621161
auto afd = dyn_cast<AbstractFunctionDecl>(e->getDecl());
11631162
if (afd) {
1164-
auto constantInfo = SGF.getConstantInfo(constant);
1165-
1166-
// Forward local substitutions to a non-generic local function.
1167-
if (afd->getParent()->isLocalContext() && !afd->getGenericParams())
1168-
subs = constantInfo.getForwardingSubstitutions(SGF.getASTContext());
1169-
11701163
// If there are captures, put the placeholder curry level in the formal
11711164
// type.
11721165
// TODO: Eliminate the need for this.
11731166
if (afd->getCaptureInfo().hasLocalCaptures())
11741167
substFnType = CanFunctionType::get(
11751168
SGF.getASTContext().TheEmptyTupleType, substFnType);
11761169
}
1177-
1170+
1171+
ArrayRef<Substitution> subs;
11781172
if (e->getDeclRef().isSpecialized()) {
1179-
assert(subs.empty() && "nested local generics not yet supported");
11801173
subs = e->getDeclRef().getSubstitutions();
11811174
}
1182-
1183-
1175+
11841176
// Enum case constructor references are open-coded.
11851177
if (isa<EnumElementDecl>(e->getDecl()))
11861178
setCallee(Callee::forEnumElement(SGF, constant, substFnType, e));
@@ -1189,21 +1181,20 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
11891181

11901182
// If the decl ref requires captures, emit the capture params.
11911183
if (afd) {
1184+
// FIXME: We should be checking hasLocalCaptures() on the lowered
1185+
// captures in the constant info too, to generate more efficient
1186+
// code for mutually recursive local functions which otherwise
1187+
// capture no state.
11921188
if (afd->getCaptureInfo().hasLocalCaptures()) {
1193-
assert(!e->getDeclRef().isSpecialized()
1194-
&& "generic local fns not implemented");
1195-
11961189
SmallVector<ManagedValue, 4> captures;
11971190
SGF.emitCaptures(e, afd, CaptureEmission::ImmediateApplication,
11981191
captures);
11991192
ApplyCallee->setCaptures(std::move(captures));
12001193
}
1201-
1202-
// FIXME: We should be checking hasLocalCaptures() on the lowered
1203-
// captures in the constant info too, to generate more efficient
1204-
// code for mutually recursive local functions which otherwise
1205-
// capture no state.
1206-
1194+
1195+
if (subs.empty() && afd->getCaptureInfo().hasGenericParamCaptures()) {
1196+
subs = SGF.getForwardingSubstitutions();
1197+
}
12071198
}
12081199

12091200
// If there are substitutions, add them, always at depth 0.
@@ -1227,14 +1218,15 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
12271218
SILDeclRef constant(e);
12281219

12291220
ArrayRef<Substitution> subs;
1221+
if (e->getCaptureInfo().hasGenericParamCaptures())
1222+
subs = SGF.getForwardingSubstitutions();
1223+
12301224
CanFunctionType substFnType = getSubstFnType();
12311225

12321226
// FIXME: We should be checking hasLocalCaptures() on the lowered
12331227
// captures in the constant info above, to generate more efficient
12341228
// code for mutually recursive local functions which otherwise
12351229
// capture no state.
1236-
auto constantInfo = SGF.getConstantInfo(constant);
1237-
subs = constantInfo.getForwardingSubstitutions(SGF.getASTContext());
12381230

12391231
// If there are captures, put the placeholder curry level in the formal
12401232
// type.

test/SILGen/generic_closures.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,19 +217,31 @@ func outer_generic<T>(t: T, i: Int) {
217217
// CHECK: [[THUNK_CLOSURE:%.*]] = partial_apply [[THUNK]]<T>([[CLOSURE]])
218218
// CHECK: strong_release [[THUNK_CLOSURE]]
219219

220+
// CHECK: [[FN:%.*]] = function_ref @_TFF16generic_closures13outer_genericurFT1tx1iSi_T_L_23inner_generic_nocaptureu__rFT1uqd___qd__ : $@convention(thin) <τ_0_0><τ_1_0> (@in τ_1_0) -> @out τ_1_0
221+
// CHECK: [[RESULT:%.*]] = apply [[FN]]<T, T>({{.*}}) : $@convention(thin) <τ_0_0><τ_1_0> (@in τ_1_0) -> @out τ_1_0
222+
_ = inner_generic_nocapture(u: t)
223+
220224
// CHECK: [[FN:%.*]] = function_ref @_TFF16generic_closures13outer_genericurFT1tx1iSi_T_L_14inner_generic1u__rfT1uqd___Si : $@convention(thin) <τ_0_0><τ_1_0> (@in τ_1_0, Int) -> Int
221225
// CHECK: [[CLOSURE:%.*]] = partial_apply [[FN]]<T, ()>(%1) : $@convention(thin) <τ_0_0><τ_1_0> (@in τ_1_0, Int) -> Int
222226
// CHECK: [[THUNK:%.*]] = function_ref @_TTRGrXFo_iT__dSi_XFo__dSi_
223227
// CHECK: [[THUNK_CLOSURE:%.*]] = partial_apply [[THUNK]]<T>([[CLOSURE]])
224228
// CHECK: strong_release [[THUNK_CLOSURE]]
225229
let _: () -> Int = inner_generic1
226230

231+
// CHECK: [[FN:%.*]] = function_ref @_TFF16generic_closures13outer_genericurFT1tx1iSi_T_L_14inner_generic1u__rfT1uqd___Si : $@convention(thin) <τ_0_0><τ_1_0> (@in τ_1_0, Int) -> Int
232+
// CHECK: [[RESULT:%.*]] = apply [[FN]]<T, T>({{.*}}) : $@convention(thin) <τ_0_0><τ_1_0> (@in τ_1_0, Int) -> Int
233+
_ = inner_generic1(u: t)
234+
227235
// CHECK: [[FN:%.*]] = function_ref @_TFF16generic_closures13outer_genericurFT1tx1iSi_T_L_14inner_generic2u__rfT1uqd___x : $@convention(thin) <τ_0_0><τ_1_0> (@in τ_1_0, @owned @box τ_0_0) -> @out τ_0_0
228236
// CHECK: [[CLOSURE:%.*]] = partial_apply [[FN]]<T, ()>([[ARG:%.*]]) : $@convention(thin) <τ_0_0><τ_1_0> (@in τ_1_0, @owned @box τ_0_0) -> @out τ_0_0
229237
// CHECK: [[THUNK:%.*]] = function_ref @_TTRGrXFo_iT__ix_XFo__ix_
230238
// CHECK: [[THUNK_CLOSURE:%.*]] = partial_apply [[THUNK]]<T>([[CLOSURE]])
231239
// CHECK: strong_release [[THUNK_CLOSURE]]
232240
let _: () -> T = inner_generic2
241+
242+
// CHECK: [[FN:%.*]] = function_ref @_TFF16generic_closures13outer_genericurFT1tx1iSi_T_L_14inner_generic2u__rfT1uqd___x : $@convention(thin) <τ_0_0><τ_1_0> (@in τ_1_0, @owned @box τ_0_0) -> @out τ_0_0
243+
// CHECK: [[RESULT:%.*]] = apply [[FN]]<T, T>({{.*}}) : $@convention(thin) <τ_0_0><τ_1_0> (@in τ_1_0, @owned @box τ_0_0) -> @out τ_0_0
244+
_ = inner_generic2(u: t)
233245
}
234246

235247
// CHECK-LABEL: sil hidden @_TF16generic_closures14outer_concreteFT1iSi_T_ : $@convention(thin) (Int) -> ()
@@ -249,10 +261,18 @@ func outer_concrete(i: Int) {
249261
// CHECK: strong_release [[THUNK_CLOSURE]]
250262
let _: () -> () = inner_generic_nocapture
251263

264+
// CHECK: [[FN:%.*]] = function_ref @_TFF16generic_closures14outer_concreteFT1iSi_T_L_23inner_generic_nocaptureurFT1ux_x : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0
265+
// CHECK: [[RESULT:%.*]] = apply [[FN]]<Int>({{.*}}) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0
266+
_ = inner_generic_nocapture(u: i)
267+
252268
// CHECK: [[FN:%.*]] = function_ref @_TFF16generic_closures14outer_concreteFT1iSi_T_L_13inner_genericurfT1ux_Si : $@convention(thin) <τ_0_0> (@in τ_0_0, Int) -> Int
253269
// CHECK: [[CLOSURE:%.*]] = partial_apply [[FN]]<()>(%0) : $@convention(thin) <τ_0_0> (@in τ_0_0, Int) -> Int
254270
// CHECK: [[THUNK:%.*]] = function_ref @_TTRXFo_iT__dSi_XFo__dSi_
255271
// CHECK: [[THUNK_CLOSURE:%.*]] = partial_apply [[THUNK]]([[CLOSURE]])
256272
// CHECK: strong_release [[THUNK_CLOSURE]]
257273
let _: () -> Int = inner_generic
274+
275+
// CHECK: [[FN:%.*]] = function_ref @_TFF16generic_closures14outer_concreteFT1iSi_T_L_13inner_genericurfT1ux_Si : $@convention(thin) <τ_0_0> (@in τ_0_0, Int) -> Int
276+
// CHECK: [[RESULT:%.*]] = apply [[FN]]<Int>({{.*}}) : $@convention(thin) <τ_0_0> (@in τ_0_0, Int) -> Int
277+
_ = inner_generic(u: i)
258278
}

0 commit comments

Comments
 (0)