Skip to content

Commit ac110c0

Browse files
committed
SILGen: When forming a closure, apply substitutions before applying captures
We now have enough machinery in place to reference local generic functions which have captures, to get a value of function type that can be passed around. Generic local functions still cannot be directly called from function call expressions, since those go down a different path in SILGenApply.cpp -- the next patch will add support for this case.
1 parent 45cadc2 commit ac110c0

File tree

4 files changed

+173
-101
lines changed

4 files changed

+173
-101
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 11 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -445,57 +445,9 @@ emitRValueForDecl(SILLocation loc, ConcreteDeclRef declRef, Type ncRefType,
445445
}
446446

447447
auto silDeclRef = SILDeclRef(decl, ResilienceExpansion::Minimal, uncurryLevel);
448-
auto constantInfo = getConstantInfo(silDeclRef);
449-
450-
ManagedValue result = emitFunctionRef(loc, silDeclRef, constantInfo);
451-
452-
// Get the lowered AST types:
453-
// - the original type
454-
auto origLoweredFormalType =
455-
AbstractionPattern(constantInfo.LoweredInterfaceType);
456-
if (hasLocalCaptures) {
457-
// Get the unlowered formal type of the constant, stripping off
458-
// the first level of function application, which applies captures.
459-
origLoweredFormalType =
460-
AbstractionPattern(constantInfo.FormalInterfaceType)
461-
.getFunctionResultType();
462-
463-
// Lower it, being careful to use the right generic signature.
464-
origLoweredFormalType =
465-
AbstractionPattern(
466-
origLoweredFormalType.getGenericSignature(),
467-
SGM.Types.getLoweredASTFunctionType(
468-
cast<FunctionType>(origLoweredFormalType.getType()),
469-
0, silDeclRef));
470-
}
471-
472-
// - the substituted type
473-
auto substFormalType = cast<AnyFunctionType>(refType);
474-
auto substLoweredFormalType =
475-
SGM.Types.getLoweredASTFunctionType(substFormalType, 0, silDeclRef);
476-
477-
// If the declaration reference is specialized, create the partial
478-
// application.
479-
if (declRef.isSpecialized()) {
480-
// Substitute the function type.
481-
auto origFnType = result.getType().castTo<SILFunctionType>();
482-
auto substFnType = origFnType->substGenericArgs(
483-
SGM.M, SGM.SwiftModule,
484-
declRef.getSubstitutions());
485-
auto closureType = adjustFunctionType(substFnType,
486-
SILFunctionType::Representation::Thick);
487-
488-
SILValue spec = B.createPartialApply(loc, result.forward(*this),
489-
SILType::getPrimitiveObjectType(substFnType),
490-
declRef.getSubstitutions(),
491-
{ },
492-
SILType::getPrimitiveObjectType(closureType));
493-
result = emitManagedRValueWithCleanup(spec);
494-
}
495-
496-
// Generalize if necessary.
497-
result = emitOrigToSubstValue(loc, result, origLoweredFormalType,
498-
substLoweredFormalType);
448+
449+
ManagedValue result = emitClosureValue(loc, silDeclRef, refType,
450+
declRef.getSubstitutions());
499451
return RValue(*this, loc, refType, result);
500452
}
501453

@@ -1965,9 +1917,16 @@ RValue RValueEmitter::visitAbstractClosureExpr(AbstractClosureExpr *e,
19651917
// Emit the closure body.
19661918
SGF.SGM.emitClosure(e);
19671919

1920+
ArrayRef<Substitution> subs;
1921+
if (e->getCaptureInfo().hasGenericParamCaptures())
1922+
subs = SGF.getForwardingSubstitutions();
1923+
19681924
// Generate the closure value (if any) for the closure expr's function
19691925
// reference.
1970-
return RValue(SGF, e, SGF.emitClosureValue(e, SILDeclRef(e), e));
1926+
auto refType = e->getType()->getCanonicalType();
1927+
ManagedValue result = SGF.emitClosureValue(e, SILDeclRef(e),
1928+
refType, subs);
1929+
return RValue(SGF, e, refType, result);
19711930
}
19721931

19731932
RValue RValueEmitter::

lib/SILGen/SILGenFunction.cpp

