Skip to content

Commit c206216

Browse files
committed
[CSSimplify] Attempt to split trailing closures into an implicit .callAsFunction
In situations like `T(...) { ... }` where `T` is a callable type, it's not immediately clear whether trailing closures are associated with `.init` of `T` or implicit `.callAsFunction`. So if constructor didn't match trailing closures, let's attempt to split them off and form an implicit `.callAsFunction` call with them as a fallback.
1 parent 4acd8ca commit c206216

File tree

1 file changed

+101
-1
lines changed

1 file changed

+101
-1
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10647,8 +10647,108 @@ ConstraintSystem::simplifyApplicableFnConstraint(
1064710647
subKind, argumentsLoc, trailingClosureMatching);
1064810648

1064910649
switch (matchCallResult) {
10650-
case SolutionKind::Error:
10650+
case SolutionKind::Error: {
10651+
if (shouldAttemptFixes())
10652+
return SolutionKind::Error;
10653+
10654+
auto resultTy = func2->getResult();
10655+
10656+
// If this is a call that constructs a callable type with
10657+
// a trailing closure(s), closure(s) might not belong to
10658+
// the constructor but rather to implicit `callAsFunction`,
10659+
// there is no way to determine that without trying.
10660+
if (resultTy->isCallableNominalType(DC) &&
10661+
argumentList->hasAnyTrailingClosures()) {
10662+
auto *calleeLoc = getCalleeLocator(argumentsLoc);
10663+
10664+
bool isInit = false;
10665+
if (auto overload = findSelectedOverloadFor(calleeLoc)) {
10666+
isInit = bool(dyn_cast_or_null<ConstructorDecl>(
10667+
overload->choice.getDeclOrNull()));
10668+
}
10669+
10670+
if (!isInit)
10671+
return SolutionKind::Error;
10672+
10673+
auto &ctx = getASTContext();
10674+
auto numTrailing = argumentList->getNumTrailingClosures();
10675+
10676+
SmallVector<Argument, 4> newArguments;
10677+
SmallVector<Argument, 4> trailingClosures;
10678+
10679+
for (unsigned i = 0, n = argumentList->size(); i != n; ++i) {
10680+
if (argumentList->isTrailingClosureIndex(i)) {
10681+
trailingClosures.push_back(argumentList->get(i));
10682+
} else {
10683+
newArguments.push_back(argumentList->get(i));
10684+
}
10685+
}
10686+
10687+
// Original argument list with all the trailing closures removed.
10688+
auto *newArgumentList = ArgumentList::createParsed(
10689+
ctx, argumentList->getLParenLoc(), newArguments,
10690+
argumentList->getRParenLoc(),
10691+
/*firstTrailingClosureIndex=*/None);
10692+
10693+
auto trailingClosureTypes = func1->getParams().take_back(numTrailing);
10694+
// The original result type is going to become a result of
10695+
// implicit `.callAsFunction` instead since `.callAsFunction`
10696+
// is inserted between `.init` and trailing closures.
10697+
auto callAsFunctionResultTy = func1->getResult();
10698+
10699+
// The implicit replacement for original result type which
10700+
// represents a callable type produced by `.init` call.
10701+
auto callableType =
10702+
createTypeVariable(getConstraintLocator({}), /*flags=*/0);
10703+
10704+
// The original application type with all the trailing closures
10705+
// dropped from it and result replaced to the implicit variable.
10706+
func1 = FunctionType::get(func1->getParams().drop_back(numTrailing),
10707+
callableType, func1->getExtInfo());
10708+
10709+
auto matchCallResult = ::matchCallArguments(
10710+
*this, func2, newArgumentList, func1->getParams(),
10711+
func2->getParams(), subKind, argumentsLoc, trailingClosureMatching);
10712+
10713+
if (matchCallResult != SolutionKind::Solved)
10714+
return SolutionKind::Error;
10715+
10716+
// Note that `createImplicit` cannot be used here because it
10717+
// doesn't allow us to specify trailing closure index.
10718+
auto *implicitCallArgumentList = ArgumentList::createParsed(
10719+
ctx, /*LParen=*/SourceLoc(), trailingClosures,
10720+
/*RParen=*/SourceLoc(),
10721+
/*firstTrailingClosureIndex=*/0);
10722+
10723+
SmallVector<Identifier, 2> closureLabelsScratch;
10724+
// Create implicit `.callAsFunction` expression to use as an anchor
10725+
// for new argument list that only has trailing closures in it.
10726+
auto *implicitCall = UnresolvedDotExpr::createImplicit(
10727+
ctx, getAsExpr(argumentsLoc->getAnchor()), {ctx.Id_callAsFunction},
10728+
implicitCallArgumentList->getArgumentLabels(closureLabelsScratch));
10729+
10730+
associateArgumentList(
10731+
getConstraintLocator(implicitCall,
10732+
ConstraintLocator::ApplyArgument),
10733+
implicitCallArgumentList);
10734+
10735+
auto callAsFunctionArguments =
10736+
FunctionType::get(trailingClosureTypes, callAsFunctionResultTy,
10737+
FunctionType::ExtInfo());
10738+
10739+
// Form an unsolved constraint to apply trailing closures to a
10740+
// callable type produced by `.init`. This constraint would become
10741+
// active when `callableType` is bound.
10742+
addUnsolvedConstraint(Constraint::create(
10743+
*this, ConstraintKind::ApplicableFunction, callAsFunctionArguments,
10744+
callableType,
10745+
getConstraintLocator(implicitCall,
10746+
ConstraintLocator::ApplyFunction)));
10747+
break;
10748+
}
10749+
1065110750
return SolutionKind::Error;
10751+
}
1065210752

1065310753
case SolutionKind::Unsolved: {
1065410754
// Only occurs when there is an ambiguity between forward scanning and

0 commit comments

Comments
 (0)