Skip to content

Commit b4f3a7b

Browse files
Backport "Priority warning fix alternative" to 3.5.0 (#20953)
Backports #20487 to 3.5.0-RC3
2 parents edc8cbc + 1d993a7 commit b4f3a7b

File tree

5 files changed

+46
-13
lines changed

5 files changed

+46
-13
lines changed

Diff for: compiler/src/dotty/tools/dotc/typer/Implicits.scala

+33-7
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,12 @@ object Implicits:
419419
sealed abstract class SearchResult extends Showable {
420420
def tree: Tree
421421
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+
422428
def recoverWith(other: SearchFailure => SearchResult): SearchResult = this match {
423429
case _: SearchSuccess => this
424430
case fail: SearchFailure => other(fail)
@@ -434,13 +440,17 @@ object Implicits:
434440
* @param tstate The typer state to be committed if this alternative is chosen
435441
*/
436442
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
438445

439446
/** A failed search */
440447
case class SearchFailure(tree: Tree) extends SearchResult {
441448
require(tree.tpe.isInstanceOf[SearchFailureType], s"unexpected type for ${tree}")
442449
final def isAmbiguous: Boolean = tree.tpe.isInstanceOf[AmbiguousImplicits | TooUnspecific]
443450
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
444454
}
445455

446456
object SearchFailure {
@@ -1290,6 +1300,12 @@ trait Implicits:
12901300
/** Search a list of eligible implicit references */
12911301
private def searchImplicit(eligible: List[Candidate], contextual: Boolean): SearchResult =
12921302

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+
12931309
/** Compare `alt1` with `alt2` to determine which one should be chosen.
12941310
*
12951311
* @return a number > 0 if `alt1` is preferred over `alt2`
@@ -1306,6 +1322,8 @@ trait Implicits:
13061322
*/
13071323
def compareAlternatives(alt1: RefAndLevel, alt2: RefAndLevel): Int =
13081324
def comp(using Context) = explore(compare(alt1.ref, alt2.ref, preferGeneral = true))
1325+
def warn(msg: Message) =
1326+
priorityChangeWarnings += ((alt1.ref, alt2.ref, msg))
13091327
if alt1.ref eq alt2.ref then 0
13101328
else if alt1.level != alt2.level then alt1.level - alt2.level
13111329
else
@@ -1319,16 +1337,16 @@ trait Implicits:
13191337
case 1 => "the first alternative"
13201338
case _ => "none - it's ambiguous"
13211339
if sv.stable == SourceVersion.`3.5` then
1322-
report.warning(
1340+
warn(
13231341
em"""Given search preference for $pt between alternatives ${alt1.ref} and ${alt2.ref} will change
13241342
|Current choice : ${choice(prev)}
1325-
|New choice from Scala 3.6: ${choice(cmp)}""", srcPos)
1343+
|New choice from Scala 3.6: ${choice(cmp)}""")
13261344
prev
13271345
else
1328-
report.warning(
1346+
warn(
13291347
em"""Change in given search preference for $pt between alternatives ${alt1.ref} and ${alt2.ref}
13301348
|Previous choice : ${choice(prev)}
1331-
|New choice from Scala 3.6: ${choice(cmp)}""", srcPos)
1349+
|New choice from Scala 3.6: ${choice(cmp)}""")
13321350
cmp
13331351
else cmp
13341352
else cmp
@@ -1423,7 +1441,11 @@ trait Implicits:
14231441
// need a candidate better than `cand`
14241442
healAmbiguous(fail, newCand =>
14251443
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)
14271449
case best: SearchSuccess =>
14281450
if (ctx.mode.is(Mode.ImplicitExploration) || isCoherent)
14291451
best
@@ -1578,7 +1600,11 @@ trait Implicits:
15781600
validateOrdering(ord)
15791601
throw ex
15801602

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
15821608
end searchImplicit
15831609

15841610
def isUnderSpecifiedArgument(tp: Type): Boolean =

Diff for: tests/pos/i20484.scala

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
given Int = ???
2+
given Char = ???
3+
val a = summon[Int]

Diff for: tests/semanticdb/expect/InventedNames.expect.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ given [T/*<-givens::InventedNames$package.given_Z_T#[T]*/]: Z/*->givens::Z#*/[T/
3232

3333
val a/*<-givens::InventedNames$package.a.*/ = intValue/*->givens::InventedNames$package.intValue.*/
3434
val b/*<-givens::InventedNames$package.b.*/ = given_String/*->givens::InventedNames$package.given_String.*/
35-
//val c = given_Double
35+
val c/*<-givens::InventedNames$package.c.*/ = given_Double/*->givens::InventedNames$package.given_Double().*/
3636
val d/*<-givens::InventedNames$package.d.*/ = given_List_T/*->givens::InventedNames$package.given_List_T().*/[Int/*->scala::Int#*/]
3737
val e/*<-givens::InventedNames$package.e.*/ = given_Char/*->givens::InventedNames$package.given_Char.*/
3838
val f/*<-givens::InventedNames$package.f.*/ = given_Float/*->givens::InventedNames$package.given_Float.*/

Diff for: tests/semanticdb/expect/InventedNames.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ given [T]: Z[T] with
3232

3333
val a = intValue
3434
val b = given_String
35-
//val c = given_Double
35+
val c = given_Double
3636
val d = given_List_T[Int]
3737
val e = given_Char
3838
val f = given_Float

Diff for: tests/semanticdb/metac.expect

+8-4
Original file line numberDiff line numberDiff line change
@@ -2093,15 +2093,16 @@ Schema => SemanticDB v4
20932093
Uri => InventedNames.scala
20942094
Text => empty
20952095
Language => Scala
2096-
Symbols => 44 entries
2097-
Occurrences => 64 entries
2098-
Synthetics => 2 entries
2096+
Symbols => 45 entries
2097+
Occurrences => 66 entries
2098+
Synthetics => 3 entries
20992099

21002100
Symbols:
2101-
givens/InventedNames$package. => final package object givens extends Object { self: givens.type => +23 decls }
2101+
givens/InventedNames$package. => final package object givens extends Object { self: givens.type => +24 decls }
21022102
givens/InventedNames$package.`* *`. => final implicit lazy val given method * * Long
21032103
givens/InventedNames$package.a. => val method a Int
21042104
givens/InventedNames$package.b. => val method b String
2105+
givens/InventedNames$package.c. => val method c Double
21052106
givens/InventedNames$package.d. => val method d List[Int]
21062107
givens/InventedNames$package.e. => val method e Char
21072108
givens/InventedNames$package.f. => val method f Float
@@ -2192,6 +2193,8 @@ Occurrences:
21922193
[32:8..32:16): intValue -> givens/InventedNames$package.intValue.
21932194
[33:4..33:5): b <- givens/InventedNames$package.b.
21942195
[33:8..33:20): given_String -> givens/InventedNames$package.given_String.
2196+
[34:4..34:5): c <- givens/InventedNames$package.c.
2197+
[34:8..34:20): given_Double -> givens/InventedNames$package.given_Double().
21952198
[35:4..35:5): d <- givens/InventedNames$package.d.
21962199
[35:8..35:20): given_List_T -> givens/InventedNames$package.given_List_T().
21972200
[35:21..35:24): Int -> scala/Int#
@@ -2211,6 +2214,7 @@ Occurrences:
22112214

22122215
Synthetics:
22132216
[24:0..24:0): => *(x$1)
2217+
[34:8..34:20):given_Double => *(intValue)
22142218
[40:8..40:15):given_Y => *(given_X)
22152219

22162220
expect/Issue1749.scala

0 commit comments

Comments
 (0)