@@ -1302,9 +1302,11 @@ trait Implicits:
1302
1302
1303
1303
// A map that associates a priority change warning (between -source 3.4 and 3.6)
1304
1304
// with the candidate refs mentioned in the warning. We report the associated
1305
- // message if both candidates qualify in tryImplicit and at least one of the candidates
1306
- // is part of the result of the implicit search.
1307
- val priorityChangeWarnings = mutable.ListBuffer [(TermRef , TermRef , Message )]()
1305
+ // message if one of the critical candidates is part of the result of the implicit search.
1306
+ val priorityChangeWarnings = mutable.ListBuffer [(/* critical:*/ List [TermRef ], Message )]()
1307
+
1308
+ def isWarnPriorityChangeVersion (sv : SourceVersion ): Boolean =
1309
+ sv.stable == SourceVersion .`3.5` || sv == SourceVersion .`3.6-migration`
1308
1310
1309
1311
/** Compare `alt1` with `alt2` to determine which one should be chosen.
1310
1312
*
@@ -1319,19 +1321,24 @@ trait Implicits:
1319
1321
* return new result with preferGeneral = true
1320
1322
* 3.6 and higher: compare with preferGeneral = true
1321
1323
*
1324
+ * @param disambiguate The call is used to disambiguate two successes, not for ranking.
1325
+ * When ranking, we are always filtering out either > 0 or <= 0 results.
1326
+ * In each case a priority change from 0 to -1 or vice versa makes no difference.
1322
1327
*/
1323
- def compareAlternatives (alt1 : RefAndLevel , alt2 : RefAndLevel ): Int =
1328
+ def compareAlternatives (alt1 : RefAndLevel , alt2 : RefAndLevel , disambiguate : Boolean = false ): Int =
1324
1329
def comp (using Context ) = explore(compare(alt1.ref, alt2.ref, preferGeneral = true ))
1325
- def warn (msg : Message ) =
1326
- priorityChangeWarnings += ((alt1.ref, alt2.ref, msg))
1327
1330
if alt1.ref eq alt2.ref then 0
1328
1331
else if alt1.level != alt2.level then alt1.level - alt2.level
1329
1332
else
1330
1333
var cmp = comp(using searchContext())
1331
1334
val sv = Feature .sourceVersion
1332
- if sv.stable == SourceVersion .`3.5` || sv == SourceVersion .`3.6-migration` then
1335
+ if isWarnPriorityChangeVersion(sv) then
1333
1336
val prev = comp(using searchContext().addMode(Mode .OldImplicitResolution ))
1334
- if cmp != prev then
1337
+ if disambiguate && cmp != prev then
1338
+ def warn (msg : Message ) =
1339
+ val critical = alt1.ref :: alt2.ref :: Nil
1340
+ priorityChangeWarnings += ((critical, msg))
1341
+ implicits.println(i " PRIORITY CHANGE ${alt1.ref}, ${alt2.ref}, $disambiguate" )
1335
1342
def choice (c : Int ) = c match
1336
1343
case - 1 => " the second alternative"
1337
1344
case 1 => " the first alternative"
@@ -1348,7 +1355,9 @@ trait Implicits:
1348
1355
|Previous choice : ${choice(prev)}
1349
1356
|New choice from Scala 3.6: ${choice(cmp)}""" )
1350
1357
cmp
1351
- else cmp
1358
+ else cmp max prev
1359
+ // When ranking, we keep the better of cmp and prev, which ends up retaining a candidate
1360
+ // if it is retained in either version.
1352
1361
else cmp
1353
1362
end compareAlternatives
1354
1363
@@ -1358,8 +1367,9 @@ trait Implicits:
1358
1367
*/
1359
1368
def disambiguate (alt1 : SearchResult , alt2 : SearchSuccess ) = alt1 match
1360
1369
case alt1 : SearchSuccess =>
1361
- var diff = compareAlternatives(alt1, alt2)
1362
- assert(diff <= 0 ) // diff > 0 candidates should already have been eliminated in `rank`
1370
+ var diff = compareAlternatives(alt1, alt2, disambiguate = true )
1371
+ assert(diff <= 0 || isWarnPriorityChangeVersion(Feature .sourceVersion))
1372
+ // diff > 0 candidates should already have been eliminated in `rank`
1363
1373
if diff == 0 && alt1.ref =:= alt2.ref then
1364
1374
diff = 1 // See i12951 for a test where this happens
1365
1375
else if diff == 0 && alt2.isExtension then
@@ -1443,8 +1453,8 @@ trait Implicits:
1443
1453
compareAlternatives(newCand, cand) > 0 )
1444
1454
else
1445
1455
// keep only warnings that don't involve the failed candidate reference
1446
- priorityChangeWarnings.filterInPlace: (ref1, ref2 , _) =>
1447
- ref1 != cand.ref && ref2 != cand.ref
1456
+ priorityChangeWarnings.filterInPlace: (critical , _) =>
1457
+ ! critical.contains( cand.ref)
1448
1458
rank(remaining, found, fail :: rfailures)
1449
1459
case best : SearchSuccess =>
1450
1460
if (ctx.mode.is(Mode .ImplicitExploration ) || isCoherent)
@@ -1453,8 +1463,7 @@ trait Implicits:
1453
1463
case retained : SearchSuccess =>
1454
1464
val newPending =
1455
1465
if (retained eq found) || remaining.isEmpty then remaining
1456
- else remaining.filterConserve(cand =>
1457
- compareAlternatives(retained, cand) <= 0 )
1466
+ else remaining.filterConserve(newCand => compareAlternatives(newCand, retained) >= 0 )
1458
1467
rank(newPending, retained, rfailures)
1459
1468
case fail : SearchFailure =>
1460
1469
// The ambiguity happened in the current search: to recover we
@@ -1601,8 +1610,8 @@ trait Implicits:
1601
1610
throw ex
1602
1611
1603
1612
val result = rank(sort(eligible), NoMatchingImplicitsFailure , Nil )
1604
- for (ref1, ref2 , msg) <- priorityChangeWarnings do
1605
- if result.found.exists(ref => ref == ref1 || ref == ref2 ) then
1613
+ for (critical , msg) <- priorityChangeWarnings do
1614
+ if result.found.exists(critical.contains(_) ) then
1606
1615
report.warning(msg, srcPos)
1607
1616
result
1608
1617
end searchImplicit
0 commit comments