Skip to content

Commit 3cb7af0

Browse files
committed
Move SILGenFunction::buildThunkType out to a utility function
1 parent bd6f27b commit 3cb7af0

File tree

4 files changed

+296
-269
lines changed

4 files changed

+296
-269
lines changed

include/swift/SIL/TypeLowering.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,6 +1204,18 @@ CanSILFunctionType getNativeSILFunctionType(
12041204
Optional<SubstitutionMap> reqtSubs = None,
12051205
ProtocolConformanceRef witnessMethodConformance = ProtocolConformanceRef());
12061206

1207+
/// Build the type of a function transformation thunk.
1208+
CanSILFunctionType buildSILFunctionThunkType(
1209+
SILFunction *fn,
1210+
CanSILFunctionType &sourceType,
1211+
CanSILFunctionType &expectedType,
1212+
CanType &inputSubstType,
1213+
CanType &outputSubstType,
1214+
GenericEnvironment *&genericEnv,
1215+
SubstitutionMap &interfaceSubs,
1216+
CanType &dynamicSelfType,
1217+
bool withoutActuallyEscaping);
1218+
12071219
} // namespace swift
12081220

12091221
namespace llvm {

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2407,6 +2407,287 @@ CanSILFunctionType swift::getNativeSILFunctionType(
24072407
substConstant, reqtSubs, witnessMethodConformance, None);
24082408
}
24092409

