@@ -2749,13 +2749,66 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
2749
2749
return false ;
2750
2750
}
2751
2751
2752
- // Problems related to fixes forming ambiguous solution set
2753
- // could only be diagnosed (at the moment), if all of the fixes
2754
- // have the same callee locator, which means they fix different
2755
- // overloads of the same declaration.
2756
- ConstraintLocator *commonCalleeLocator = nullptr ;
2752
+ // Collect aggregated fixes from all solutions
2753
+ llvm::SmallMapVector<std::pair<ConstraintLocator *, FixKind>,
2754
+ llvm::SmallVector<ConstraintFix *, 4 >, 4 > aggregatedFixes;
2755
+ for (const auto &solution: solutions) {
2756
+ for (auto fixesPerLocator: solution.getAggregatedFixes ()) {
2757
+ for (auto kindAndFixes: fixesPerLocator.second ) {
2758
+ aggregatedFixes[{fixesPerLocator.first , kindAndFixes.first }]
2759
+ .push_back (kindAndFixes.second .front ());
2760
+ }
2761
+ }
2762
+ }
2763
+
2764
+ // If there are no overload differences, diagnose the common fixes.
2765
+ SolutionDiff solutionDiff (solutions);
2766
+ if (solutionDiff.overloads .size () == 0 ) {
2767
+ bool diagnosed = false ;
2768
+ ConstraintSystem::SolverScope scope (*this );
2769
+ applySolution (solutions.front ());
2770
+ for (auto fixes: aggregatedFixes) {
2771
+ // A common fix must appear in all solutions
2772
+ if (fixes.second .size () < solutions.size ()) continue ;
2773
+ diagnosed |= fixes.second .front ()->diagnose ();
2774
+ }
2775
+ return diagnosed;
2776
+ }
2777
+
2778
+ // If there is an overload difference, let's see if there's a common callee
2779
+ // locator for all of the fixes.
2780
+ auto ambiguousOverload = llvm::find_if (solutionDiff.overloads ,
2781
+ [&](const auto &overloadDiff) {
2782
+ return llvm::all_of (aggregatedFixes, [&](const auto &aggregatedFix) {
2783
+ auto *locator = aggregatedFix.first .first ;
2784
+ auto *anchor = locator->getAnchor ();
2785
+ // Assignment failures are all about the source expression, because
2786
+ // they treat destination as a contextual type.
2787
+ if (auto *assignExpr = dyn_cast<AssignExpr>(anchor))
2788
+ anchor = assignExpr->getSrc ();
2789
+
2790
+ if (auto *callExpr = dyn_cast<CallExpr>(anchor)) {
2791
+ if (!isa<TypeExpr>(callExpr->getDirectCallee ()))
2792
+ anchor = callExpr->getDirectCallee ();
2793
+ } else if (auto *applyExpr = dyn_cast<ApplyExpr>(anchor)) {
2794
+ anchor = applyExpr->getFn ();
2795
+ }
2796
+
2797
+ return overloadDiff.locator ->getAnchor () == anchor;
2798
+ });
2799
+ });
2800
+
2801
+ if (ambiguousOverload == solutionDiff.overloads .end ())
2802
+ return false ;
2803
+
2804
+ ConstraintLocator* commonCalleeLocator = ambiguousOverload->locator ;
2757
2805
SmallPtrSet<ValueDecl *, 4 > distinctChoices;
2758
2806
SmallVector<const Solution *, 4 > viableSolutions;
2807
+ assert (ambiguousOverload->choices .size () == solutions.size ());
2808
+ for (unsigned i = 0 ; i < solutions.size (); ++i) {
2809
+ if (distinctChoices.insert (ambiguousOverload->choices [i].getDecl ()).second )
2810
+ viableSolutions.push_back (&solutions[i]);
2811
+ }
2759
2812
2760
2813
enum class AmbiguityKind {
2761
2814
// / There is exactly one fix associated with each candidate.
@@ -2771,103 +2824,23 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
2771
2824
};
2772
2825
auto ambiguityKind = AmbiguityKind::CloseMatch;
2773
2826
2774
- bool diagnosable = llvm::all_of (solutions, [&](const Solution &solution) {
2775
- ArrayRef<ConstraintFix *> fixes = solution.Fixes ;
2776
-
2777
- if (fixes.empty ())
2827
+ // FIXME: Can this be re-written in a cleaner way?
2828
+ for (const auto &solution: solutions) {
2829
+ if (solution.Fixes .empty ())
2778
2830
return false ;
2779
2831
2780
- if (fixes.size () > 1 ) {
2781
- // Attempt to disambiguite in cases where the argument matches
2782
- // involves tuple mismatches. e.g.
2783
- // func t<T, U>(_: (T, U), _: (U, T)) {}
2784
- // func useTuples(_ x: Int, y: Float) {
2785
- // t((x, y), (x, y))
2786
- // }
2787
- // So fixes are ambiguous in all solutions.
2788
- if ((ambiguityKind == AmbiguityKind::CloseMatch ||
2789
- ambiguityKind == AmbiguityKind::ArgumentMismatch) &&
2790
- llvm::all_of (fixes, [](const ConstraintFix *fix) -> bool {
2791
- return fix->getKind () == FixKind::AllowTupleTypeMismatch;
2792
- })) {
2793
- ambiguityKind = AmbiguityKind::ArgumentMismatch;
2794
- } else {
2795
- ambiguityKind =
2796
- (ambiguityKind == AmbiguityKind::CloseMatch ||
2797
- ambiguityKind == AmbiguityKind::ArgumentMismatch ||
2798
- ambiguityKind == AmbiguityKind::ParameterList) &&
2799
- llvm::all_of (
2800
- fixes,
2801
- [](const ConstraintFix *fix) -> bool {
2802
- auto *locator = fix->getLocator ();
2803
- return locator
2804
- ->findLast <LocatorPathElt::ApplyArgument>()
2805
- .hasValue ();
2806
- })
2807
- ? AmbiguityKind::ParameterList
2808
- : AmbiguityKind::General;
2809
- }
2832
+ if (solution.Fixes .size () > 1 ) {
2833
+ ambiguityKind = (ambiguityKind == AmbiguityKind::CloseMatch ||
2834
+ ambiguityKind == AmbiguityKind::ParameterList) &&
2835
+ llvm::all_of (solution.Fixes , [](const ConstraintFix *fix) -> bool {
2836
+ auto *locator = fix->getLocator ();
2837
+ return locator->findLast <LocatorPathElt::ApplyArgument>().hasValue ();
2838
+ }) ? AmbiguityKind::ParameterList
2839
+ : AmbiguityKind::General;
2810
2840
}
2811
-
2812
- if (fixes.size () == 1 ) {
2813
- // Attempt to disambiguite in cases where all the solutions
2814
- // produces the same fixes for different generic arguments e.g.
2815
- // func f<T>(_: T, _: T) {}
2816
- // f(Int(1), Float(1))
2817
- //
2818
- ambiguityKind =
2819
- ((ambiguityKind == AmbiguityKind::CloseMatch ||
2820
- ambiguityKind == AmbiguityKind::ArgumentMismatch) &&
2821
- fixes.front ()->getKind () == FixKind::AllowArgumentTypeMismatch)
2822
- ? AmbiguityKind::ArgumentMismatch
2823
- : AmbiguityKind::CloseMatch;
2824
- }
2825
-
2826
- for (const auto *fix : fixes) {
2827
- auto *locator = fix->getLocator ();
2828
- // Assignment failures are all about the source expression,
2829
- // because they treat destination as a contextual type.
2830
- if (auto *anchor = locator->getAnchor ()) {
2831
- if (auto *assignExpr = dyn_cast<AssignExpr>(anchor))
2832
- locator = getConstraintLocator (assignExpr->getSrc ());
2833
- }
2834
-
2835
- auto *calleeLocator = solution.getCalleeLocator (locator);
2836
- if (!commonCalleeLocator)
2837
- commonCalleeLocator = calleeLocator;
2838
- else if (commonCalleeLocator != calleeLocator)
2839
- return false ;
2840
- }
2841
-
2842
- auto overload = solution.getOverloadChoiceIfAvailable (commonCalleeLocator);
2843
- if (!overload)
2844
- return false ;
2845
-
2846
- auto *decl = overload->choice .getDeclOrNull ();
2847
- if (!decl)
2848
- return false ;
2849
-
2850
- // If this declaration is distinct, let's record this solution
2851
- // as viable, otherwise we'd produce the same diagnostic multiple
2852
- // times, which means that actual problem is elsewhere.
2853
- if (distinctChoices.insert (decl).second )
2854
- viableSolutions.push_back (&solution);
2855
- return true ;
2856
- });
2857
-
2858
- if (ambiguityKind == AmbiguityKind::ArgumentMismatch &&
2859
- viableSolutions.size () == 1 ) {
2860
- // Let's apply the solution so the contextual generic types
2861
- // are available in the system for diagnostics.
2862
- applySolution (*viableSolutions[0 ]);
2863
- solutions.front ().Fixes .front ()->diagnose (/* asNote*/ false );
2864
- return true ;
2865
2841
}
2866
2842
2867
- if (!diagnosable || viableSolutions.size () < 2 )
2868
- return false ;
2869
-
2870
- auto *decl = *distinctChoices.begin ();
2843
+ auto *decl = ambiguousOverload->choices .front ().getDecl ();
2871
2844
assert (solverState);
2872
2845
2873
2846
bool diagnosed = true ;
0 commit comments