Skip to content

Commit 676e9df

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 e746017 commit 676e9df

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
@@ -829,8 +829,9 @@ static bool allowsUnlabeledTrailingClosureParameter(const ParamDecl *param) {
829829
if (param->isInOut())
830830
return false;
831831

832-
Type paramType =
833-
param->getInterfaceType()->getRValueType()->lookThroughAllOptionalTypes();
832+
Type paramType = param->isVariadic() ? param->getVarargBaseTy()
833+
: param->getInterfaceType();
834+
paramType = paramType->getRValueType()->lookThroughAllOptionalTypes();
834835

835836
// For autoclosure parameters, look through the autoclosure result type
836837
// to get the actual argument type.

lib/Sema/CSSimplify.cpp

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

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

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

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

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

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

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)