@@ -432,59 +432,114 @@ matchCallArguments(SmallVectorImpl<AnyFunctionType::Param> &args,
432
432
haveUnfulfilledParams = true ;
433
433
};
434
434
435
- // If we have a trailing closure, it maps to the last parameter.
436
- // TODO: generalize this correctly for the closure arg index.
437
- if (unlabeledTrailingClosureArgIndex && numParams > 0 ) {
438
- unsigned lastParamIdx = numParams - 1 ;
439
- bool lastAcceptsTrailingClosure =
440
- acceptsTrailingClosure (params[lastParamIdx]);
441
-
442
- // If the last parameter is defaulted, this might be
443
- // an attempt to use a trailing closure with previous
444
- // parameter that accepts a function type e.g.
445
- //
446
- // func foo(_: () -> Int, _ x: Int = 0) {}
447
- // foo { 42 }
448
- if (!lastAcceptsTrailingClosure && numParams > 1 &&
449
- paramInfo.hasDefaultArgument (lastParamIdx)) {
450
- auto paramType = params[lastParamIdx - 1 ].getPlainType ();
451
- // If the parameter before defaulted last accepts.
452
- if (paramType->is <AnyFunctionType>()) {
453
- lastAcceptsTrailingClosure = true ;
454
- lastParamIdx -= 1 ;
435
+ // If we have an unlabeled trailing closure, we match trailing closure
436
+ // labels from the end, then match the trailing closure arg.
437
+ if (unlabeledTrailingClosureArgIndex) {
438
+ unsigned unlabeledArgIdx = *unlabeledTrailingClosureArgIndex;
439
+
440
+ // One past the next parameter index to look at.
441
+ unsigned prevParamIdx = numParams;
442
+
443
+ // Scan backwards to match any labeled trailing closures.
444
+ for (unsigned argIdx = numArgs - 1 ; argIdx != unlabeledArgIdx; --argIdx) {
445
+ bool claimed = false ;
446
+
447
+ // We do this scan on a copy of prevParamIdx so that, if it fails,
448
+ // we'll restart at this same point for the next trailing closure.
449
+ unsigned prevParamIdxForArg = prevParamIdx;
450
+ while (prevParamIdxForArg > 0 ) {
451
+ prevParamIdxForArg -= 1 ;
452
+ unsigned paramIdx = prevParamIdxForArg;
453
+
454
+ // Check for an exact label match.
455
+ const auto ¶m = params[paramIdx];
456
+ if (param.getLabel () == args[argIdx].getLabel ()) {
457
+ parameterBindings[paramIdx].push_back (argIdx);
458
+ claim (param.getLabel (), argIdx);
459
+
460
+ // Future arguments should search prior to this parameter.
461
+ prevParamIdx = prevParamIdxForArg;
462
+ claimed = true ;
463
+ break ;
464
+ }
465
+ }
466
+
467
+ // If we ran out of parameters, there's no match for this argument.
468
+ // TODO: somehow fall through to report out-of-order arguments?
469
+ if (!claimed) {
470
+ if (listener.extraArgument (argIdx))
471
+ return true ;
455
472
}
456
473
}
457
474
458
- bool isExtraClosure = false ;
459
- // If there is no suitable last parameter to accept the trailing closure,
475
+ // Okay, we've matched all the labeled closures; scan backwards from
476
+ // there to match the unlabeled trailing closure.
477
+ Optional<unsigned > unlabeledParamIdx;
478
+ if (prevParamIdx > 0 ) {
479
+ unsigned paramIdx = prevParamIdx - 1 ;
480
+
481
+ bool lastAcceptsTrailingClosure =
482
+ acceptsTrailingClosure (params[paramIdx]);
483
+
484
+ // If the last parameter is defaulted, this might be
485
+ // an attempt to use a trailing closure with previous
486
+ // parameter that accepts a function type e.g.
487
+ //
488
+ // func foo(_: () -> Int, _ x: Int = 0) {}
489
+ // foo { 42 }
490
+ //
491
+ // FIXME: shouldn't this skip multiple arguments and look for
492
+ // something that acceptsTrailingClosure rather than just something
493
+ // with a function type?
494
+ if (!lastAcceptsTrailingClosure && paramIdx > 0 &&
495
+ paramInfo.hasDefaultArgument (paramIdx)) {
496
+ auto paramType = params[paramIdx - 1 ].getPlainType ();
497
+ // If the parameter before defaulted last accepts.
498
+ if (paramType->is <AnyFunctionType>()) {
499
+ lastAcceptsTrailingClosure = true ;
500
+ paramIdx -= 1 ;
501
+ }
502
+ }
503
+
504
+ if (lastAcceptsTrailingClosure)
505
+ unlabeledParamIdx = paramIdx;
506
+ }
507
+
508
+ // If there's no suitable last parameter to accept the trailing closure,
460
509
// notify the listener and bail if we need to.
461
- if (!lastAcceptsTrailingClosure) {
462
- if (numArgs > numParams) {
510
+ if (!unlabeledParamIdx) {
511
+ bool isExtraClosure = false ;
512
+
513
+ if (prevParamIdx == 0 ) {
514
+ isExtraClosure = true ;
515
+ } else if (unlabeledArgIdx > 0 ) {
463
516
// Argument before the trailing closure.
464
- unsigned prevArg = numArgs - 2 ;
517
+ unsigned prevArg = unlabeledArgIdx - 1 ;
465
518
auto &arg = args[prevArg];
466
519
// If the argument before trailing closure matches
467
520
// last parameter, this is just a special case of
468
521
// an extraneous argument.
469
- const auto param = params[numParams - 1 ];
522
+ const auto param = params[prevParamIdx - 1 ];
470
523
if (param.hasLabel () && param.getLabel () == arg.getLabel ()) {
471
524
isExtraClosure = true ;
472
- if (listener.extraArgument (numArgs - 1 ))
473
- return true ;
474
525
}
475
526
}
476
527
477
- if (!isExtraClosure &&
478
- listener.trailingClosureMismatch (lastParamIdx, numArgs - 1 ))
479
- return true ;
480
- }
528
+ if (isExtraClosure) {
529
+ if (listener.extraArgument (unlabeledArgIdx))
530
+ return true ;
531
+ } else {
532
+ if (listener.trailingClosureMismatch (prevParamIdx - 1 ,
533
+ unlabeledArgIdx))
534
+ return true ;
535
+ }
481
536
482
- // Claim the parameter/argument pair.
483
- claim (params[lastParamIdx]. getLabel (), numArgs - 1 ,
484
- /* ignoreNameClash= */ true );
485
- // Let's claim the trailing closure unless it's an extra argument.
486
- if (!isExtraClosure)
487
- parameterBindings[lastParamIdx]. push_back (numArgs - 1 );
537
+ } else {
538
+ // Claim the parameter/argument pair.
539
+ claim (params[*unlabeledParamIdx]. getLabel (), unlabeledArgIdx,
540
+ /* ignoreNameClash= */ true );
541
+ parameterBindings[*unlabeledParamIdx]. push_back (unlabeledArgIdx);
542
+ }
488
543
}
489
544
490
545
{
0 commit comments