Skip to content

Commit 45a7b45

Browse files
committed
[SILGen] Lower unapplied methods.
1 parent 4479996 commit 45a7b45

File tree

4 files changed

+197
-25
lines changed

4 files changed

+197
-25
lines changed

lib/SILGen/SILGen.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
430430
ResilienceExpansion expansion, unsigned &baseOperand,
431431
bool &needsGenericContext, SubstitutionMap subs, ValueDecl *decl,
432432
ArrayRef<ProtocolConformanceRef> indexHashables, CanType baseTy,
433-
DeclContext *useDC, bool forPropertyDescriptor);
433+
DeclContext *useDC, bool forPropertyDescriptor, bool isApplied = false);
434434

435435
/// Emit all differentiability witnesses for the given function, visiting its
436436
/// `@differentiable` and `@derivative` attributes.

lib/SILGen/SILGenApply.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7408,6 +7408,58 @@ RValue SILGenFunction::emitRValueForKeyPathMethod(
74087408
return emission.apply(C);
74097409
}
74107410

7411+
/// Emit a call to an unapplied keypath method.
7412+
RValue SILGenFunction::emitUnappliedKeyPathMethod(
7413+
SILLocation loc, ManagedValue base, CanType baseType,
7414+
AbstractFunctionDecl *method, Type methodTy, PreparedArguments &&methodArgs,
7415+
SubstitutionMap subs, SGFContext C) {
7416+
FormalEvaluationScope writebackScope(*this);
7417+
7418+
RValue selfRValue(*this, loc, baseType, base);
7419+
ArgumentSource selfArg(loc, std::move(selfRValue));
7420+
7421+
std::optional<Callee> callee =
7422+
Callee::formCallee(*this, method, selfArg.getSubstRValueType(),
7423+
SILDeclRef(method), subs, loc);
7424+
7425+
SILValue methodRef;
7426+
if (callee) {
7427+
SILDeclRef calleeMethod = callee->getMethodName();
7428+
auto &constantInfo =
7429+
SGM.Types.getConstantInfo(F.getTypeExpansionContext(), calleeMethod);
7430+
SILType methodTy = constantInfo.getSILType();
7431+
7432+
switch (callee->kind) {
7433+
case Callee::Kind::StandaloneFunction: {
7434+
SILFunction *silMethod = SGM.getFunction(calleeMethod, NotForDefinition);
7435+
methodRef = B.createFunctionRef(loc, silMethod);
7436+
break;
7437+
}
7438+
case Callee::Kind::ClassMethod: {
7439+
methodRef =
7440+
B.createClassMethod(loc, base.getValue(), calleeMethod, methodTy);
7441+
break;
7442+
}
7443+
case Callee::Kind::WitnessMethod: {
7444+
CanType protocolSelfType = baseType->getCanonicalType();
7445+
ProtocolDecl *protocol = cast<ProtocolDecl>(method->getDeclContext());
7446+
ProtocolConformanceRef conformance =
7447+
subs.lookupConformance(protocolSelfType, protocol);
7448+
methodRef = B.createWitnessMethod(loc, protocolSelfType, conformance,
7449+
calleeMethod, methodTy);
7450+
break;
7451+
}
7452+
default:
7453+
llvm_unreachable("Unhandled callee kind for unapplied key path method.");
7454+
}
7455+
}
7456+
7457+
auto partialMV = B.createPartialApply(loc, methodRef, subs, base,
7458+
ParameterConvention::Direct_Guaranteed);
7459+
CanType partialType = methodTy->getCanonicalType();
7460+
return RValue(*this, loc, partialType, partialMV);
7461+
}
7462+
74117463
/// Emit a call to an addressor.
74127464
///
74137465
/// Returns an l-value managed value.

lib/SILGen/SILGenExpr.cpp

Lines changed: 138 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3755,6 +3755,96 @@ static SILFunction *getOrCreateKeyPathAppliedMethod(
37553755
return thunk;
37563756
}
37573757

