mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #59432 from xedin/rdar-94959816
[ConstraintSystem] Allow injecting `callAsFunction` after defaulted arguments
This commit is contained in:
@@ -467,6 +467,35 @@ static bool matchCallArgumentsImpl(
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's consider current closure to be extraneous if:
|
||||
//
|
||||
// - current parameter has a default value and doesn't accept a trailing
|
||||
// closure; and
|
||||
// - no other free parameter after this one accepts a trailing closure via
|
||||
// forward or backward scan. This check makes sure that it's safe to
|
||||
// reject and push it to the next parameter without affecting backward
|
||||
// scan logic.
|
||||
//
|
||||
// In other words - let's push the closure argument through defaulted
|
||||
// parameters until it can be considered extraneous if no parameters
|
||||
// could possibly match it.
|
||||
if (!paramInfo.acceptsUnlabeledTrailingClosureArgument(paramIdx) &&
|
||||
!parameterRequiresArgument(params, paramInfo, paramIdx)) {
|
||||
if (llvm::none_of(
|
||||
range(paramIdx + 1, params.size()), [&](unsigned idx) {
|
||||
return parameterBindings[idx].empty() &&
|
||||
(paramInfo.acceptsUnlabeledTrailingClosureArgument(
|
||||
idx) ||
|
||||
backwardScanAcceptsTrailingClosure(params[idx]));
|
||||
})) {
|
||||
haveUnfulfilledParams = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// If one or more parameters can match the closure, let's check
|
||||
// whether backward scan is applicable here.
|
||||
}
|
||||
|
||||
// If this parameter does not require an argument, consider applying a
|
||||
// backward-match rule that skips this parameter if doing so is the only
|
||||
// way to successfully match arguments to parameters.
|
||||
@@ -1076,8 +1105,10 @@ constraints::getCompletionArgInfo(ASTNode anchor, ConstraintSystem &CS) {
|
||||
class ArgumentFailureTracker : public MatchCallArgumentListener {
|
||||
protected:
|
||||
ConstraintSystem &CS;
|
||||
NullablePtr<ValueDecl> Callee;
|
||||
SmallVectorImpl<AnyFunctionType::Param> &Arguments;
|
||||
ArrayRef<AnyFunctionType::Param> Parameters;
|
||||
Optional<unsigned> UnlabeledTrailingClosureArgIndex;
|
||||
ConstraintLocatorBuilder Locator;
|
||||
|
||||
private:
|
||||
@@ -1109,11 +1140,14 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
ArgumentFailureTracker(ConstraintSystem &cs,
|
||||
ArgumentFailureTracker(ConstraintSystem &cs, ValueDecl *callee,
|
||||
SmallVectorImpl<AnyFunctionType::Param> &args,
|
||||
ArrayRef<AnyFunctionType::Param> params,
|
||||
Optional<unsigned> unlabeledTrailingClosureArgIndex,
|
||||
ConstraintLocatorBuilder locator)
|
||||
: CS(cs), Arguments(args), Parameters(params), Locator(locator) {}
|
||||
: CS(cs), Callee(callee), Arguments(args), Parameters(params),
|
||||
UnlabeledTrailingClosureArgIndex(unlabeledTrailingClosureArgIndex),
|
||||
Locator(locator) {}
|
||||
|
||||
~ArgumentFailureTracker() override {
|
||||
if (!MissingArguments.empty()) {
|
||||
@@ -1143,6 +1177,19 @@ public:
|
||||
if (!CS.shouldAttemptFixes())
|
||||
return true;
|
||||
|
||||
// If this is a trailing closure, let's check if the call is
|
||||
// to an init of a callable type. If so, let's not record it
|
||||
// as extraneous since it would be matched against implicitly
|
||||
// injected `.callAsFunction` call.
|
||||
if (UnlabeledTrailingClosureArgIndex &&
|
||||
argIdx == *UnlabeledTrailingClosureArgIndex && Callee) {
|
||||
if (auto *ctor = dyn_cast<ConstructorDecl>(Callee.get())) {
|
||||
auto resultTy = ctor->getResultInterfaceType();
|
||||
if (resultTy->isCallableNominalType(CS.DC))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ExtraArguments.push_back(std::make_pair(argIdx, Arguments[argIdx]));
|
||||
return false;
|
||||
}
|
||||
@@ -1251,12 +1298,15 @@ class CompletionArgumentTracker : public ArgumentFailureTracker {
|
||||
struct CompletionArgInfo ArgInfo;
|
||||
|
||||
public:
|
||||
CompletionArgumentTracker(ConstraintSystem &cs,
|
||||
CompletionArgumentTracker(ConstraintSystem &cs, ValueDecl *callee,
|
||||
SmallVectorImpl<AnyFunctionType::Param> &args,
|
||||
ArrayRef<AnyFunctionType::Param> params,
|
||||
Optional<unsigned> unlabeledTrailingClosureArgIndex,
|
||||
ConstraintLocatorBuilder locator,
|
||||
struct CompletionArgInfo ArgInfo)
|
||||
: ArgumentFailureTracker(cs, args, params, locator), ArgInfo(ArgInfo) {}
|
||||
: ArgumentFailureTracker(cs, callee, args, params,
|
||||
unlabeledTrailingClosureArgIndex, locator),
|
||||
ArgInfo(ArgInfo) {}
|
||||
|
||||
Optional<unsigned> missingArgument(unsigned paramIdx,
|
||||
unsigned argInsertIdx) override {
|
||||
@@ -1666,14 +1716,16 @@ static ConstraintSystem::TypeMatchResult matchCallArguments(
|
||||
if (cs.isForCodeCompletion()) {
|
||||
if (auto completionInfo = getCompletionArgInfo(locator.getAnchor(), cs)) {
|
||||
listener = std::make_unique<CompletionArgumentTracker>(
|
||||
cs, argsWithLabels, params, locator, *completionInfo);
|
||||
cs, callee, argsWithLabels, params,
|
||||
argList->getFirstTrailingClosureIndex(), locator, *completionInfo);
|
||||
}
|
||||
}
|
||||
if (!listener) {
|
||||
// We didn't create an argument tracker for code completion. Create a
|
||||
// normal one.
|
||||
listener = std::make_unique<ArgumentFailureTracker>(cs, argsWithLabels,
|
||||
params, locator);
|
||||
listener = std::make_unique<ArgumentFailureTracker>(
|
||||
cs, callee, argsWithLabels, params,
|
||||
argList->getFirstTrailingClosureIndex(), locator);
|
||||
}
|
||||
auto callArgumentMatch = constraints::matchCallArguments(
|
||||
argsWithLabels, params, paramInfo,
|
||||
|
||||
Reference in New Issue
Block a user