Skip to content

Commit 563ce3c

Browse files
committed
[Trailing closures] Allow the unlabeled closure for variadic closure parameters.
Once the first argument for a variadic function-typed parameter has been matched, allow an unlabeled trailing closure to match, rather than banning all uses of the unlabeled trailing closure with variadic parameters.
1 parent 12e0abf commit 563ce3c

File tree

3 files changed

+41
-18
lines changed

3 files changed

+41
-18
lines changed

lib/AST/Type.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -839,8 +839,9 @@ static bool allowsUnlabeledTrailingClosureParameter(const ParamDecl *param) {
839839
if (param->isInOut())
840840
return false;
841841

842-
Type paramType =
843-
param->getInterfaceType()->getRValueType()->lookThroughAllOptionalTypes();
842+
Type paramType = param->isVariadic() ? param->getVarargBaseTy()
843+
: param->getInterfaceType();
844+
paramType = paramType->getRValueType()->lookThroughAllOptionalTypes();
844845

845846
// For autoclosure parameters, look through the autoclosure result type
846847
// to get the actual argument type.

lib/Sema/CSSimplify.cpp

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,15 @@ static ConstraintSystem::TypeMatchOptions getDefaultDecompositionOptions(
200200
return flags | ConstraintSystem::TMF_GenerateConstraints;
201201
}
202202

203+
/// Whether the given parameter requires an argument.
204+
static bool parameterRequiresArgument(
205+
ArrayRef<AnyFunctionType::Param> params,
206+
const ParameterListInfo &paramInfo,
207+
unsigned paramIdx) {
208+
return !paramInfo.hasDefaultArgument(paramIdx)
209+
&& !params[paramIdx].isVariadic();
210+
}
211+
203212
/// Determine whether any parameter from the given index up until the end
204213
/// requires an argument to be provided.
205214
///
@@ -222,8 +231,7 @@ static bool anyParameterRequiresArgument(
222231
break;
223232

224233
// If this parameter requires an argument, tell the caller.
225-
if (!paramInfo.hasDefaultArgument(paramIdx)
226-
&& !params[paramIdx].isVariadic())
234+
if (parameterRequiresArgument(params, paramInfo, paramIdx))
227235
return true;
228236
}
229237

@@ -316,13 +324,6 @@ matchCallArguments(SmallVectorImpl<AnyFunctionType::Param> &args,
316324
if (numClaimedArgs == numArgs)
317325
return None;
318326

319-
// If we're claiming variadic arguments, do not claim an unlabeled trailing
320-
// closure argument.
321-
if (forVariadic &&
322-
unlabeledTrailingClosureArgIndex &&
323-
nextArgIdx == *unlabeledTrailingClosureArgIndex)
324-
return None;
325-
326327
// Go hunting for an unclaimed argument whose name does match.
327328
Optional<unsigned> claimedWithSameName;
328329
for (unsigned i = nextArgIdx; i != numArgs; ++i) {
@@ -425,10 +426,10 @@ matchCallArguments(SmallVectorImpl<AnyFunctionType::Param> &args,
425426
return;
426427
}
427428

428-
// If this parameter has a default argument, consider applying a "fuzzy"
429-
// match rule that skips this parameter if doing so is the only way to
430-
// satisfy
431-
if (paramInfo.hasDefaultArgument(paramIdx) &&
429+
// If this parameter does not require an argument, consider applying a
430+
// "fuzzy" match rule that skips this parameter if doing so is the only
431+
// way to successfully match arguments to parameters.
432+
if (!parameterRequiresArgument(params, paramInfo, paramIdx) &&
432433
param.getPlainType()->getASTContext().LangOpts
433434
.EnableFuzzyForwardScanTrailingClosureMatching &&
434435
anyParameterRequiresArgument(
@@ -469,10 +470,21 @@ matchCallArguments(SmallVectorImpl<AnyFunctionType::Param> &args,
469470
auto currentNextArgIdx = nextArgIdx;
470471
{
471472
nextArgIdx = *claimed;
473+
472474
// Claim any additional unnamed arguments.
473-
while (
474-
(claimed = claimNextNamed(nextArgIdx, Identifier(), false, true))) {
475-
parameterBindings[paramIdx].push_back(*claimed);
475+
while (true) {
476+
// If the next argument is the unlabeled trailing closure and the
477+
// variadic parameter does not accept the unlabeled trailing closure
478+
// argument, we're done.
479+
if (unlabeledTrailingClosureArgIndex &&
480+
skipClaimedArgs(nextArgIdx) == *unlabeledTrailingClosureArgIndex &&
481+
!paramInfo.acceptsUnlabeledTrailingClosureArgument(paramIdx))
482+
break;
483+
484+
if ((claimed = claimNextNamed(nextArgIdx, Identifier(), false, true)))
485+
parameterBindings[paramIdx].push_back(*claimed);
486+
else
487+
break;
476488
}
477489
}
478490

test/expr/postfix/call/forward_trailing_closure.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,13 @@ func testForwardMatchWithAutoclosure2(i: Int, s: String) {
8181
return i
8282
}
8383
}
84+
85+
// Match a closure parameter to a variadic parameter.
86+
func acceptsVariadicClosureParameter(closures: ((Int, Int) -> Int)...) {
87+
}
88+
89+
func testVariadicClosureParameter() {
90+
acceptsVariadicClosureParameter { x, y in x % y }
91+
acceptsVariadicClosureParameter() { x, y in x % y }
92+
acceptsVariadicClosureParameter(closures: +, -, *, /) { x, y in x % y }
93+
}

0 commit comments

Comments
 (0)