@@ -1310,6 +1310,10 @@ trait Implicits:
1310
1310
// message if one of the critical candidates is part of the result of the implicit search.
1311
1311
val priorityChangeWarnings = mutable.ListBuffer [(/* critical:*/ List [TermRef ], Message )]()
1312
1312
1313
+ val sv = Feature .sourceVersion
1314
+ val isLastOldVersion = sv.stable == SourceVersion .`3.6`
1315
+ val isWarnPriorityChangeVersion = isLastOldVersion || sv == SourceVersion .`3.7-migration`
1316
+
1313
1317
/** Compare `alt1` with `alt2` to determine which one should be chosen.
1314
1318
*
1315
1319
* @return a number > 0 if `alt1` is preferred over `alt2`
@@ -1333,10 +1337,7 @@ trait Implicits:
1333
1337
else if alt1.level != alt2.level then alt1.level - alt2.level
1334
1338
else
1335
1339
val cmp = comp(using searchContext())
1336
- val sv = Feature .sourceVersion
1337
- val isLastOldVersion = sv.stable == SourceVersion .`3.6`
1338
- val isMigratingVersion = sv == SourceVersion .`3.7-migration`
1339
- if isLastOldVersion || isMigratingVersion then
1340
+ if isWarnPriorityChangeVersion then
1340
1341
val prev = comp(using searchContext().addMode(Mode .OldImplicitResolution ))
1341
1342
if disambiguate && cmp != prev then
1342
1343
implicits.println(i " PRIORITY CHANGE ${alt1.ref}, ${alt2.ref}" )
@@ -1419,15 +1420,7 @@ trait Implicits:
1419
1420
if diff < 0 then alt2
1420
1421
else if diff > 0 then alt1
1421
1422
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
1423
+ case _ : SearchFailure => alt2
1431
1424
1432
1425
/** Try to find a best matching implicit term among all the candidates in `pending`.
1433
1426
* @param pending The list of candidates that remain to be tested
@@ -1451,12 +1444,27 @@ trait Implicits:
1451
1444
pending match {
1452
1445
case cand :: remaining =>
1453
1446
/** To recover from an ambiguous implicit failure, we need to find a pending
1454
- * candidate that is strictly better than the failed candidate(s).
1447
+ * candidate that is strictly better than the failed `ambiguous` candidate(s).
1455
1448
* If no such candidate is found, we propagate the ambiguity.
1456
1449
*/
1457
- def healAmbiguous (fail : SearchFailure , betterThanFailed : Candidate => Boolean ) =
1458
- val newPending = remaining.filter(betterThanFailed)
1459
- rank(newPending, fail, Nil ).recoverWith(_ => fail)
1450
+ def healAmbiguous (fail : SearchFailure , ambiguous : List [RefAndLevel ]) =
1451
+ def betterThanAmbiguous (newCand : RefAndLevel , disambiguate : Boolean ): Boolean =
1452
+ ambiguous.forall(compareAlternatives(newCand, _, disambiguate) > 0 )
1453
+
1454
+ inline def betterByCurrentScheme (newCand : RefAndLevel ): Boolean =
1455
+ if isWarnPriorityChangeVersion then
1456
+ // newCand may have only been kept in pending because it was better in the other priotization scheme.
1457
+ // If that candidate produces a SearchSuccess, disambiguate will return it as the found SearchResult.
1458
+ // We must now recheck it was really better than the ambigous candidates we are recovering from,
1459
+ // under the rules of the current scheme, which are applied when disambiguate = true.
1460
+ betterThanAmbiguous(newCand, disambiguate = true )
1461
+ else true
1462
+
1463
+ val newPending = remaining.filter(betterThanAmbiguous(_, disambiguate = false ))
1464
+ rank(newPending, fail, Nil ) match
1465
+ case found : SearchSuccess if betterByCurrentScheme(found) => found
1466
+ case _ => fail
1467
+ end healAmbiguous
1460
1468
1461
1469
negateIfNot(tryImplicit(cand, contextual)) match {
1462
1470
case fail : SearchFailure =>
@@ -1471,8 +1479,7 @@ trait Implicits:
1471
1479
else
1472
1480
// The ambiguity happened in a nested search: to recover we
1473
1481
// need a candidate better than `cand`
1474
- healAmbiguous(fail, newCand =>
1475
- compareAlternatives(newCand, cand) > 0 )
1482
+ healAmbiguous(fail, cand :: Nil )
1476
1483
else
1477
1484
// keep only warnings that don't involve the failed candidate reference
1478
1485
priorityChangeWarnings.filterInPlace: (critical, _) =>
@@ -1491,9 +1498,7 @@ trait Implicits:
1491
1498
// The ambiguity happened in the current search: to recover we
1492
1499
// need a candidate better than the two ambiguous alternatives.
1493
1500
val ambi = fail.reason.asInstanceOf [AmbiguousImplicits ]
1494
- healAmbiguous(fail, newCand =>
1495
- compareAlternatives(newCand, ambi.alt1) > 0 &&
1496
- compareAlternatives(newCand, ambi.alt2) > 0 )
1501
+ healAmbiguous(fail, ambi.alt1 :: ambi.alt2 :: Nil )
1497
1502
}
1498
1503
}
1499
1504
case nil =>
0 commit comments