@@ -1190,6 +1190,11 @@ namespace {
1190
1190
// / overloads.
1191
1191
void suggestPotentialOverloads (SourceLoc loc, bool isResult = false );
1192
1192
1193
+ // / If the candidate set has been narrowed down to a specific structural
1194
+ // / problem, e.g. that there are too few parameters specified or that
1195
+ // / argument labels don't match up, diagnose that error and return true.
1196
+ bool diagnoseAnyStructuralArgumentError (Expr *argExpr);
1197
+
1193
1198
void dump () const LLVM_ATTRIBUTE_USED;
1194
1199
1195
1200
private:
@@ -1685,6 +1690,140 @@ suggestPotentialOverloads(SourceLoc loc, bool isResult) {
1685
1690
}
1686
1691
}
1687
1692
1693
+
1694
+ // / If the candidate set has been narrowed down to a specific structural
1695
+ // / problem, e.g. that there are too few parameters specified or that argument
1696
+ // / labels don't match up, diagnose that error and return true.
1697
+ bool CalleeCandidateInfo::diagnoseAnyStructuralArgumentError (Expr *argExpr) {
1698
+ // TODO: We only handle the situation where there is exactly one candidate
1699
+ // here.
1700
+ if (size () != 1 ) return false ;
1701
+
1702
+ // We only handle structural errors here.
1703
+ if (closeness != CC_ArgumentLabelMismatch &&
1704
+ closeness != CC_ArgumentCountMismatch)
1705
+ return false ;
1706
+
1707
+ auto args = decomposeArgParamType (argExpr->getType ());
1708
+ SmallVector<Identifier, 4 > correctNames;
1709
+ unsigned OOOArgIdx = ~0U , OOOPrevArgIdx = ~0U ;
1710
+ unsigned extraArgIdx = ~0U , missingParamIdx = ~0U ;
1711
+
1712
+ // If we have a single candidate that failed to match the argument list,
1713
+ // attempt to use matchCallArguments to diagnose the problem.
1714
+ struct OurListener : public MatchCallArgumentListener {
1715
+ SmallVectorImpl<Identifier> &correctNames;
1716
+ unsigned &OOOArgIdx, &OOOPrevArgIdx;
1717
+ unsigned &extraArgIdx, &missingParamIdx;
1718
+
1719
+ public:
1720
+ OurListener (SmallVectorImpl<Identifier> &correctNames,
1721
+ unsigned &OOOArgIdx, unsigned &OOOPrevArgIdx,
1722
+ unsigned &extraArgIdx, unsigned &missingParamIdx)
1723
+ : correctNames(correctNames),
1724
+ OOOArgIdx (OOOArgIdx), OOOPrevArgIdx(OOOPrevArgIdx),
1725
+ extraArgIdx(extraArgIdx), missingParamIdx(missingParamIdx) {}
1726
+ void extraArgument (unsigned argIdx) override {
1727
+ extraArgIdx = argIdx;
1728
+ }
1729
+ void missingArgument (unsigned paramIdx) override {
1730
+ missingParamIdx = paramIdx;
1731
+ }
1732
+ void outOfOrderArgument (unsigned argIdx, unsigned prevArgIdx) override {
1733
+ OOOArgIdx = argIdx;
1734
+ OOOPrevArgIdx = prevArgIdx;
1735
+ }
1736
+ bool relabelArguments (ArrayRef<Identifier> newNames) override {
1737
+ correctNames.append (newNames.begin (), newNames.end ());
1738
+ return true ;
1739
+ }
1740
+ } listener(correctNames, OOOArgIdx, OOOPrevArgIdx,
1741
+ extraArgIdx, missingParamIdx);
1742
+
1743
+ // Use matchCallArguments to determine how close the argument list is (in
1744
+ // shape) to the specified candidates parameters. This ignores the
1745
+ // concrete types of the arguments, looking only at the argument labels.
1746
+ SmallVector<ParamBinding, 4 > paramBindings;
1747
+ auto params = decomposeArgParamType(candidates[0 ].getArgumentType());
1748
+ if (!matchCallArguments(args, params, hasTrailingClosure,
1749
+ /* allowFixes:*/ true , listener, paramBindings))
1750
+ return false ;
1751
+
1752
+
1753
+ // If we are missing an parameter, diagnose that.
1754
+ if (missingParamIdx != ~0U ) {
1755
+ Identifier name = params[missingParamIdx].Label ;
1756
+ auto loc = argExpr->getStartLoc ();
1757
+ if (name.empty ())
1758
+ CS->TC .diagnose (loc, diag::missing_argument_positional,
1759
+ missingParamIdx+1 );
1760
+ else
1761
+ CS->TC .diagnose (loc, diag::missing_argument_named, name);
1762
+ return true ;
1763
+ }
1764
+
1765
+ if (extraArgIdx != ~0U ) {
1766
+ auto name = args[extraArgIdx].Label ;
1767
+ Expr *arg = argExpr;
1768
+ auto tuple = dyn_cast<TupleExpr>(argExpr);
1769
+ if (tuple)
1770
+ arg = tuple->getElement (extraArgIdx);
1771
+ auto loc = arg->getLoc ();
1772
+ if (tuple && extraArgIdx == tuple->getNumElements ()-1 &&
1773
+ tuple->hasTrailingClosure ())
1774
+ CS->TC .diagnose (loc, diag::extra_trailing_closure_in_call)
1775
+ .highlight (arg->getSourceRange ());
1776
+ else if (params.empty ())
1777
+ CS->TC .diagnose (loc, diag::extra_argument_to_nullary_call)
1778
+ .highlight (argExpr->getSourceRange ());
1779
+ else if (name.empty ())
1780
+ CS->TC .diagnose (loc, diag::extra_argument_positional)
1781
+ .highlight (arg->getSourceRange ());
1782
+ else
1783
+ CS->TC .diagnose (loc, diag::extra_argument_named, name)
1784
+ .highlight (arg->getSourceRange ());
1785
+ return true ;
1786
+ }
1787
+
1788
+ // If this is a argument label mismatch, then diagnose that error now.
1789
+ if (!correctNames.empty() &&
1790
+ CS->diagnoseArgumentLabelError (argExpr, correctNames,
1791
+ /* isSubscript=*/ false ))
1792
+ return true;
1793
+
1794
+ // If we have an out-of-order argument, diagnose it as such.
1795
+ if (OOOArgIdx != ~0U && isa<TupleExpr>(argExpr)) {
1796
+ auto tuple = cast<TupleExpr>(argExpr);
1797
+ Identifier first = tuple->getElementName (OOOArgIdx);
1798
+ Identifier second = tuple->getElementName (OOOPrevArgIdx);
1799
+
1800
+ SourceLoc diagLoc;
1801
+ if (!first.empty ())
1802
+ diagLoc = tuple->getElementNameLoc (OOOArgIdx);
1803
+ else
1804
+ diagLoc = tuple->getElement (OOOArgIdx)->getStartLoc ();
1805
+
1806
+ if (!second.empty ()) {
1807
+ CS->TC .diagnose (diagLoc, diag::argument_out_of_order, first, second)
1808
+ .highlight (tuple->getElement (OOOArgIdx)->getSourceRange ())
1809
+ .highlight (SourceRange (tuple->getElementNameLoc (OOOPrevArgIdx),
1810
+ tuple->getElement (OOOPrevArgIdx)->getEndLoc ()));
1811
+ return true ;
1812
+ }
1813
+
1814
+ CS->TC .diagnose (diagLoc, diag::argument_out_of_order_named_unnamed, first,
1815
+ OOOPrevArgIdx)
1816
+ .highlight (tuple->getElement (OOOArgIdx)->getSourceRange ())
1817
+ .highlight (tuple->getElement (OOOPrevArgIdx)->getSourceRange ());
1818
+ return true ;
1819
+ }
1820
+ return false ;
1821
+ }
1822
+
1823
+
1824
+
1825
+
1826
+
1688
1827
// / Flags that can be used to control name lookup.
1689
1828
enum TCCFlags {
1690
1829
// / Allow the result of the subexpression to be an lvalue. If this is not
@@ -3505,7 +3644,9 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
3505
3644
3506
3645
// Filter the candidate list based on the argument we may or may not have.
3507
3646
calleeInfo.filterContextualMemberList (callExpr->getArg ());
3508
-
3647
+
3648
+ if (calleeInfo.diagnoseAnyStructuralArgumentError (callExpr->getArg ()))
3649
+ return true ;
3509
3650
3510
3651
Type argType; // Type of the argument list, if knowable.
3511
3652
if (auto FTy = fnType->getAs <AnyFunctionType>())
@@ -3529,124 +3670,8 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
3529
3670
3530
3671
calleeInfo.filterList (argExpr->getType ());
3531
3672
3532
-
3533
- // If we filtered this down to exactly one candidate, see if we can produce
3534
- // an extremely specific error about it.
3535
- if (calleeInfo.size () == 1 ) {
3536
- if (calleeInfo.closeness == CC_ArgumentLabelMismatch ||
3537
- calleeInfo.closeness == CC_ArgumentCountMismatch) {
3538
- auto args = decomposeArgParamType (argExpr->getType ());
3539
- SmallVector<Identifier, 4 > correctNames;
3540
- unsigned OOOArgIdx = ~0U , OOOPrevArgIdx = ~0U ;
3541
- unsigned extraArgIdx = ~0U , missingParamIdx = ~0U ;
3542
-
3543
- // If we have a single candidate that failed to match the argument list,
3544
- // attempt to use matchCallArguments to diagnose the problem.
3545
- struct OurListener : public MatchCallArgumentListener {
3546
- SmallVectorImpl<Identifier> &correctNames;
3547
- unsigned &OOOArgIdx, &OOOPrevArgIdx;
3548
- unsigned &extraArgIdx, &missingParamIdx;
3549
-
3550
- public:
3551
- OurListener (SmallVectorImpl<Identifier> &correctNames,
3552
- unsigned &OOOArgIdx, unsigned &OOOPrevArgIdx,
3553
- unsigned &extraArgIdx, unsigned &missingParamIdx)
3554
- : correctNames(correctNames),
3555
- OOOArgIdx (OOOArgIdx), OOOPrevArgIdx(OOOPrevArgIdx),
3556
- extraArgIdx(extraArgIdx), missingParamIdx(missingParamIdx) {}
3557
- void extraArgument (unsigned argIdx) override {
3558
- extraArgIdx = argIdx;
3559
- }
3560
- void missingArgument (unsigned paramIdx) override {
3561
- missingParamIdx = paramIdx;
3562
- }
3563
- void outOfOrderArgument (unsigned argIdx, unsigned prevArgIdx) override {
3564
- OOOArgIdx = argIdx;
3565
- OOOPrevArgIdx = prevArgIdx;
3566
- }
3567
- bool relabelArguments (ArrayRef<Identifier> newNames) override {
3568
- correctNames.append (newNames.begin (), newNames.end ());
3569
- return true ;
3570
- }
3571
- } listener(correctNames, OOOArgIdx, OOOPrevArgIdx,
3572
- extraArgIdx, missingParamIdx);
3573
-
3574
- // Use matchCallArguments to determine how close the argument list is (in
3575
- // shape) to the specified candidates parameters. This ignores the
3576
- // concrete types of the arguments, looking only at the argument labels.
3577
- SmallVector<ParamBinding, 4 > paramBindings;
3578
- auto params = decomposeArgParamType(calleeInfo[0 ].getArgumentType());
3579
- if (matchCallArguments(args, params, hasTrailingClosure,
3580
- /* allowFixes:*/ true , listener, paramBindings)) {
3581
-
3582
- // If we are missing an parameter, diagnose that.
3583
- if (missingParamIdx != ~0U ) {
3584
- Identifier name = params[missingParamIdx].Label ;
3585
- auto loc = callExpr->getArg ()->getStartLoc ();
3586
- if (name.empty ())
3587
- diagnose (loc, diag::missing_argument_positional,
3588
- missingParamIdx+1 );
3589
- else
3590
- diagnose (loc, diag::missing_argument_named, name);
3591
- return true ;
3592
- }
3593
-
3594
- if (extraArgIdx != ~0U ) {
3595
- auto name = args[extraArgIdx].Label ;
3596
- Expr *arg = argExpr;
3597
- auto tuple = dyn_cast<TupleExpr>(argExpr);
3598
- if (tuple)
3599
- arg = tuple->getElement (extraArgIdx);
3600
- auto loc = arg->getLoc ();
3601
- if (tuple && extraArgIdx == tuple->getNumElements ()-1 &&
3602
- tuple->hasTrailingClosure ())
3603
- diagnose (loc, diag::extra_trailing_closure_in_call)
3604
- .highlight (arg->getSourceRange ());
3605
- else if (name.empty ())
3606
- diagnose (loc, diag::extra_argument_positional)
3607
- .highlight (arg->getSourceRange ());
3608
- else
3609
- diagnose (loc, diag::extra_argument_named, name)
3610
- .highlight (arg->getSourceRange ());
3611
- return true ;
3612
- }
3613
-
3614
- // If this is a argument label mismatch, then diagnose that error now.
3615
- if (!correctNames.empty () &&
3616
- CS->diagnoseArgumentLabelError (argExpr, correctNames,
3617
- /* isSubscript=*/ false ))
3618
- return true ;
3619
-
3620
- // If we have an out-of-order argument, diagnose it as such.
3621
- if (OOOArgIdx != ~0U && isa<TupleExpr>(callExpr->getArg ())) {
3622
- auto tuple = cast<TupleExpr>(callExpr->getArg ());
3623
- Identifier first = tuple->getElementName (OOOArgIdx);
3624
- Identifier second = tuple->getElementName (OOOPrevArgIdx);
3625
-
3626
- SourceLoc diagLoc;
3627
- if (!first.empty ())
3628
- diagLoc = tuple->getElementNameLoc (OOOArgIdx);
3629
- else
3630
- diagLoc = tuple->getElement (OOOArgIdx)->getStartLoc ();
3631
-
3632
- if (!second.empty ()) {
3633
- diagnose (diagLoc,
3634
- diag::argument_out_of_order, first, second)
3635
- .highlight (tuple->getElement (OOOArgIdx)->getSourceRange ())
3636
- .highlight (SourceRange (tuple->getElementNameLoc (OOOPrevArgIdx),
3637
- tuple->getElement (OOOPrevArgIdx)->getEndLoc ()));
3638
- return true ;
3639
- }
3640
-
3641
- diagnose (diagLoc, diag::argument_out_of_order_named_unnamed, first,
3642
- OOOPrevArgIdx)
3643
- .highlight (tuple->getElement (OOOArgIdx)->getSourceRange ())
3644
- .highlight (tuple->getElement (OOOPrevArgIdx)->getSourceRange ());
3645
- return true ;
3646
- }
3647
- }
3648
- }
3649
- }
3673
+ if (calleeInfo.diagnoseAnyStructuralArgumentError (argExpr))
3674
+ return true ;
3650
3675
3651
3676
// If we have a failure where the candidate set differs on exactly one
3652
3677
// argument, and where we have a consistent mismatch across the candidate set
0 commit comments