Skip to content

Commit 1e93f22

Browse files
Fix healAmbiguous to compareAlternatives with disambiguate = true
On the final result, compared with all the ambiguous candidates we are trying to recover from. We should still use `disambiguate = false` when filtering the `pending` candidates for the purpose of warnings, as in the other cases. Before, we could heal an ambiguous SearchFailure with a candidate which was considered better only under the alternative given prioritization scheme, see #21045 for details.
1 parent 0b8e102 commit 1e93f22

File tree

1 file changed

+11
-17
lines changed

1 file changed

+11
-17
lines changed

compiler/src/dotty/tools/dotc/typer/Implicits.scala

+11-17
Original file line numberDiff line numberDiff line change
@@ -1419,15 +1419,7 @@ trait Implicits:
14191419
if diff < 0 then alt2
14201420
else if diff > 0 then alt1
14211421
else SearchFailure(new AmbiguousImplicits(alt1, alt2, pt, argument), span)
1422-
case fail: SearchFailure =>
1423-
fail.reason match
1424-
case ambi: AmbiguousImplicits =>
1425-
if compareAlternatives(ambi.alt1, alt2, disambiguate = true) < 0
1426-
&& compareAlternatives(ambi.alt2, alt2, disambiguate = true) < 0
1427-
then alt2
1428-
else alt1
1429-
case _ =>
1430-
alt2
1422+
case _: SearchFailure => alt2
14311423

14321424
/** Try to find a best matching implicit term among all the candidates in `pending`.
14331425
* @param pending The list of candidates that remain to be tested
@@ -1454,9 +1446,14 @@ trait Implicits:
14541446
* candidate that is strictly better than the failed candidate(s).
14551447
* If no such candidate is found, we propagate the ambiguity.
14561448
*/
1457-
def healAmbiguous(fail: SearchFailure, betterThanFailed: Candidate => Boolean) =
1458-
val newPending = remaining.filter(betterThanFailed)
1459-
rank(newPending, fail, Nil).recoverWith(_ => fail)
1449+
def healAmbiguous(fail: SearchFailure, ambiguousCands: List[RefAndLevel]) =
1450+
def betterThanAll(newCand: RefAndLevel, disambiguate: Boolean): Boolean =
1451+
ambiguousCands.forall(compareAlternatives(newCand, _, disambiguate) > 0)
1452+
1453+
val newPending = remaining.filter(betterThanAll(_, disambiguate = false))
1454+
rank(newPending, fail, Nil) match
1455+
case found: SearchSuccess if betterThanAll(found, disambiguate = true) => found
1456+
case _ => fail
14601457

14611458
negateIfNot(tryImplicit(cand, contextual)) match {
14621459
case fail: SearchFailure =>
@@ -1471,8 +1468,7 @@ trait Implicits:
14711468
else
14721469
// The ambiguity happened in a nested search: to recover we
14731470
// need a candidate better than `cand`
1474-
healAmbiguous(fail, newCand =>
1475-
compareAlternatives(newCand, cand) > 0)
1471+
healAmbiguous(fail, cand :: Nil)
14761472
else
14771473
// keep only warnings that don't involve the failed candidate reference
14781474
priorityChangeWarnings.filterInPlace: (critical, _) =>
@@ -1491,9 +1487,7 @@ trait Implicits:
14911487
// The ambiguity happened in the current search: to recover we
14921488
// need a candidate better than the two ambiguous alternatives.
14931489
val ambi = fail.reason.asInstanceOf[AmbiguousImplicits]
1494-
healAmbiguous(fail, newCand =>
1495-
compareAlternatives(newCand, ambi.alt1) > 0 &&
1496-
compareAlternatives(newCand, ambi.alt2) > 0)
1490+
healAmbiguous(fail, ambi.alt1 :: ambi.alt2 :: Nil)
14971491
}
14981492
}
14991493
case nil =>

0 commit comments

Comments
 (0)