@@ -419,6 +419,12 @@ object Implicits:
419
419
sealed abstract class SearchResult extends Showable {
420
420
def tree : Tree
421
421
def toText (printer : Printer ): Text = printer.toText(this )
422
+
423
+ /** The references that were found, there can be two of them in the case
424
+ * of an AmbiguousImplicits failure
425
+ */
426
+ def found : List [TermRef ]
427
+
422
428
def recoverWith (other : SearchFailure => SearchResult ): SearchResult = this match {
423
429
case _ : SearchSuccess => this
424
430
case fail : SearchFailure => other(fail)
@@ -434,13 +440,17 @@ object Implicits:
434
440
* @param tstate The typer state to be committed if this alternative is chosen
435
441
*/
436
442
case class SearchSuccess (tree : Tree , ref : TermRef , level : Int , isExtension : Boolean = false )(val tstate : TyperState , val gstate : GadtConstraint )
437
- extends SearchResult with RefAndLevel with Showable
443
+ extends SearchResult with RefAndLevel with Showable :
444
+ final def found = ref :: Nil
438
445
439
446
/** A failed search */
440
447
case class SearchFailure (tree : Tree ) extends SearchResult {
441
448
require(tree.tpe.isInstanceOf [SearchFailureType ], s " unexpected type for ${tree}" )
442
449
final def isAmbiguous : Boolean = tree.tpe.isInstanceOf [AmbiguousImplicits | TooUnspecific ]
443
450
final def reason : SearchFailureType = tree.tpe.asInstanceOf [SearchFailureType ]
451
+ final def found = tree.tpe match
452
+ case tpe : AmbiguousImplicits => tpe.alt1.ref :: tpe.alt2.ref :: Nil
453
+ case _ => Nil
444
454
}
445
455
446
456
object SearchFailure {
@@ -1290,6 +1300,12 @@ trait Implicits:
1290
1300
/** Search a list of eligible implicit references */
1291
1301
private def searchImplicit (eligible : List [Candidate ], contextual : Boolean ): SearchResult =
1292
1302
1303
+ // A map that associates a priority change warning (between -source 3.4 and 3.6)
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 )]()
1308
+
1293
1309
/** Compare `alt1` with `alt2` to determine which one should be chosen.
1294
1310
*
1295
1311
* @return a number > 0 if `alt1` is preferred over `alt2`
@@ -1306,6 +1322,8 @@ trait Implicits:
1306
1322
*/
1307
1323
def compareAlternatives (alt1 : RefAndLevel , alt2 : RefAndLevel ): Int =
1308
1324
def comp (using Context ) = explore(compare(alt1.ref, alt2.ref, preferGeneral = true ))
1325
+ def warn (msg : Message ) =
1326
+ priorityChangeWarnings += ((alt1.ref, alt2.ref, msg))
1309
1327
if alt1.ref eq alt2.ref then 0
1310
1328
else if alt1.level != alt2.level then alt1.level - alt2.level
1311
1329
else
@@ -1319,16 +1337,16 @@ trait Implicits:
1319
1337
case 1 => " the first alternative"
1320
1338
case _ => " none - it's ambiguous"
1321
1339
if sv.stable == SourceVersion .`3.5` then
1322
- report.warning (
1340
+ warn (
1323
1341
em """ Given search preference for $pt between alternatives ${alt1.ref} and ${alt2.ref} will change
1324
1342
|Current choice : ${choice(prev)}
1325
- |New choice from Scala 3.6: ${choice(cmp)}""" , srcPos )
1343
+ |New choice from Scala 3.6: ${choice(cmp)}""" )
1326
1344
prev
1327
1345
else
1328
- report.warning (
1346
+ warn (
1329
1347
em """ Change in given search preference for $pt between alternatives ${alt1.ref} and ${alt2.ref}
1330
1348
|Previous choice : ${choice(prev)}
1331
- |New choice from Scala 3.6: ${choice(cmp)}""" , srcPos )
1349
+ |New choice from Scala 3.6: ${choice(cmp)}""" )
1332
1350
cmp
1333
1351
else cmp
1334
1352
else cmp
@@ -1423,7 +1441,11 @@ trait Implicits:
1423
1441
// need a candidate better than `cand`
1424
1442
healAmbiguous(fail, newCand =>
1425
1443
compareAlternatives(newCand, cand) > 0 )
1426
- else rank(remaining, found, fail :: rfailures)
1444
+ else
1445
+ // keep only warnings that don't involve the failed candidate reference
1446
+ priorityChangeWarnings.filterInPlace: (ref1, ref2, _) =>
1447
+ ref1 != cand.ref && ref2 != cand.ref
1448
+ rank(remaining, found, fail :: rfailures)
1427
1449
case best : SearchSuccess =>
1428
1450
if (ctx.mode.is(Mode .ImplicitExploration ) || isCoherent)
1429
1451
best
@@ -1578,7 +1600,11 @@ trait Implicits:
1578
1600
validateOrdering(ord)
1579
1601
throw ex
1580
1602
1581
- rank(sort(eligible), NoMatchingImplicitsFailure , Nil )
1603
+ 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
1606
+ report.warning(msg, srcPos)
1607
+ result
1582
1608
end searchImplicit
1583
1609
1584
1610
def isUnderSpecifiedArgument (tp : Type ): Boolean =
0 commit comments