@@ -2958,6 +2958,8 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
2958
2958
// Collect aggregated fixes from all solutions
2959
2959
using LocatorAndKind = std::pair<ConstraintLocator *, FixKind>;
2960
2960
using SolutionAndFix = std::pair<const Solution *, const ConstraintFix *>;
2961
+ using AggregatedEntry = std::pair<LocatorAndKind,
2962
+ llvm::SmallVector<SolutionAndFix, 4 >>;
2961
2963
llvm::SmallMapVector<LocatorAndKind, llvm::SmallVector<SolutionAndFix, 4 >, 4 >
2962
2964
aggregatedFixes;
2963
2965
for (const auto &solution : solutions) {
@@ -2966,134 +2968,174 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
2966
2968
aggregatedFixes[key].emplace_back (&solution, fix);
2967
2969
}
2968
2970
}
2971
+
2972
+ auto getAggregatedFixAnchor = [](const AggregatedEntry &aggregatedFix) {
2973
+ auto *locator = aggregatedFix.first .first ;
2974
+ auto anchor = locator->getAnchor ();
2975
+ // Assignment failures are all about the source expression, because
2976
+ // they treat destination as a contextual type.
2977
+ if (auto *assignExpr = getAsExpr<AssignExpr>(anchor))
2978
+ anchor = assignExpr->getSrc ();
2979
+
2980
+ if (auto *callExpr = getAsExpr<CallExpr>(anchor)) {
2981
+ if (!isa<TypeExpr>(callExpr->getDirectCallee ()))
2982
+ anchor = callExpr->getDirectCallee ();
2983
+ } else if (auto *applyExpr = getAsExpr<ApplyExpr>(anchor)) {
2984
+ anchor = applyExpr->getFn ();
2985
+ }
2986
+ return anchor;
2987
+ };
2988
+
2989
+ SmallPtrSet<SolutionDiff::OverloadDiff* , 4 > ambiguosOverloads;
2969
2990
2970
- // If there is an overload difference, let's see if there's a common callee
2971
- // locator for all of the fixes.
2972
- auto ambiguousOverload = llvm::find_if (solutionDiff.overloads ,
2973
- [&](const auto &overloadDiff) {
2974
- return llvm::all_of (aggregatedFixes, [&](const auto &aggregatedFix) {
2975
- auto *locator = aggregatedFix.first .first ;
2976
- auto anchor = locator->getAnchor ();
2977
- // Assignment failures are all about the source expression, because
2978
- // they treat destination as a contextual type.
2979
- if (auto *assignExpr = getAsExpr<AssignExpr>(anchor))
2980
- anchor = assignExpr->getSrc ();
2981
-
2982
- if (auto *callExpr = getAsExpr<CallExpr>(anchor)) {
2983
- if (!isa<TypeExpr>(callExpr->getDirectCallee ()))
2984
- anchor = callExpr->getDirectCallee ();
2985
- } else if (auto *applyExpr = getAsExpr<ApplyExpr>(anchor)) {
2986
- anchor = applyExpr->getFn ();
2987
- }
2988
-
2989
- return overloadDiff.locator ->getAnchor () == anchor;
2991
+ bool diagnosed = false ;
2992
+ for (const AggregatedEntry &aggregatedFix : aggregatedFixes) {
2993
+ auto ambiguousOverload =
2994
+ llvm::find_if (solutionDiff.overloads , [&](const auto &overloadDiff) {
2995
+ return overloadDiff.locator ->getAnchor () ==
2996
+ getAggregatedFixAnchor (aggregatedFix);
2990
2997
});
2991
- });
2992
2998
2993
- // If we didn't find an ambiguous overload, diagnose the common fixes.
2994
- if (ambiguousOverload == solutionDiff.overloads .end ()) {
2995
- bool diagnosed = false ;
2996
- for (auto fixes: aggregatedFixes) {
2999
+ if (ambiguousOverload == solutionDiff.overloads .end ()) {
2997
3000
// A common fix must appear in all solutions
2998
- auto &commonFixes = fixes.second ;
2999
- if (commonFixes.size () != solutions.size ()) continue ;
3001
+ auto &commonFixes = aggregatedFix.second ;
3002
+ if (commonFixes.size () != solutions.size ())
3003
+ continue ;
3000
3004
3001
3005
auto *firstFix = commonFixes.front ().second ;
3002
3006
diagnosed |= firstFix->diagnoseForAmbiguity (commonFixes);
3007
+ } else {
3008
+ ambiguosOverloads.insert (ambiguousOverload);
3003
3009
}
3004
- return diagnosed;
3005
3010
}
3006
3011
3007
- auto *commonCalleeLocator = ambiguousOverload->locator ;
3008
- auto *decl = ambiguousOverload->choices .front ().getDecl ();
3009
- assert (solverState);
3012
+ if (diagnosed)
3013
+ return true ;
3014
+
3015
+ // If all non-overloaded common fixes do not appear in all solutions
3016
+ // nor are diagnosed for ambiguity, let's try to fall back to common
3017
+ // anchor diagnostic.
3010
3018
3011
- bool diagnosed = true ;
3012
- {
3013
- DiagnosticTransaction transaction (getASTContext ().Diags );
3019
+ if (ambiguosOverloads.empty ())
3020
+ return false ;
3014
3021
3015
- auto commonAnchor = commonCalleeLocator->getAnchor ();
3016
- if (auto *callExpr = getAsExpr<CallExpr>(commonAnchor))
3017
- commonAnchor = callExpr->getDirectCallee ();
3018
- auto &DE = getASTContext ().Diags ;
3019
- const auto name = decl->getName ();
3020
-
3021
- // Emit an error message for the ambiguity.
3022
- if (aggregatedFixes.size () == 1 &&
3023
- aggregatedFixes.front ().first .first ->isForContextualType ()) {
3024
- auto anchor = aggregatedFixes.front ().first .first ->getAnchor ();
3025
- auto baseName = name.getBaseName ();
3026
- DE.diagnose (getLoc (commonAnchor), diag::no_candidates_match_result_type,
3027
- baseName.userFacingName (), getContextualType (anchor));
3028
- } else if (name.isOperator ()) {
3029
- auto *anchor = castToExpr (commonCalleeLocator->getAnchor ());
3030
-
3031
- // If operator is "applied" e.g. `1 + 2` there are tailored
3032
- // diagnostics in case of ambiguity, but if it's referenced
3033
- // e.g. `arr.sort(by: <)` it's better to produce generic error
3034
- // and a note per candidate.
3035
- if (auto *parentExpr = getParentExpr (anchor)) {
3036
- if (isa<ApplyExpr>(parentExpr)) {
3037
- diagnoseOperatorAmbiguity (*this , name.getBaseIdentifier (), solutions,
3038
- commonCalleeLocator);
3039
- return true ;
3022
+ diagnosed = true ;
3023
+ for (auto ambiguousOverload : ambiguosOverloads) {
3024
+ auto *commonCalleeLocator = ambiguousOverload->locator ;
3025
+ auto *decl = ambiguousOverload->choices .front ().getDecl ();
3026
+ assert (solverState);
3027
+
3028
+ {
3029
+ DiagnosticTransaction transaction (getASTContext ().Diags );
3030
+
3031
+ auto commonAnchor = commonCalleeLocator->getAnchor ();
3032
+ if (auto *callExpr = getAsExpr<CallExpr>(commonAnchor))
3033
+ commonAnchor = callExpr->getDirectCallee ();
3034
+ auto &DE = getASTContext ().Diags ;
3035
+ const auto name = decl->getName ();
3036
+
3037
+ // Emit an error message for the ambiguity.
3038
+ if (aggregatedFixes.size () == 1 &&
3039
+ aggregatedFixes.front ().first .first ->isForContextualType ()) {
3040
+ auto anchor = aggregatedFixes.front ().first .first ->getAnchor ();
3041
+ auto baseName = name.getBaseName ();
3042
+ DE.diagnose (getLoc (commonAnchor), diag::no_candidates_match_result_type,
3043
+ baseName.userFacingName (), getContextualType (anchor));
3044
+ } else if (name.isOperator ()) {
3045
+ auto *anchor = castToExpr (commonCalleeLocator->getAnchor ());
3046
+
3047
+ // If operator is "applied" e.g. `1 + 2` there are tailored
3048
+ // diagnostics in case of ambiguity, but if it's referenced
3049
+ // e.g. `arr.sort(by: <)` it's better to produce generic error
3050
+ // and a note per candidate.
3051
+ if (auto *parentExpr = getParentExpr (anchor)) {
3052
+ if (isa<ApplyExpr>(parentExpr)) {
3053
+ diagnoseOperatorAmbiguity (*this , name.getBaseIdentifier (),
3054
+ solutions, commonCalleeLocator);
3055
+ return true ;
3056
+ }
3040
3057
}
3041
- }
3042
3058
3043
- DE.diagnose (anchor->getLoc (), diag::no_overloads_match_exactly_in_call,
3044
- /* isApplication=*/ false , decl->getDescriptiveKind (),
3045
- name.isSpecial (), name.getBaseName ());
3046
- } else {
3047
- bool isApplication =
3048
- llvm::any_of (ArgumentInfos, [&](const auto &argInfo) {
3049
- return argInfo.first ->getAnchor () == commonAnchor;
3050
- });
3059
+ DE.diagnose (anchor->getLoc (), diag::no_overloads_match_exactly_in_call,
3060
+ /* isApplication=*/ false , decl->getDescriptiveKind (),
3061
+ name.isSpecial (), name.getBaseName ());
3062
+ } else {
3063
+ bool isApplication =
3064
+ llvm::any_of (ArgumentInfos, [&](const auto &argInfo) {
3065
+ return argInfo.first ->getAnchor () == commonAnchor;
3066
+ });
3051
3067
3052
- DE.diagnose (getLoc (commonAnchor),
3053
- diag::no_overloads_match_exactly_in_call, isApplication,
3054
- decl->getDescriptiveKind (), name.isSpecial (),
3055
- name.getBaseName ());
3056
- }
3068
+ DE.diagnose (getLoc (commonAnchor),
3069
+ diag::no_overloads_match_exactly_in_call, isApplication,
3070
+ decl->getDescriptiveKind (), name.isSpecial (),
3071
+ name.getBaseName ());
3072
+ }
3057
3073
3058
- // Produce candidate notes
3059
- SmallPtrSet<ValueDecl *, 4 > distinctChoices;
3060
- llvm::SmallSet<CanType, 4 > candidateTypes;
3061
- for (const auto &solution: solutions) {
3062
- auto overload = solution.getOverloadChoice (commonCalleeLocator);
3063
- auto *decl = overload.choice .getDecl ();
3064
- auto type = solution.simplifyType (overload.openedType );
3065
- // Skip if we've already produced a note for this overload
3066
- if (!distinctChoices.insert (decl).second )
3067
- continue ;
3074
+ // Produce candidate notes
3075
+ SmallPtrSet<ValueDecl *, 4 > distinctChoices;
3076
+ llvm::SmallSet<CanType, 4 > candidateTypes;
3077
+ for (const auto &solution : solutions) {
3078
+ auto overload = solution.getOverloadChoice (commonCalleeLocator);
3079
+ auto *decl = overload.choice .getDecl ();
3080
+ auto type = solution.simplifyType (overload.openedType );
3081
+ // Skip if we've already produced a note for this overload
3082
+ if (!distinctChoices.insert (decl).second )
3083
+ continue ;
3068
3084
3069
- if (solution.Fixes .size () == 1 ) {
3070
- diagnosed &=
3071
- solution.Fixes .front ()->diagnose (solution, /* asNote*/ true );
3072
- } else if (llvm::all_of (solution.Fixes ,
3073
- [&](ConstraintFix *fix) {
3074
- return fix->getLocator ()
3075
- ->findLast <LocatorPathElt::ApplyArgument>().hasValue ();
3076
- })) {
3077
- // All fixes have to do with arguments, so let's show the parameter lists.
3078
- auto *fn = type->getAs <AnyFunctionType>();
3079
- assert (fn);
3080
- DE.diagnose (decl->getLoc (),
3081
- diag::candidate_partial_match,
3082
- fn->getParamListAsString (fn->getParams ()));
3083
- } else {
3084
- // Emit a general "found candidate" note
3085
- if (decl->getLoc ().isInvalid ()) {
3086
- if (candidateTypes.insert (type->getCanonicalType ()).second )
3087
- DE.diagnose (getLoc (commonAnchor), diag::found_candidate_type, type);
3085
+ if (solution.Fixes .size () == 1 ) {
3086
+ diagnosed &=
3087
+ solution.Fixes .front ()->diagnose (solution, /* asNote*/ true );
3088
3088
} else {
3089
- DE.diagnose (decl->getLoc (), diag::found_candidate);
3089
+ auto emitGeneralFoundCandidate = [&]() {
3090
+ // Emit a general "found candidate" note
3091
+ if (decl->getLoc ().isInvalid ()) {
3092
+ if (candidateTypes.insert (type->getCanonicalType ()).second )
3093
+ DE.diagnose (getLoc (commonAnchor), diag::found_candidate_type,
3094
+ type);
3095
+ } else {
3096
+ DE.diagnose (decl->getLoc (), diag::found_candidate);
3097
+ }
3098
+ };
3099
+
3100
+ if (llvm::all_of (solution.Fixes , [](ConstraintFix *fix) {
3101
+ return fix->getLocator ()
3102
+ ->findLast <LocatorPathElt::ApplyArgument>()
3103
+ .hasValue ();
3104
+ })) {
3105
+
3106
+ // All fixes have to do with arguments, so let's show the parameter
3107
+ // lists.
3108
+ auto *fn = type->getAs <AnyFunctionType>();
3109
+ assert (fn);
3110
+
3111
+ if (fn->getNumParams () == 1 ) {
3112
+ // For single param functions if we have a re-label fix,
3113
+ // let's prefer note that instead of a general mismatch.
3114
+ auto relabelFix =
3115
+ llvm::find_if (solution.Fixes , [](ConstraintFix *fix) {
3116
+ return fix->getKind () == FixKind::RelabelArguments;
3117
+ });
3118
+ if (relabelFix != solution.Fixes .end ()) {
3119
+ (*relabelFix)->diagnose (solution, /* asNote*/ true );
3120
+ } else {
3121
+ emitGeneralFoundCandidate ();
3122
+ }
3123
+ continue ;
3124
+ }
3125
+
3126
+ DE.diagnose (decl->getLoc (), diag::candidate_partial_match,
3127
+ fn->getParamListAsString (fn->getParams ()));
3128
+
3129
+ } else {
3130
+ emitGeneralFoundCandidate ();
3131
+ }
3090
3132
}
3091
3133
}
3092
- }
3093
3134
3094
- // If not all of the fixes produced a note, we can't diagnose this.
3095
- if (!diagnosed)
3096
- transaction.abort ();
3135
+ // If not all of the fixes produced a note, we can't diagnose this.
3136
+ if (!diagnosed)
3137
+ transaction.abort ();
3138
+ }
3097
3139
}
3098
3140
3099
3141
return diagnosed;
0 commit comments