@@ -3063,43 +3063,19 @@ diagnoseAmbiguityWithEphemeralPointers(ConstraintSystem &cs,
3063
3063
}
3064
3064
3065
3065
static bool diagnoseAmbiguity (
3066
- ConstraintSystem &cs,
3066
+ ConstraintSystem &cs, const SolutionDiff::OverloadDiff &ambiguity,
3067
3067
ArrayRef<std::pair<const Solution *, const ConstraintFix *>> aggregateFix,
3068
- SolutionDiff &solutionDiff, ArrayRef<Solution> solutions) {
3068
+ ArrayRef<Solution> solutions) {
3069
+ auto *locator = aggregateFix.front ().second ->getLocator ();
3069
3070
auto anchor = aggregateFix.front ().second ->getAnchor ();
3070
3071
3071
- // Assignment failures are all about the source expression, because
3072
- // they treat destination as a contextual type.
3073
- if (auto *assignExpr = getAsExpr<AssignExpr>(anchor))
3074
- anchor = assignExpr->getSrc ();
3075
-
3076
- if (auto *callExpr = getAsExpr<CallExpr>(anchor)) {
3077
- if (!isa<TypeExpr>(callExpr->getDirectCallee ()))
3078
- anchor = callExpr->getDirectCallee ();
3079
- } else if (auto *applyExpr = getAsExpr<ApplyExpr>(anchor)) {
3080
- anchor = applyExpr->getFn ();
3081
- }
3082
-
3083
- auto ambiguity =
3084
- llvm::find_if (solutionDiff.overloads ,
3085
- [&anchor](const SolutionDiff::OverloadDiff &diff) -> bool {
3086
- return diff.locator ->getAnchor () == anchor;
3087
- });
3088
-
3089
- if (ambiguity == solutionDiff.overloads .end ()) {
3090
- auto &fix = aggregateFix.front ();
3091
- return aggregateFix.size () == 1
3092
- ? fix.second ->diagnose (*fix.first , /* asNote=*/ false )
3093
- : fix.second ->diagnoseForAmbiguity (aggregateFix);
3094
- }
3095
-
3096
3072
auto &DE = cs.getASTContext ().Diags ;
3097
3073
3098
- auto *decl = ambiguity-> choices .front ().getDeclOrNull ();
3074
+ auto *decl = ambiguity. choices .front ().getDeclOrNull ();
3099
3075
if (!decl)
3100
3076
return false ;
3101
3077
3102
- auto *commonCalleeLocator = ambiguity-> locator ;
3078
+ auto *commonCalleeLocator = ambiguity. locator ;
3103
3079
3104
3080
bool diagnosed = true ;
3105
3081
{
@@ -3112,7 +3088,11 @@ static bool diagnoseAmbiguity(
3112
3088
const auto name = decl->getName ();
3113
3089
3114
3090
// Emit an error message for the ambiguity.
3115
- if (name.isOperator ()) {
3091
+ if (locator->isForContextualType ()) {
3092
+ auto baseName = name.getBaseName ();
3093
+ DE.diagnose (getLoc (commonAnchor), diag::no_candidates_match_result_type,
3094
+ baseName.userFacingName (), cs.getContextualType (anchor));
3095
+ } else if (name.isOperator ()) {
3116
3096
auto *anchor = castToExpr (commonCalleeLocator->getAnchor ());
3117
3097
3118
3098
// If operator is "applied" e.g. `1 + 2` there are tailored
@@ -3217,145 +3197,66 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
3217
3197
if (diagnoseAmbiguityWithEphemeralPointers (*this , solutions))
3218
3198
return true ;
3219
3199
3220
- // Collect aggregated fixes from all solutions
3221
- using LocatorAndKind = std::pair<ConstraintLocator *, FixKind>;
3222
- using SolutionAndFix = std::pair<const Solution *, const ConstraintFix *>;
3223
- llvm::SmallMapVector<LocatorAndKind, llvm::SmallVector<SolutionAndFix, 4 >, 4 >
3224
- aggregatedFixes;
3225
- for (const auto &solution : solutions) {
3226
- for (const auto *fix : solution.Fixes ) {
3227
- LocatorAndKind key (fix->getLocator (), fix->getKind ());
3228
- aggregatedFixes[key].emplace_back (&solution, fix);
3229
- }
3230
- }
3200
+ using Fix = std::pair<const Solution *, const ConstraintFix *>;
3231
3201
3232
- // If there is an overload difference, let's see if there's a common callee
3233
- // locator for all of the fixes.
3234
- auto ambiguousOverload = llvm::find_if (solutionDiff.overloads ,
3235
- [&](const auto &overloadDiff) {
3236
- return llvm::all_of (aggregatedFixes, [&](const auto &aggregatedFix) {
3237
- auto *locator = aggregatedFix.first .first ;
3238
- auto anchor = locator->getAnchor ();
3239
- // Assignment failures are all about the source expression, because
3240
- // they treat destination as a contextual type.
3241
- if (auto *assignExpr = getAsExpr<AssignExpr>(anchor))
3242
- anchor = assignExpr->getSrc ();
3243
-
3244
- if (auto *callExpr = getAsExpr<CallExpr>(anchor)) {
3245
- if (!isa<TypeExpr>(callExpr->getDirectCallee ()))
3246
- anchor = callExpr->getDirectCallee ();
3247
- } else if (auto *applyExpr = getAsExpr<ApplyExpr>(anchor)) {
3248
- anchor = applyExpr->getFn ();
3249
- }
3202
+ llvm::SmallSetVector<Fix, 4 > fixes;
3203
+ for (auto &solution : solutions) {
3204
+ for (auto *fix : solution.Fixes )
3205
+ fixes.insert ({&solution, fix});
3206
+ }
3250
3207
3251
- return overloadDiff.locator ->getAnchor () == anchor;
3252
- });
3253
- });
3208
+ llvm::MapVector<ConstraintLocator *, SmallVector<Fix, 4 >> fixesByCallee;
3254
3209
3255
- // If we didn't find an ambiguous overload, diagnose the common fixes.
3256
- if (ambiguousOverload == solutionDiff.overloads .end ()) {
3257
- bool diagnosed = false ;
3258
- for (auto fixes: aggregatedFixes) {
3259
- // A common fix must appear in all solutions
3260
- auto &commonFixes = fixes.second ;
3261
- if (commonFixes.size () != solutions.size ()) continue ;
3210
+ for (const auto &entry : fixes) {
3211
+ const auto &solution = *entry.first ;
3212
+ const auto *fix = entry.second ;
3213
+ auto *calleeLocator = solution.getCalleeLocator (fix->getLocator ());
3262
3214
3263
- auto *firstFix = commonFixes.front ().second ;
3264
- diagnosed |= firstFix->diagnoseForAmbiguity (commonFixes);
3265
- }
3266
- return diagnosed;
3215
+ fixesByCallee[calleeLocator].push_back ({&solution, fix});
3267
3216
}
3268
3217
3269
- auto *commonCalleeLocator = ambiguousOverload->locator ;
3270
- auto *decl = ambiguousOverload->choices .front ().getDecl ();
3271
- assert (solverState);
3218
+ bool diagnosed = false ;
3272
3219
3273
- bool diagnosed = true ;
3274
- {
3275
- DiagnosticTransaction transaction (getASTContext ().Diags );
3220
+ // All of the fixes which have been considered already.
3221
+ llvm::SmallSetVector<Fix, 4 > consideredFixes;
3276
3222
3277
- auto commonAnchor = commonCalleeLocator->getAnchor ();
3278
- if (auto *callExpr = getAsExpr<CallExpr>(commonAnchor))
3279
- commonAnchor = callExpr->getDirectCallee ();
3280
- auto &DE = getASTContext ().Diags ;
3281
- const auto name = decl->getName ();
3223
+ for (const auto &ambiguity : solutionDiff.overloads ) {
3224
+ auto fixes = fixesByCallee.find (ambiguity.locator );
3225
+ if (fixes == fixesByCallee.end ())
3226
+ continue ;
3282
3227
3283
- // Emit an error message for the ambiguity.
3284
- if (aggregatedFixes.size () == 1 &&
3285
- aggregatedFixes.front ().first .first ->isForContextualType ()) {
3286
- auto anchor = aggregatedFixes.front ().first .first ->getAnchor ();
3287
- auto baseName = name.getBaseName ();
3288
- DE.diagnose (getLoc (commonAnchor), diag::no_candidates_match_result_type,
3289
- baseName.userFacingName (), getContextualType (anchor));
3290
- } else if (name.isOperator ()) {
3291
- auto *anchor = castToExpr (commonCalleeLocator->getAnchor ());
3228
+ auto aggregate = fixes->second ;
3229
+ diagnosed |= ::diagnoseAmbiguity (*this , ambiguity, aggregate, solutions);
3292
3230
3293
- // If operator is "applied" e.g. `1 + 2` there are tailored
3294
- // diagnostics in case of ambiguity, but if it's referenced
3295
- // e.g. `arr.sort(by: <)` it's better to produce generic error
3296
- // and a note per candidate.
3297
- if (auto *parentExpr = getParentExpr (anchor)) {
3298
- if (isa<ApplyExpr>(parentExpr)) {
3299
- diagnoseOperatorAmbiguity (*this , name.getBaseIdentifier (), solutions,
3300
- commonCalleeLocator);
3301
- return true ;
3302
- }
3303
- }
3231
+ consideredFixes.insert (aggregate.begin (), aggregate.end ());
3232
+ }
3304
3233
3305
- DE.diagnose (anchor->getLoc (), diag::no_overloads_match_exactly_in_call,
3306
- /* isApplication=*/ false , decl->getDescriptiveKind (),
3307
- name.isSpecial (), name.getBaseName ());
3308
- } else {
3309
- bool isApplication =
3310
- llvm::any_of (ArgumentInfos, [&](const auto &argInfo) {
3311
- return argInfo.first ->getAnchor () == commonAnchor;
3312
- });
3234
+ // Remove all of the fixes which have been attached to ambiguous
3235
+ // overload choices.
3236
+ fixes.set_subtract (consideredFixes);
3313
3237
3314
- DE.diagnose (getLoc (commonAnchor),
3315
- diag::no_overloads_match_exactly_in_call, isApplication,
3316
- decl->getDescriptiveKind (), name.isSpecial (),
3317
- name.getBaseName ());
3318
- }
3238
+ llvm::MapVector<std::pair<FixKind, ConstraintLocator *>, SmallVector<Fix, 4 >>
3239
+ fixesByKind;
3319
3240
3320
- // Produce candidate notes
3321
- SmallPtrSet<ValueDecl *, 4 > distinctChoices;
3322
- llvm::SmallSet<CanType, 4 > candidateTypes;
3323
- for (const auto &solution: solutions) {
3324
- auto overload = solution.getOverloadChoice (commonCalleeLocator);
3325
- auto *decl = overload.choice .getDecl ();
3326
- auto type = solution.simplifyType (overload.openedType );
3327
- // Skip if we've already produced a note for this overload
3328
- if (!distinctChoices.insert (decl).second )
3329
- continue ;
3241
+ for (const auto &entry : fixes) {
3242
+ const auto *fix = entry.second ;
3243
+ fixesByKind[{fix->getKind (), fix->getLocator ()}].push_back (
3244
+ {entry.first , fix});
3245
+ }
3330
3246
3331
- if (solution.Fixes .size () == 1 ) {
3332
- diagnosed &=
3333
- solution.Fixes .front ()->diagnose (solution, /* asNote*/ true );
3334
- } else if (llvm::all_of (solution.Fixes ,
3335
- [&](ConstraintFix *fix) {
3336
- return fix->getLocator ()
3337
- ->findLast <LocatorPathElt::ApplyArgument>().hasValue ();
3338
- })) {
3339
- // All fixes have to do with arguments, so let's show the parameter lists.
3340
- auto *fn = type->getAs <AnyFunctionType>();
3341
- assert (fn);
3342
- DE.diagnose (decl->getLoc (),
3343
- diag::candidate_partial_match,
3344
- fn->getParamListAsString (fn->getParams ()));
3345
- } else {
3346
- // Emit a general "found candidate" note
3347
- if (decl->getLoc ().isInvalid ()) {
3348
- if (candidateTypes.insert (type->getCanonicalType ()).second )
3349
- DE.diagnose (getLoc (commonAnchor), diag::found_candidate_type, type);
3350
- } else {
3351
- DE.diagnose (decl->getLoc (), diag::found_candidate);
3352
- }
3353
- }
3247
+ // If leftover fix is contained in all of the solutions let's
3248
+ // diagnose it as ambiguity.
3249
+ for (const auto &entry : fixesByKind) {
3250
+ if (llvm::all_of (solutions, [&](const Solution &solution) -> bool {
3251
+ return llvm::any_of (
3252
+ solution.Fixes , [&](const ConstraintFix *fix) -> bool {
3253
+ return std::make_pair (fix->getKind (), fix->getLocator ()) ==
3254
+ entry.first ;
3255
+ });
3256
+ })) {
3257
+ auto &aggregate = entry.second ;
3258
+ diagnosed |= aggregate.front ().second ->diagnoseForAmbiguity (aggregate);
3354
3259
}
3355
-
3356
- // If not all of the fixes produced a note, we can't diagnose this.
3357
- if (!diagnosed)
3358
- transaction.abort ();
3359
3260
}
3360
3261
3361
3262
return diagnosed;
0 commit comments