Lines changed: 57 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -207,27 +207,11 @@ SILGenFunction::emitSiblingMethodRef(SILLocation loc,
207207
methodTy, subs);
208208
}
209209

210-
ManagedValue SILGenFunction::emitFunctionRef(SILLocation loc,
211-
SILDeclRef constant,
212-
SILConstantInfo constantInfo) {
213-
// If the function has captures, apply them.
214-
if (auto fn = constant.getAnyFunctionRef()) {
215-
if (fn->getCaptureInfo().hasLocalCaptures() ||
216-
fn->getCaptureInfo().hasGenericParamCaptures()) {
217-
return emitClosureValue(loc, constant, *fn);
218-
}
219-
}
220-
221-
// Otherwise, use a global FunctionRefInst.
222-
SILValue c = emitGlobalFunctionRef(loc, constant, constantInfo);
223-
return ManagedValue::forUnmanaged(c);
224-
}
225-
226210
void SILGenFunction::emitCaptures(SILLocation loc,
227-
AnyFunctionRef TheClosure,
211+
AnyFunctionRef closure,
228212
CaptureEmission purpose,
229213
SmallVectorImpl<ManagedValue> &capturedArgs) {
230-
auto captureInfo = SGM.Types.getLoweredLocalCaptures(TheClosure);
214+
auto captureInfo = SGM.Types.getLoweredLocalCaptures(closure);
231215
// For boxed captures, we need to mark the contained variables as having
232216
// escaped for DI diagnostics.
233217
SmallVector<SILValue, 2> escapesToMark;
@@ -349,31 +333,38 @@ void SILGenFunction::emitCaptures(SILLocation loc,
349333

350334
ManagedValue
351335
SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant,
352-
AnyFunctionRef TheClosure) {
336+
CanType expectedType,
337+
ArrayRef<Substitution> subs) {
338+
auto closure = *constant.getAnyFunctionRef();
339+
auto captureInfo = closure.getCaptureInfo();
340+
353341
assert(((constant.uncurryLevel == 1 &&
354-
TheClosure.getCaptureInfo().hasLocalCaptures()) ||
342+
captureInfo.hasLocalCaptures()) ||
355343
(constant.uncurryLevel == 0 &&
356-
!TheClosure.getCaptureInfo().hasLocalCaptures())) &&
344+
!captureInfo.hasLocalCaptures())) &&
357345
"curried local functions not yet supported");
358346

359347
auto constantInfo = getConstantInfo(constant);
360348
SILValue functionRef = emitGlobalFunctionRef(loc, constant, constantInfo);
361349
SILType functionTy = functionRef->getType();
362350

363-
auto expectedType =
364-
cast<FunctionType>(TheClosure.getType()->getCanonicalType());
365-
366-
// Forward substitutions from the outer scope.
367-
351+
// Apply substitutions.
368352
auto pft = constantInfo.SILFnType;
369353

370-
auto forwardSubs = constantInfo.getForwardingSubstitutions(getASTContext());
371-
372354
bool wasSpecialized = false;
373-
if (pft->isPolymorphic() && !forwardSubs.empty()) {
355+
if (pft->isPolymorphic()) {
356+
// If the lowered function type is generic but Sema did not hand us any
357+
// substitutions, the function is a local function that appears in a
358+
// generic context but does not have a generic parameter list of its own;
359+
// just use our forwarding substitutions.
360+
if (subs.empty()) {
361+
assert(closure.getAsDeclContext()->isLocalContext() &&
362+
"cannot reference generic global function without substitutions");
363+
subs = getForwardingSubstitutions();
364+
}
374365
auto specialized = pft->substGenericArgs(F.getModule(),
375366
F.getModule().getSwiftModule(),
376-
forwardSubs);
367+
subs);
377368
functionTy = SILType::getPrimitiveObjectType(specialized);
378369
wasSpecialized = true;
379370
}
@@ -382,19 +373,19 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant,
382373
// globals, but we still need to mark them as escaping so that DI can flag
383374
// uninitialized uses.
384375
if (this == SGM.TopLevelSGF) {
385-
SGM.emitMarkFunctionEscapeForTopLevelCodeGlobals(loc,
386-
TheClosure.getCaptureInfo());
376+
SGM.emitMarkFunctionEscapeForTopLevelCodeGlobals(
377+
loc, captureInfo);
387378
}
388379

