Skip to content

Commit e746017

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 f7f8096 commit e746017

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
@@ -199,6 +199,37 @@ static ConstraintSystem::TypeMatchOptions getDefaultDecompositionOptions(
199199
return flags | ConstraintSystem::TMF_GenerateConstraints;
200200
}
201201

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

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

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)