@@ -44,8 +44,9 @@ bool MatchCallArgumentListener::incorrectLabel(unsigned paramIdx) {
4444 return true ;
4545}
4646
47- void MatchCallArgumentListener::outOfOrderArgument (unsigned argIdx,
47+ bool MatchCallArgumentListener::outOfOrderArgument (unsigned argIdx,
4848 unsigned prevArgIdx) {
49+ return true ;
4950}
5051
5152bool MatchCallArgumentListener::relabelArguments (ArrayRef<Identifier> newNames){
@@ -578,9 +579,47 @@ matchCallArguments(ArrayRef<AnyFunctionType::Param> args,
578579 // If any arguments were provided out-of-order, check whether we have
579580 // violated any of the reordering rules.
580581 if (potentiallyOutOfOrder) {
582+ // If we've seen label failures and now there is an out-of-order
583+ // parameter (or even worse - OoO parameter with label re-naming),
584+ // we most likely have no idea what would be the best
585+ // diagnostic for this situation, so let's just try to re-label.
586+ auto isOutOfOrderArgument = [&](bool hadLabelMismatch, unsigned argIdx,
587+ unsigned prevArgIdx) {
588+ if (hadLabelMismatch)
589+ return false ;
590+
591+ auto newLabel = args[argIdx].getLabel ();
592+ auto oldLabel = args[prevArgIdx].getLabel ();
593+
594+ unsigned actualIndex = prevArgIdx;
595+ for (; actualIndex != argIdx; ++actualIndex) {
596+ // Looks like new position (excluding defaulted parameters),
597+ // has a valid label.
598+ if (newLabel == params[actualIndex].getLabel ())
599+ break ;
600+
601+ // If we are moving the the position with a different label
602+ // and there is no default value for it, can't diagnose the
603+ // problem as a simple re-ordering.
604+ if (!defaultMap.test (actualIndex))
605+ return false ;
606+ }
607+
608+ for (unsigned i = actualIndex + 1 , n = params.size (); i != n; ++i) {
609+ if (oldLabel == params[i].getLabel ())
610+ break ;
611+
612+ if (!defaultMap.test (i))
613+ return false ;
614+ }
615+
616+ return true ;
617+ };
618+
581619 unsigned argIdx = 0 ;
582620 // Enumerate the parameters and their bindings to see if any arguments are
583621 // our of order
622+ bool hadLabelMismatch = false ;
584623 for (auto binding : parameterBindings) {
585624 for (auto boundArgIdx : binding) {
586625 // We've found the parameter that has an out of order
@@ -611,17 +650,20 @@ matchCallArguments(ArrayRef<AnyFunctionType::Param> args,
611650 // - The parameter is unnamed, in which case we try to fix the
612651 // problem by removing the name.
613652 if (expectedLabel.empty ()) {
653+ hadLabelMismatch = true ;
614654 if (listener.extraneousLabel (toArgIdx))
615655 return true ;
616656 // - The argument is unnamed, in which case we try to fix the
617657 // problem by adding the name.
618658 } else if (argumentLabel.empty ()) {
659+ hadLabelMismatch = true ;
619660 if (listener.missingLabel (toArgIdx))
620661 return true ;
621662 // - The argument label has a typo at the same position.
622- } else if (fromArgIdx == toArgIdx &&
623- listener.incorrectLabel (toArgIdx)) {
624- return true ;
663+ } else if (fromArgIdx == toArgIdx) {
664+ hadLabelMismatch = true ;
665+ if (listener.incorrectLabel (toArgIdx))
666+ return true ;
625667 }
626668 }
627669
@@ -631,8 +673,18 @@ matchCallArguments(ArrayRef<AnyFunctionType::Param> args,
631673 continue ;
632674 }
633675
634- listener.outOfOrderArgument (fromArgIdx, toArgIdx);
635- return true ;
676+ // This situation looks like out-of-order argument but it's hard
677+ // to say exactly without considering other factors, because it
678+ // could be invalid labeling too.
679+ if (isOutOfOrderArgument (hadLabelMismatch, fromArgIdx, toArgIdx))
680+ return listener.outOfOrderArgument (fromArgIdx, toArgIdx);
681+
682+ SmallVector<Identifier, 8 > expectedLabels;
683+ llvm::transform (params, std::back_inserter (expectedLabels),
684+ [](const AnyFunctionType::Param ¶m) {
685+ return param.getLabel ();
686+ });
687+ return listener.relabelArguments (expectedLabels);
636688 }
637689 }
638690 }
0 commit comments