389-
if (!TheClosure.getCaptureInfo().hasLocalCaptures() && !wasSpecialized) {
380+
if (!captureInfo.hasLocalCaptures() && !wasSpecialized) {
390381
auto result = ManagedValue::forUnmanaged(functionRef);
391382
return emitOrigToSubstValue(loc, result,
392383
AbstractionPattern(expectedType),
393384
expectedType);
394385
}
395386

396387
SmallVector<ManagedValue, 4> capturedArgs;
397-
emitCaptures(loc, TheClosure, CaptureEmission::PartialApplication,
388+
emitCaptures(loc, closure, CaptureEmission::PartialApplication,
398389
capturedArgs);
399390

400391
// The partial application takes ownership of the context parameters.
@@ -405,15 +396,42 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant,
405396
SILType closureTy =
406397
SILGenBuilder::getPartialApplyResultType(functionRef->getType(),
407398
capturedArgs.size(), SGM.M,
408-
forwardSubs);
399+
subs);
409400
auto toClosure =
410401
B.createPartialApply(loc, functionRef, functionTy,
411-
forwardSubs, forwardedArgs, closureTy);
402+
subs, forwardedArgs, closureTy);
412403
auto result = emitManagedRValueWithCleanup(toClosure);
413404

414-
return emitOrigToSubstValue(loc, result,
415-
AbstractionPattern(expectedType),
416-
expectedType);
405+
// Get the lowered AST types:
406+
// - the original type
407+
auto origLoweredFormalType =
408+
AbstractionPattern(constantInfo.LoweredInterfaceType);
409+
if (captureInfo.hasLocalCaptures()) {
410+
// Get the unlowered formal type of the constant, stripping off
411+
// the first level of function application, which applies captures.
412+
origLoweredFormalType =
413+
AbstractionPattern(constantInfo.FormalInterfaceType)
414+
.getFunctionResultType();
415+
416+
// Lower it, being careful to use the right generic signature.
417+
origLoweredFormalType =
418+
AbstractionPattern(
419+
origLoweredFormalType.getGenericSignature(),
420+
SGM.Types.getLoweredASTFunctionType(
421+
cast<FunctionType>(origLoweredFormalType.getType()),
422+
0, constant));
423+
}
424+
425+
// - the substituted type
426+
auto substFormalType = cast<FunctionType>(expectedType);
427+
auto substLoweredFormalType =
428+
SGM.Types.getLoweredASTFunctionType(substFormalType, 0, constant);
429+
430+
// Generalize if necessary.
431+
result = emitOrigToSubstValue(loc, result, origLoweredFormalType,
432+
substLoweredFormalType);
433+
434+
return result;
417435
}
418436

419437
void SILGenFunction::emitFunction(FuncDecl *fd) {

lib/SILGen/SILGenFunction.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,12 +1045,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
10451045
SILValue emitDynamicMethodRef(SILLocation loc, SILDeclRef constant,
10461046
SILConstantInfo constantInfo);
10471047

1048-
/// Returns a reference to a constant in local context. This will return a
1049-
/// retained closure object reference if the constant refers to a local func
1050-
/// decl.
1051-
ManagedValue emitFunctionRef(SILLocation loc, SILDeclRef constant,
1052-
SILConstantInfo constantInfo);
1053-
10541048
/// Emit the specified VarDecl as an LValue if possible, otherwise return
10551049
/// null.
10561050
ManagedValue emitLValueForDecl(SILLocation loc, VarDecl *var,
@@ -1081,9 +1075,13 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
10811075
CaptureEmission purpose,
10821076
SmallVectorImpl<ManagedValue> &captures);
10831077

1078+
/// Produce a reference to a function, which may be a local function
1079+
/// with captures. If the function is generic, substitutions must be
1080+
/// given. The result is re-abstracted to the given expected type.
10841081
ManagedValue emitClosureValue(SILLocation loc,
10851082
SILDeclRef function,
1086-
AnyFunctionRef TheClosure);
1083+
CanType expectedType,
1084+
ArrayRef<Substitution> subs);
10871085

10881086
ArgumentSource prepareAccessorBaseArg(SILLocation loc, ManagedValue base,
10891087
CanType baseFormalType,

0 commit comments

Comments
 (0)