Skip to content

Commit 3354c65

Browse files
committed
Improve specificity comparisons for extension methods
Comparing the wrapper objects for specificity is not enough; we should also look at the resolved methods themselves.
1 parent a2ad418 commit 3354c65

File tree

2 files changed

+34
-7
lines changed

2 files changed

+34
-7
lines changed

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

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,16 +1455,29 @@ trait Implicits { self: Typer =>
14551455
* - If alt2 is preferred over alt1, pick alt2, otherwise return an
14561456
* ambiguous implicits error.
14571457
*/
1458-
def disambiguate(alt1: SearchResult, alt2: SearchSuccess) = alt1 match {
1458+
def disambiguate(alt1: SearchResult, alt2: SearchSuccess) = alt1 match
14591459
case alt1: SearchSuccess =>
1460-
val diff = compareCandidate(alt1, alt2.ref, alt2.level)
1460+
var diff = compareCandidate(alt1, alt2.ref, alt2.level)
14611461
assert(diff <= 0) // diff > 0 candidates should already have been eliminated in `rank`
1462-
if (diff < 0) alt2
1463-
else
1464-
// numericValueTypeBreak(alt1, alt2) recoverWith
1465-
SearchFailure(new AmbiguousImplicits(alt1, alt2, pt, argument))
1462+
1463+
if diff == 0 then
1464+
// Fall back: if both results are extension method applications,
1465+
// compare the extension methods instead of their wrappers.
1466+
object extMethodApply with
1467+
def unapply(t: Tree): Option[Type] = t match
1468+
case t: Applications.ExtMethodApply => Some(methPart(stripApply(t.app)).tpe)
1469+
case _ => None
1470+
end extMethodApply
1471+
1472+
(alt1.tree, alt2.tree) match
1473+
case (extMethodApply(ref1: TermRef), extMethodApply(ref2: TermRef)) =>
1474+
diff = compare(ref1, ref2)
1475+
case _ =>
1476+
1477+
if diff < 0 then alt2
1478+
else if diff > 0 then alt1
1479+
else SearchFailure(new AmbiguousImplicits(alt1, alt2, pt, argument))
14661480
case _: SearchFailure => alt2
1467-
}
14681481

14691482
/** Faced with an ambiguous implicits failure `fail`, try to find another
14701483
* alternative among `pending` that is strictly better than both ambiguous

tests/run/extension-specificity.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class A
2+
class B extends A
3+
4+
given a: extension (x: A) with
5+
def foo: Int = 1
6+
7+
given b: extension (x: B) with
8+
def foo: Int = 2
9+
10+
@main def Test =
11+
val a = A()
12+
assert(a.foo == 1)
13+
val b = B()
14+
assert(b.foo == 2)

0 commit comments

Comments
 (0)