ManagedValue SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, AnyFunctionRef TheClosure) { assert(((constant.uncurryLevel == 1 && TheClosure.getCaptureInfo().hasLocalCaptures()) || (constant.uncurryLevel == 0 && !TheClosure.getCaptureInfo().hasLocalCaptures())) && "curried local functions not yet supported"); auto constantInfo = getConstantInfo(constant); SILValue functionRef = emitGlobalFunctionRef(loc, constant, constantInfo); SILType functionTy = functionRef->getType(); auto expectedType = cast<FunctionType>(TheClosure.getType()->getCanonicalType()); // Forward substitutions from the outer scope. auto pft = constantInfo.SILFnType; auto forwardSubs = constantInfo.getForwardingSubstitutions(getASTContext()); bool wasSpecialized = false; if (pft->isPolymorphic() && !forwardSubs.empty()) { auto specialized = pft->substGenericArgs(F.getModule(), F.getModule().getSwiftModule(), forwardSubs); functionTy = SILType::getPrimitiveObjectType(specialized); wasSpecialized = true; } if (!TheClosure.getCaptureInfo().hasLocalCaptures() && !wasSpecialized) { auto result = ManagedValue::forUnmanaged(functionRef); return emitOrigToSubstValue(loc, result, AbstractionPattern(expectedType), expectedType); } SmallVector<ManagedValue, 4> capturedArgs; emitCaptures(loc, TheClosure, CaptureEmission::PartialApplication, capturedArgs); // The partial application takes ownership of the context parameters. SmallVector<SILValue, 4> forwardedArgs; for (auto capture : capturedArgs) forwardedArgs.push_back(capture.forward(*this)); SILType closureTy = SILGenBuilder::getPartialApplyResultType(functionRef->getType(), capturedArgs.size(), SGM.M, forwardSubs); auto toClosure = B.createPartialApply(loc, functionRef, functionTy, forwardSubs, forwardedArgs, closureTy); auto result = emitManagedRValueWithCleanup(toClosure); return emitOrigToSubstValue(loc, result, AbstractionPattern(expectedType), expectedType); }
static unsigned getFuncNaturalUncurryLevel(AnyFunctionRef AFR) { assert(AFR.getParameterLists().size() >= 1 && "no arguments for func?!"); unsigned Level = AFR.getParameterLists().size() - 1; // Functions with captures have an extra uncurry level for the capture // context. if (AFR.getCaptureInfo().hasLocalCaptures()) Level += 1; return Level; }
static unsigned getFuncNaturalUncurryLevel(AnyFunctionRef AFR) { assert(AFR.getParameterLists().size() >= 1 && "no arguments for func?!"); unsigned Level = AFR.getParameterLists().size() - 1; // Functions with captures have an extra uncurry level for the capture // context. llvm::DenseSet<AnyFunctionRef> visited; visited.insert(AFR); if (hasLoweredLocalCaptures(AFR, visited)) Level += 1; return Level; }
void SILGenFunction::emitProlog(AnyFunctionRef TheClosure, ArrayRef<ParameterList*> paramPatterns, Type resultType) { unsigned ArgNo = emitProlog(paramPatterns, resultType, TheClosure.getAsDeclContext()); // Emit the capture argument variables. These are placed last because they // become the first curry level of the SIL function. auto captureInfo = SGM.Types.getLoweredLocalCaptures(TheClosure); for (auto capture : captureInfo.getCaptures()) { if (capture.isDynamicSelfMetadata()) { auto selfMetatype = MetatypeType::get( captureInfo.getDynamicSelfType()->getSelfType(), MetatypeRepresentation::Thick) ->getCanonicalType(); SILType ty = SILType::getPrimitiveObjectType(selfMetatype); SILValue val = new (SGM.M) SILArgument(F.begin(), ty); (void) val; return; } emitCaptureArguments(*this, capture, ++ArgNo); } }
void SILGenFunction::emitProlog(AnyFunctionRef TheClosure, ArrayRef<ParameterList*> paramPatterns, Type resultType) { unsigned ArgNo = emitProlog(paramPatterns, resultType, TheClosure.getAsDeclContext()); // Emit the capture argument variables. These are placed last because they // become the first curry level of the SIL function. auto captureInfo = SGM.Types.getLoweredLocalCaptures(TheClosure); for (auto capture : captureInfo.getCaptures()) emitCaptureArguments(*this, capture, ++ArgNo); }
void SILGenFunction::emitProlog(AnyFunctionRef TheClosure, ArrayRef<ParameterList*> paramPatterns, Type resultType, bool throws) { uint16_t ArgNo = emitProlog(paramPatterns, resultType, TheClosure.getAsDeclContext(), throws); // Emit the capture argument variables. These are placed last because they // become the first curry level of the SIL function. auto captureInfo = SGM.Types.getLoweredLocalCaptures(TheClosure); for (auto capture : captureInfo.getCaptures()) { if (capture.isDynamicSelfMetadata()) { auto selfMetatype = MetatypeType::get( captureInfo.getDynamicSelfType()); SILType ty = getLoweredType(selfMetatype); SILValue val = F.begin()->createFunctionArgument(ty); (void) val; return; } emitCaptureArguments(*this, TheClosure, capture, ++ArgNo); } }
void SILGenFunction::emitProlog(AnyFunctionRef TheClosure, ParameterList *paramList, ParamDecl *selfParam, Type resultType, bool throws) { uint16_t ArgNo = emitProlog(paramList, selfParam, resultType, TheClosure.getAsDeclContext(), throws); // Emit an unreachable instruction if a parameter type is // uninhabited if (paramList) { for (auto *param : *paramList) { if (param->getType()->isStructurallyUninhabited()) { SILLocation unreachableLoc(param); unreachableLoc.markAsPrologue(); B.createUnreachable(unreachableLoc); break; } } } // Emit the capture argument variables. These are placed last because they // become the first curry level of the SIL function. auto captureInfo = SGM.Types.getLoweredLocalCaptures(TheClosure); for (auto capture : captureInfo.getCaptures()) { if (capture.isDynamicSelfMetadata()) { auto selfMetatype = MetatypeType::get( captureInfo.getDynamicSelfType()); SILType ty = getLoweredType(selfMetatype); SILValue val = F.begin()->createFunctionArgument(ty); (void) val; return; } emitCaptureArguments(*this, TheClosure, capture, ++ArgNo); } }
/// TODO: We should consult the cached LoweredLocalCaptures the SIL /// TypeConverter calculates, but that would require plumbing SILModule& /// through every SILDeclRef constructor. Since this is only used to determine /// "natural uncurry level", and "uncurry level" is a concept we'd like to /// phase out, it's not worth it. static bool hasLoweredLocalCaptures(AnyFunctionRef AFR, llvm::DenseSet<AnyFunctionRef> &visited) { if (!AFR.getCaptureInfo().hasLocalCaptures()) return false; // Scan for local, non-function captures. bool functionCapturesToRecursivelyCheck = false; auto addFunctionCapture = [&](AnyFunctionRef capture) { if (visited.find(capture) == visited.end()) functionCapturesToRecursivelyCheck = true; }; for (auto &capture : AFR.getCaptureInfo().getCaptures()) { if (!capture.getDecl()->getDeclContext()->isLocalContext()) continue; // We transitively capture a local function's captures. if (auto func = dyn_cast<AbstractFunctionDecl>(capture.getDecl())) { addFunctionCapture(func); continue; } // We may either directly capture properties, or capture through their // accessors. if (auto var = dyn_cast<VarDecl>(capture.getDecl())) { switch (var->getStorageKind()) { case VarDecl::StoredWithTrivialAccessors: llvm_unreachable("stored local variable with trivial accessors?"); case VarDecl::InheritedWithObservers: llvm_unreachable("inherited local variable?"); case VarDecl::StoredWithObservers: case VarDecl::Addressed: case VarDecl::AddressedWithTrivialAccessors: case VarDecl::AddressedWithObservers: case VarDecl::ComputedWithMutableAddress: // Directly capture storage if we're supposed to. if (capture.isDirect()) return true; // Otherwise, transitively capture the accessors. SWIFT_FALLTHROUGH; case VarDecl::Computed: addFunctionCapture(var->getGetter()); if (auto setter = var->getSetter()) addFunctionCapture(setter); continue; case VarDecl::Stored: return true; } } // Anything else is directly captured. return true; } // Recursively consider function captures, since we didn't have any direct // captures. auto captureHasLocalCaptures = [&](AnyFunctionRef capture) -> bool { if (visited.insert(capture).second) return hasLoweredLocalCaptures(capture, visited); return false; }; if (functionCapturesToRecursivelyCheck) { for (auto &capture : AFR.getCaptureInfo().getCaptures()) { if (!capture.getDecl()->getDeclContext()->isLocalContext()) continue; if (auto func = dyn_cast<AbstractFunctionDecl>(capture.getDecl())) { if (captureHasLocalCaptures(func)) return true; continue; } if (auto var = dyn_cast<VarDecl>(capture.getDecl())) { switch (var->getStorageKind()) { case VarDecl::StoredWithTrivialAccessors: llvm_unreachable("stored local variable with trivial accessors?"); case VarDecl::InheritedWithObservers: llvm_unreachable("inherited local variable?"); case VarDecl::StoredWithObservers: case VarDecl::Addressed: case VarDecl::AddressedWithTrivialAccessors: case VarDecl::AddressedWithObservers: case VarDecl::ComputedWithMutableAddress: assert(!capture.isDirect() && "should have short circuited out"); // Otherwise, transitively capture the accessors. SWIFT_FALLTHROUGH; case VarDecl::Computed: if (captureHasLocalCaptures(var->getGetter())) return true; if (auto setter = var->getSetter()) if (captureHasLocalCaptures(setter)) return true; continue; case VarDecl::Stored: llvm_unreachable("should have short circuited out"); } } llvm_unreachable("should have short circuited out"); } } return false; }
static void emitCaptureArguments(SILGenFunction &SGF, AnyFunctionRef closure, CapturedValue capture, uint16_t ArgNo) { auto *VD = capture.getDecl(); SILLocation Loc(VD); Loc.markAsPrologue(); // Local function to get the captured variable type within the capturing // context. auto getVarTypeInCaptureContext = [&]() -> Type { auto interfaceType = VD->getInterfaceType(); return GenericEnvironment::mapTypeIntoContext( closure.getGenericEnvironment(), interfaceType); }; // FIXME: Expansion auto expansion = ResilienceExpansion::Minimal; switch (SGF.SGM.Types.getDeclCaptureKind(capture, expansion)) { case CaptureKind::None: break; case CaptureKind::Constant: { auto type = getVarTypeInCaptureContext(); auto &lowering = SGF.getTypeLowering(type); // Constant decls are captured by value. SILType ty = lowering.getLoweredType(); SILValue val = SGF.F.begin()->createFunctionArgument(ty, VD); bool NeedToDestroyValueAtExit = false; // If the original variable was settable, then Sema will have treated the // VarDecl as an lvalue, even in the closure's use. As such, we need to // allow formation of the address for this captured value. Create a // temporary within the closure to provide this address. if (VD->isSettable(VD->getDeclContext())) { auto addr = SGF.emitTemporaryAllocation(VD, ty); // We have created a copy that needs to be destroyed. val = SGF.B.emitCopyValueOperation(Loc, val); NeedToDestroyValueAtExit = true; lowering.emitStore(SGF.B, VD, val, addr, StoreOwnershipQualifier::Init); val = addr; } SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(val); if (auto *AllocStack = dyn_cast<AllocStackInst>(val)) AllocStack->setArgNo(ArgNo); else { SILDebugVariable DbgVar(/*Constant*/ true, ArgNo); SGF.B.createDebugValue(Loc, val, DbgVar); } // TODO: Closure contexts should always be guaranteed. if (NeedToDestroyValueAtExit && !lowering.isTrivial()) SGF.enterDestroyCleanup(val); break; } case CaptureKind::Box: { // LValues are captured as a retained @box that owns // the captured value. auto type = getVarTypeInCaptureContext(); auto boxTy = SGF.SGM.Types.getContextBoxTypeForCapture(VD, SGF.SGM.Types.getLoweredRValueType(type), SGF.F.getGenericEnvironment(), /*mutable*/ true); SILValue box = SGF.F.begin()->createFunctionArgument( SILType::getPrimitiveObjectType(boxTy), VD); SILValue addr = SGF.B.createProjectBox(VD, box, 0); SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(addr, box); SILDebugVariable DbgVar(/*Constant*/ false, ArgNo); SGF.B.createDebugValueAddr(Loc, addr, DbgVar); break; } case CaptureKind::StorageAddress: { // Non-escaping stored decls are captured as the address of the value. auto type = getVarTypeInCaptureContext(); SILType ty = SGF.getLoweredType(type).getAddressType(); SILValue addr = SGF.F.begin()->createFunctionArgument(ty, VD); SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(addr); SILDebugVariable DbgVar(/*Constant*/ true, ArgNo); SGF.B.createDebugValueAddr(Loc, addr, DbgVar); break; } } }
static void emitCaptureArguments(SILGenFunction &gen, AnyFunctionRef closure, CapturedValue capture, unsigned ArgNo) { auto *VD = capture.getDecl(); SILLocation Loc(VD); Loc.markAsPrologue(); // Local function to get the captured variable type within the capturing // context. auto getVarTypeInCaptureContext = [&]() -> Type { auto interfaceType = VD->getInterfaceType(); return GenericEnvironment::mapTypeIntoContext( closure.getGenericEnvironment(), interfaceType); }; switch (gen.SGM.Types.getDeclCaptureKind(capture)) { case CaptureKind::None: break; case CaptureKind::Constant: { auto type = getVarTypeInCaptureContext(); auto &lowering = gen.getTypeLowering(type); // Constant decls are captured by value. SILType ty = lowering.getLoweredType(); SILValue val = gen.F.begin()->createFunctionArgument(ty, VD); // If the original variable was settable, then Sema will have treated the // VarDecl as an lvalue, even in the closure's use. As such, we need to // allow formation of the address for this captured value. Create a // temporary within the closure to provide this address. if (VD->isSettable(VD->getDeclContext())) { auto addr = gen.emitTemporaryAllocation(VD, ty); lowering.emitStore(gen.B, VD, val, addr, StoreOwnershipQualifier::Init); val = addr; } gen.VarLocs[VD] = SILGenFunction::VarLoc::get(val); if (auto *AllocStack = dyn_cast<AllocStackInst>(val)) AllocStack->setArgNo(ArgNo); else gen.B.createDebugValue(Loc, val, {/*Constant*/true, ArgNo}); // TODO: Closure contexts should always be guaranteed. if (!gen.SGM.M.getOptions().EnableGuaranteedClosureContexts && !lowering.isTrivial()) gen.enterDestroyCleanup(val); break; } case CaptureKind::Box: { // LValues are captured as a retained @box that owns // the captured value. auto type = getVarTypeInCaptureContext(); auto boxTy = gen.SGM.Types.getContextBoxTypeForCapture(VD, gen.getLoweredType(type).getSwiftRValueType(), gen.F.getGenericEnvironment(), /*mutable*/ true); SILValue box = gen.F.begin()->createFunctionArgument( SILType::getPrimitiveObjectType(boxTy), VD); SILValue addr = gen.B.createProjectBox(VD, box, 0); gen.VarLocs[VD] = SILGenFunction::VarLoc::get(addr, box); gen.B.createDebugValueAddr(Loc, addr, {/*Constant*/false, ArgNo}); if (!gen.SGM.M.getOptions().EnableGuaranteedClosureContexts) gen.Cleanups.pushCleanup<StrongReleaseCleanup>(box); break; } case CaptureKind::StorageAddress: { // Non-escaping stored decls are captured as the address of the value. auto type = getVarTypeInCaptureContext(); SILType ty = gen.getLoweredType(type).getAddressType(); SILValue addr = gen.F.begin()->createFunctionArgument(ty, VD); gen.VarLocs[VD] = SILGenFunction::VarLoc::get(addr); gen.B.createDebugValueAddr(Loc, addr, {/*Constant*/true, ArgNo}); break; } } }