3758+
static SILFunction *getOrCreateUnappliedKeypathMethod(
3759+
SILGenModule &SGM, AbstractFunctionDecl *method, SubstitutionMap subs,
3760+
GenericEnvironment *genericEnv, ResilienceExpansion expansion,
3761+
ArrayRef<IndexTypePair> args, CanType baseType, CanType methodType) {
3762+
lookupMethodViaProtocol(method, subs);
3763+
3764+
auto genericSig =
3765+
genericEnv ? genericEnv->getGenericSignature().getCanonicalSignature()
3766+
: nullptr;
3767+
if (genericSig && genericSig->areAllParamsConcrete()) {
3768+
genericSig = nullptr;
3769+
genericEnv = nullptr;
3770+
}
3771+
3772+
// Build the thunk signature for an unapplied method.
3773+
auto signature = [&]() {
3774+
CanType loweredBaseTy = SGM.Types.getLoweredRValueType(
3775+
TypeExpansionContext::minimal(), AbstractionPattern::getOpaque(),
3776+
baseType);
3777+
CanType loweredMethodTy = SGM.Types.getLoweredRValueType(
3778+
TypeExpansionContext::minimal(), AbstractionPattern::getOpaque(),
3779+
methodType);
3780+
3781+
return SILFunctionType::get(
3782+
genericSig,
3783+
SILFunctionType::ExtInfo().withRepresentation(
3784+
SILFunctionType::Representation::KeyPathAccessorGetter),
3785+
SILCoroutineKind::None, ParameterConvention::Direct_Unowned,
3786+
{SILParameterInfo(loweredBaseTy,
3787+
ParameterConvention::Indirect_In_Guaranteed)},
3788+
{}, SILResultInfo(loweredMethodTy, ResultConvention::Indirect),
3789+
std::nullopt, SubstitutionMap(), SubstitutionMap(),
3790+
SGM.getASTContext());
3791+
}();
3792+
3793+
// Mangle the name of the thunk to see if we already created it.
3794+
auto name = Mangle::ASTMangler(SGM.getASTContext(), method)
3795+
.mangleKeyPathUnappliedMethodThunkHelper(
3796+
method, genericSig, baseType, subs, expansion);
3797+
auto loc = RegularLocation::getAutoGeneratedLocation();
3798+
auto thunk =
3799+
getOrCreateKeypathThunk(SGM, name, signature, genericEnv, expansion, loc);
3800+
if (!thunk->empty())
3801+
return thunk;
3802+
3803+
// Emit the thunk, which accesses the underlying property normally with
3804+
// reabstraction where necessary.
3805+
if (genericEnv) {
3806+
baseType = genericEnv->mapTypeIntoContext(baseType)->getCanonicalType();
3807+
methodType = genericEnv->mapTypeIntoContext(methodType)->getCanonicalType();
3808+
thunk->setGenericEnvironment(genericEnv);
3809+
}
3810+
SILGenFunction subSGF(SGM, *thunk, SGM.SwiftModule);
3811+
signature = subSGF.F.getLoweredFunctionTypeInContext(
3812+
subSGF.F.getTypeExpansionContext());
3813+
auto resultArgTy =
3814+
subSGF.silConv.getSILType(signature->getSingleResult(), signature,
3815+
subSGF.F.getTypeExpansionContext());
3816+
auto baseArgTy =
3817+
subSGF.silConv.getSILType(signature->getParameters()[0], signature,
3818+
subSGF.F.getTypeExpansionContext());
3819+
SILFunctionArgument *resultArg = nullptr;
3820+
SILFunctionArgument *baseArg = nullptr;
3821+
SILValue argPtr;
3822+
emitKeyPathThunk(SGM, subSGF, genericEnv, signature, thunk, args, resultArg,
3823+
resultArgTy, baseArg, baseArgTy, argPtr,
3824+
!args.empty() ? signature->getParameters()[1]
3825+
: SILParameterInfo());
3826+
3827+
ArgumentScope scope(subSGF, loc);
3828+
auto baseSubstValue =
3829+
emitKeyPathRValueBase(subSGF, method, loc, baseArg, baseType, subs);
3830+
auto preparedArgs =
3831+
loadIndexValuesForKeyPathComponent(subSGF, loc, method, args, argPtr);
3832+
3833+
ManagedValue resultSubst;
3834+
{
3835+
RValue resultRValue = subSGF.emitUnappliedKeyPathMethod(
3836+
loc, baseSubstValue, baseType, method, methodType,
3837+
std::move(preparedArgs), subs, SGFContext());
3838+
3839+
resultSubst = std::move(resultRValue).getAsSingleValue(subSGF, loc);
3840+
}
3841+
3842+
emitReturn(subSGF, methodType, resultSubst, resultArgTy, resultArg, scope,
3843+
loc);
3844+
SGM.emitLazyConformancesForFunction(thunk);
3845+
return thunk;
3846+
}
3847+
37583848
static void
37593849
getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
37603850
SILLocation loc,
@@ -4211,7 +4301,7 @@ KeyPathPatternComponent SILGenModule::emitKeyPathComponentForDecl(
42114301
ResilienceExpansion expansion, unsigned &baseOperand,
42124302
bool &needsGenericContext, SubstitutionMap subs, ValueDecl *decl,
42134303
ArrayRef<ProtocolConformanceRef> indexHashables, CanType baseTy,
4214-
DeclContext *useDC, bool forPropertyDescriptor) {
4304+
DeclContext *useDC, bool forPropertyDescriptor, bool isApplied) {
42154305
if (auto *storage = dyn_cast<AbstractFunctionDecl>(decl)) {
42164306
// ABI-compatible overrides do not have property descriptors, so we need
42174307
// to reference the overridden declaration instead.
@@ -4225,34 +4315,55 @@ KeyPathPatternComponent SILGenModule::emitKeyPathComponentForDecl(
42254315
SubstitutionMap externalSubs;
42264316
CanType componentTy;
42274317
auto methodTy = decl->getInterfaceType()->castTo<AnyFunctionType>();
4228-
// Otherwise, component type is method type without Self.
4229-
auto methodResTy = decl->getInterfaceType()->castTo<AnyFunctionType>();
4230-
if (auto genMethodTy = methodResTy->getAs<GenericFunctionType>())
4231-
methodResTy = genMethodTy->substGenericArgs(subs);
4232-
auto methodInterfaceTy = cast<AnyFunctionType>(
4233-
methodResTy->mapTypeOutOfContext()->getCanonicalType());
4234-
componentTy = methodInterfaceTy.getResult();
4318+
if (isApplied) {
4319+
// If method is applied, set component type to method result type.
4320+
auto methodResultTy =
4321+
methodTy->getResult()->castTo<AnyFunctionType>()->getResult();
4322+
if (auto genMethodTy = methodResultTy->getAs<GenericFunctionType>())
4323+
methodResultTy = genMethodTy->substGenericArgs(subs);
4324+
componentTy = methodResultTy->mapTypeOutOfContext()->getCanonicalType();
4325+
} else {
4326+
// Otherwise, component type is method type without Self.
4327+
if (auto genMethodTy = methodTy->getAs<GenericFunctionType>())
4328+
methodTy = genMethodTy->substGenericArgs(subs);
4329+
auto methodInterfaceTy = cast<AnyFunctionType>(
4330+
methodTy->mapTypeOutOfContext()->getCanonicalType());
4331+
componentTy = methodInterfaceTy.getResult();
4332+
}
42354333

4236-
SmallVector<IndexTypePair, 4> argTypes;
4237-
lowerKeyPathMemberIndexTypes(*this, argTypes, decl, subs,
4238-
needsGenericContext);
4334+
if (decl->getAttrs().hasAttribute<OptionalAttr>()) {
4335+
// The component type for an @objc optional requirement needs to be
4336+
// wrapped in an optional
4337+
componentTy = OptionalType::get(componentTy)->getCanonicalType();
4338+
}
42394339

4340+
SmallVector<IndexTypePair, 4> argTypes;
42404341
SmallVector<KeyPathPatternComponent::Index, 4> argPatterns;
42414342
SILFunction *argEquals = nullptr, *argHash = nullptr;
4242-
lowerKeyPathMemberIndexPatterns(argPatterns, argTypes, indexHashables,
4243-
baseOperand);
4244-
4245-
getOrCreateKeyPathEqualsAndHash(*this, loc,
4246-
needsGenericContext ? genericEnv : nullptr,
4247-
expansion, argPatterns, argEquals, argHash);
4343+
if (isApplied) {
4344+
lowerKeyPathMemberIndexTypes(*this, argTypes, decl, subs,
4345+
needsGenericContext);
4346+
lowerKeyPathMemberIndexPatterns(argPatterns, argTypes, indexHashables,
4347+
baseOperand);
4348+
getOrCreateKeyPathEqualsAndHash(
4349+
*this, loc, needsGenericContext ? genericEnv : nullptr, expansion,
4350+
argPatterns, argEquals, argHash);
4351+
}
42484352

42494353
auto representative = SILDeclRef(storage, SILDeclRef::Kind::Func,
42504354
/*isForeign*/ storage->isImportAsMember());
42514355
auto id = getFunction(representative, NotForDefinition);
42524356

4253-
auto func = getOrCreateKeyPathAppliedMethod(
4254-
*this, storage, subs, needsGenericContext ? genericEnv : nullptr,
4255-
expansion, argTypes, baseTy, componentTy);
4357+
SILFunction *func = nullptr;
4358+
if (isApplied) {
4359+
func = getOrCreateKeyPathAppliedMethod(
4360+
*this, storage, subs, needsGenericContext ? genericEnv : nullptr,
4361+
expansion, argTypes, baseTy, componentTy);
4362+
} else {
4363+
func = getOrCreateUnappliedKeypathMethod(
4364+
*this, storage, subs, needsGenericContext ? genericEnv : nullptr,
4365+
expansion, argTypes, baseTy, componentTy);
4366+
}
42564367

42574368
auto argPatternsCopy = getASTContext().AllocateCopy(argPatterns);
42584369
return KeyPathPatternComponent::forMethod(id, func, argPatternsCopy,
@@ -4517,11 +4628,13 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) {
45174628
auto decl = component.getDeclRef().getDecl();
45184629

45194630
// If method is applied, get args from subsequent Apply component.
4631+
bool isApplied = false;
45204632
auto argComponent = components[i];
4521-
if (auto func = dyn_cast<FuncDecl>(decl);
4633+
if (auto func = dyn_cast<AbstractFunctionDecl>(decl);
45224634
func && i + 1 < components.size() &&
45234635
components[i + 1].getKind() == KeyPathExpr::Component::Kind::Apply) {
45244636
argComponent = components[i + 1];
4637+
isApplied = true;
45254638
}
45264639

45274640
unsigned numOperands = operands.size();
@@ -4530,10 +4643,11 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) {
45304643
SGF.F.getResilienceExpansion(), numOperands, needsGenericContext,
45314644
component.getDeclRef().getSubstitutions(), decl,
45324645
argComponent.getIndexHashableConformances(), baseTy, SGF.FunctionDC,
4533-
/*for descriptor*/ false));
4646+
/*for descriptor*/ false, /*is applied func*/ isApplied));
45344647
baseTy = loweredComponents.back().getComponentType();
4535-
if (kind == KeyPathExpr::Component::Kind::Member &&
4536-
!dyn_cast<FuncDecl>(decl))
4648+
if ((kind == KeyPathExpr::Component::Kind::Member &&
4649+
!dyn_cast<FuncDecl>(decl)) ||
4650+
(dyn_cast<FuncDecl>(decl) && !isApplied))
45374651
break;
45384652

45394653
auto loweredArgs = SGF.emitKeyPathOperands(

lib/SILGen/SILGenFunction.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,6 +1967,12 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
19671967
PreparedArguments &&methodArgs,
19681968
SubstitutionMap subs, SGFContext C);
19691969

1970+
RValue emitUnappliedKeyPathMethod(SILLocation loc, ManagedValue base,
1971+
CanType baseType,
1972+
AbstractFunctionDecl *method, Type methodTy,
1973+
PreparedArguments &&methodArgs,
1974+
SubstitutionMap subs, SGFContext C);
1975+
19701976
ManagedValue emitAsyncLetStart(SILLocation loc,
19711977
SILValue taskOptions,
19721978
AbstractClosureExpr *asyncLetEntryPoint,

0 commit comments

Comments
 (0)