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; }
/// 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; }