2410+
/// Build a generic signature and environment for a re-abstraction thunk.
2411+
///
2412+
/// Most thunks share the generic environment with their original function.
2413+
/// The one exception is if the thunk type involves an open existential,
2414+
/// in which case we "promote" the opened existential to a new generic parameter.
2415+
///
2416+
/// \param SGF - the parent function
2417+
/// \param openedExistential - the opened existential to promote to a generic
2418+
// parameter, if any
2419+
/// \param inheritGenericSig - whether to inherit the generic signature from the
2420+
/// parent function.
2421+
/// \param genericEnv - the new generic environment
2422+
/// \param contextSubs - map old archetypes to new archetypes
2423+
/// \param interfaceSubs - map interface types to old archetypes
2424+
static CanGenericSignature
2425+
buildThunkSignature(SILFunction *fn,
2426+
bool inheritGenericSig,
2427+
OpenedArchetypeType *openedExistential,
2428+
GenericEnvironment *&genericEnv,
2429+
SubstitutionMap &contextSubs,
2430+
SubstitutionMap &interfaceSubs,
2431+
ArchetypeType *&newArchetype) {
2432+
auto *mod = fn->getModule().getSwiftModule();
2433+
auto &ctx = mod->getASTContext();
2434+
2435+
// If there's no opened existential, we just inherit the generic environment
2436+
// from the parent function.
2437+
if (openedExistential == nullptr) {
2438+
auto genericSig =
2439+
fn->getLoweredFunctionType()->getInvocationGenericSignature();
2440+
genericEnv = fn->getGenericEnvironment();
2441+
interfaceSubs = fn->getForwardingSubstitutionMap();
2442+
contextSubs = interfaceSubs;
2443+
return genericSig;
2444+
}
2445+
2446+
// Add the existing generic signature.
2447+
int depth = 0;
2448+
GenericSignature baseGenericSig;
2449+
if (inheritGenericSig) {
2450+
if (auto genericSig =
2451+
fn->getLoweredFunctionType()->getInvocationGenericSignature()) {
2452+
baseGenericSig = genericSig;
2453+
depth = genericSig.getGenericParams().back()->getDepth() + 1;
2454+
}
2455+
}
2456+
2457+
// Add a new generic parameter to replace the opened existential.
2458+
auto *newGenericParam =
2459+
GenericTypeParamType::get(/*type sequence*/ false, depth, 0, ctx);
2460+
2461+
assert(openedExistential->isRoot());
2462+
auto constraint = openedExistential->getExistentialType();
2463+
if (auto existential = constraint->getAs<ExistentialType>())
2464+
constraint = existential->getConstraintType();
2465+
2466+
Requirement newRequirement(RequirementKind::Conformance, newGenericParam,
2467+
constraint);
2468+
2469+
auto genericSig = buildGenericSignature(ctx, baseGenericSig,
2470+
{ newGenericParam },
2471+
{ newRequirement });
2472+
genericEnv = genericSig.getGenericEnvironment();
2473+
2474+
newArchetype = genericEnv->mapTypeIntoContext(newGenericParam)
2475+
->castTo<ArchetypeType>();
2476+
2477+
// Calculate substitutions to map the caller's archetypes to the thunk's
2478+
// archetypes.
2479+
if (auto calleeGenericSig = fn->getLoweredFunctionType()
2480+
->getInvocationGenericSignature()) {
2481+
contextSubs = SubstitutionMap::get(
2482+
calleeGenericSig,
2483+
[&](SubstitutableType *type) -> Type {
2484+
return genericEnv->mapTypeIntoContext(type);
2485+
},
2486+
MakeAbstractConformanceForGenericType());
2487+
}
2488+
2489+
// Calculate substitutions to map interface types to the caller's archetypes.
2490+
interfaceSubs = SubstitutionMap::get(
2491+
genericSig,
2492+
[&](SubstitutableType *type) -> Type {
2493+
if (type->isEqual(newGenericParam))
2494+
return openedExistential;
2495+
return fn->mapTypeIntoContext(type);
2496+
},
2497+
MakeAbstractConformanceForGenericType());
2498+
2499+
return genericSig.getCanonicalSignature();
2500+
}
2501+
2502+
/// Build the type of a function transformation thunk.
2503+
CanSILFunctionType swift::buildSILFunctionThunkType(
2504+
SILFunction *fn,
2505+
CanSILFunctionType &sourceType,
2506+
CanSILFunctionType &expectedType,
2507+
CanType &inputSubstType,
2508+
CanType &outputSubstType,
2509+
GenericEnvironment *&genericEnv,
2510+
SubstitutionMap &interfaceSubs,
2511+
CanType &dynamicSelfType,
2512+
bool withoutActuallyEscaping) {
2513+
// We shouldn't be thunking generic types here, and substituted function types
2514+
// ought to have their substitutions applied before we get here.
2515+
assert(!expectedType->isPolymorphic() &&
2516+
!expectedType->getCombinedSubstitutions());
2517+
assert(!sourceType->isPolymorphic() &&
2518+
!sourceType->getCombinedSubstitutions());
2519+
2520+
// Can't build a thunk without context, so we require ownership semantics
2521+
// on the result type.
2522+
assert(expectedType->getExtInfo().hasContext());
2523+
2524+
// This may inherit @noescape from the expectedType. The @noescape attribute
2525+
// is only stripped when using this type to materialize a new decl.
2526+
auto extInfoBuilder =
2527+
expectedType->getExtInfo().intoBuilder().withRepresentation(
2528+
SILFunctionType::Representation::Thin);
2529+
2530+
if (withoutActuallyEscaping)
2531+
extInfoBuilder = extInfoBuilder.withNoEscape(false);
2532+
2533+
// Does the thunk type involve archetypes other than opened existentials?
2534+
bool hasArchetypes = false;
2535+
// Does the thunk type involve an open existential type?
2536+
CanOpenedArchetypeType openedExistential;
2537+
auto archetypeVisitor = [&](CanType t) {
2538+
if (auto archetypeTy = dyn_cast<ArchetypeType>(t)) {
2539+
if (auto opened = dyn_cast<OpenedArchetypeType>(archetypeTy)) {
2540+
const auto root = cast<OpenedArchetypeType>(CanType(opened->getRoot()));
2541+
assert((openedExistential == CanArchetypeType() ||
2542+
openedExistential == root) &&
2543+
"one too many open existentials");
2544+
openedExistential = root;
2545+
} else {
2546+
hasArchetypes = true;
2547+
}
2548+
}
2549+
};
2550+
2551+
// Use the generic signature from the context if the thunk involves
2552+
// generic parameters.
2553+
CanGenericSignature genericSig;
2554+
SubstitutionMap contextSubs;
2555+
ArchetypeType *newArchetype = nullptr;
2556+
2557+
if (expectedType->hasArchetype() || sourceType->hasArchetype()) {
2558+
expectedType.visit(archetypeVisitor);
2559+
sourceType.visit(archetypeVisitor);
2560+
2561+
genericSig = buildThunkSignature(fn,
2562+
hasArchetypes,
2563+
openedExistential,
2564+
genericEnv,
2565+
contextSubs,
2566+
interfaceSubs,
2567+
newArchetype);
2568+
}
2569+
2570+
auto substTypeHelper = [&](SubstitutableType *type) -> Type {
2571+
if (CanType(type) == openedExistential)
2572+
return newArchetype;
2573+
2574+
// If a nested archetype is rooted on our opened existential, fail:
2575+
// Type::subst attempts to substitute the parent of a nested archetype
2576+
// only if it fails to find a replacement for the nested one.
2577+
if (auto *opened = dyn_cast<OpenedArchetypeType>(type)) {
2578+
if (openedExistential->isEqual(opened->getRoot())) {
2579+
return nullptr;
2580+
}
2581+
}
2582+
2583+
return Type(type).subst(contextSubs);
2584+
};
2585+
auto substConformanceHelper =
2586+
LookUpConformanceInSubstitutionMap(contextSubs);
2587+
2588+
// Utility function to apply contextSubs, and also replace the
2589+
// opened existential with the new archetype.
2590+
auto substFormalTypeIntoThunkContext =
2591+
[&](CanType t) -> CanType {
2592+
return t.subst(substTypeHelper, substConformanceHelper)
2593+
->getCanonicalType();
2594+
};
2595+
auto substLoweredTypeIntoThunkContext =
2596+
[&](CanSILFunctionType t) -> CanSILFunctionType {
2597+
return SILType::getPrimitiveObjectType(t)
2598+
.subst(fn->getModule(), substTypeHelper, substConformanceHelper)
2599+
.castTo<SILFunctionType>();
2600+
};
2601+
2602+
sourceType = substLoweredTypeIntoThunkContext(sourceType);
2603+
expectedType = substLoweredTypeIntoThunkContext(expectedType);
2604+
2605+
bool hasDynamicSelf = false;
2606+
2607+
if (inputSubstType) {
2608+
inputSubstType = substFormalTypeIntoThunkContext(inputSubstType);
2609+
hasDynamicSelf |= inputSubstType->hasDynamicSelfType();
2610+
}
2611+
2612+
if (outputSubstType) {
2613+
outputSubstType = substFormalTypeIntoThunkContext(outputSubstType);
2614+
hasDynamicSelf |= outputSubstType->hasDynamicSelfType();
2615+
}
2616+
2617+
hasDynamicSelf |= sourceType->hasDynamicSelfType();
2618+
hasDynamicSelf |= expectedType->hasDynamicSelfType();
2619+
2620+
// If our parent function was pseudogeneric, this thunk must also be
2621+
// pseudogeneric, since we have no way to pass generic parameters.
2622+
if (genericSig)
2623+
if (fn->getLoweredFunctionType()->isPseudogeneric())
2624+
extInfoBuilder = extInfoBuilder.withIsPseudogeneric();
2625+
2626+
// Add the function type as the parameter.
2627+
auto contextConvention =
2628+
fn->getTypeLowering(sourceType).isTrivial()
2629+
? ParameterConvention::Direct_Unowned
2630+
: ParameterConvention::Direct_Guaranteed;
2631+
SmallVector<SILParameterInfo, 4> params;
2632+
params.append(expectedType->getParameters().begin(),
2633+
expectedType->getParameters().end());
2634+
params.push_back({sourceType,
2635+
sourceType->getExtInfo().hasContext()
2636+
? contextConvention
2637+
: ParameterConvention::Direct_Unowned});
2638+
2639+
// If this thunk involves DynamicSelfType in any way, add a capture for it
2640+
// in case we need to recover metadata.
2641+
if (hasDynamicSelf) {
2642+
dynamicSelfType = fn->getDynamicSelfMetadata()->getType().getASTType();
2643+
if (!isa<MetatypeType>(dynamicSelfType)) {
2644+
dynamicSelfType = CanMetatypeType::get(dynamicSelfType,
2645+
MetatypeRepresentation::Thick);
2646+
}
2647+
params.push_back({dynamicSelfType, ParameterConvention::Direct_Unowned});
2648+
}
2649+
2650+
auto mapTypeOutOfContext = [&](CanType type) -> CanType {
2651+
return type->mapTypeOutOfContext()->getCanonicalType(genericSig);
2652+
};
2653+
2654+
// Map the parameter and expected types out of context to get the interface
2655+
// type of the thunk.
2656+
SmallVector<SILParameterInfo, 4> interfaceParams;
2657+
interfaceParams.reserve(params.size());
2658+
for (auto &param : params) {
2659+
auto interfaceParam = param.map(mapTypeOutOfContext);
2660+
interfaceParams.push_back(interfaceParam);
2661+
}
2662+
2663+
SmallVector<SILYieldInfo, 4> interfaceYields;
2664+
for (auto &yield : expectedType->getYields()) {
2665+
auto interfaceYield = yield.map(mapTypeOutOfContext);
2666+
interfaceYields.push_back(interfaceYield);
2667+
}
2668+
2669+
SmallVector<SILResultInfo, 4> interfaceResults;
2670+
for (auto &result : expectedType->getResults()) {
2671+
auto interfaceResult = result.map(mapTypeOutOfContext);
2672+
interfaceResults.push_back(interfaceResult);
2673+
}
2674+
2675+
Optional<SILResultInfo> interfaceErrorResult;
2676+
if (expectedType->hasErrorResult()) {
2677+
auto errorResult = expectedType->getErrorResult();
2678+
interfaceErrorResult = errorResult.map(mapTypeOutOfContext);;
2679+
}
2680+
2681+
// The type of the thunk function.
2682+
return SILFunctionType::get(
2683+
genericSig, extInfoBuilder.build(), expectedType->getCoroutineKind(),
2684+
ParameterConvention::Direct_Unowned, interfaceParams, interfaceYields,
2685+
interfaceResults, interfaceErrorResult,
2686+
expectedType->getPatternSubstitutions(), SubstitutionMap(),
2687+
fn->getASTContext());
2688+
2689+
}
2690+
24102691
//===----------------------------------------------------------------------===//
24112692
// Foreign SILFunctionTypes
24122693
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)