Skip to content

Commit 12e0abf

Browse files
committed
Extend the "fuzzy" forward scan matching to support multiple trailing closures
The "fuzzy" forward scan matching algorithm was only applied when there was a single, unlabeled trailing closure, but was disabled in the presence of multiple trailing closures. Extend the "fuzzy" match to account for multiple trailing closures, by restricting the search for "a later parameter that needs an argument" to stop when we find a parameter that matches the first (labeled) trailing closure.
1 parent ed541f3 commit 12e0abf

File tree

2 files changed

+57
-9
lines changed

2 files changed

+57
-9
lines changed

lib/Sema/CSSimplify.cpp

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

203+
/// Determine whether any parameter from the given index up until the end
204+
/// requires an argument to be provided.
205+
///
206+
/// \param params The parameters themselves.
207+
/// \param paramInfo Declaration-provided information about the parameters.
208+
/// \param firstParamIdx The first parameter to examine to determine whether any
209+
/// parameter in the range \c [paramIdx, params.size()) requires an argument.
210+
/// \param beforeLabel If non-empty, stop examining parameters when we reach
211+
/// a parameter with this label.
212+
static bool anyParameterRequiresArgument(
213+
ArrayRef<AnyFunctionType::Param> params,
214+
const ParameterListInfo &paramInfo,
215+
unsigned firstParamIdx,
216+
Optional<Identifier> beforeLabel) {
217+
for (unsigned paramIdx : range(firstParamIdx, params.size())) {
218+
// If have been asked to stop when we reach a parameter with a particular
219+
// label, and we see a parameter with that label, we're done: no parameter
220+
// requires an argument.
221+
if (beforeLabel && *beforeLabel == params[paramIdx].getLabel())
222+
break;
223+
224+
// If this parameter requires an argument, tell the caller.
225+
if (!paramInfo.hasDefaultArgument(paramIdx)
226+
&& !params[paramIdx].isVariadic())
227+
return true;
228+
}
229+
230+
// No parameters required arguments.
231+
return false;
232+
}
233+
203234
// FIXME: This should return ConstraintSystem::TypeMatchResult instead
204235
// to give more information to the solver about the failure.
205236
bool constraints::
@@ -394,17 +425,17 @@ matchCallArguments(SmallVectorImpl<AnyFunctionType::Param> &args,
394425
return;
395426
}
396427

397-
// If there is only one trailing closure argument, consider applying
398-
// a "fuzzy" match rule that skips this parameter if it is defaulted but
399-
// later parameters require an argument.
400-
if (nextArgIdx + 1 == numArgs &&
401-
paramInfo.hasDefaultArgument(paramIdx) &&
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) &&
402432
param.getPlainType()->getASTContext().LangOpts
403433
.EnableFuzzyForwardScanTrailingClosureMatching &&
404-
llvm::any_of(range(paramIdx + 1, params.size()), [&](unsigned idx) {
405-
return !paramInfo.hasDefaultArgument(idx)
406-
&& !params[idx].isVariadic();
407-
})) {
434+
anyParameterRequiresArgument(
435+
params, paramInfo, paramIdx + 1,
436+
nextArgIdx + 1 < numArgs
437+
? Optional<Identifier>(args[nextArgIdx + 1].getLabel())
438+
: Optional<Identifier>(None))) {
408439
haveUnfulfilledParams = true;
409440
return;
410441
}

test/expr/postfix/call/forward_trailing_closure_fuzzy.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,21 @@ func testDoSomething() {
1010
doSomething(onError: nil) { x in
1111
print(x)
1212
}
13+
14+
doSomething { e in
15+
print(e)
16+
} onCompletion: { x in
17+
print(x)
18+
}
19+
}
20+
21+
func trailingClosures(
22+
arg1: () -> Void = {},
23+
arg2: () -> Void,
24+
arg3: () -> Void = {}
25+
) {}
26+
27+
func testTrailingClosures() {
28+
trailingClosures { print("Hello!") }
29+
trailingClosures { print("Hello,") } arg3: { print("world!") }
1330
}

0 commit comments

Comments
 (0)