Skip to content

Commit 6dbdc74

Browse files
authored
Detect case where two alternatives are the same after widening ExprTypes (#18787)
In implicit or extension method search we might get two alternatives that are different but that point to the same singleton type after widening ExprTypes. In that case we can arbitrarily pick one of them instead of declaring an ambiguity. Fixes #18768
2 parents 252e78a + c456947 commit 6dbdc74

File tree

2 files changed

+57
-7
lines changed

2 files changed

+57
-7
lines changed

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

+13-7
Original file line numberDiff line numberDiff line change
@@ -1780,14 +1780,20 @@ trait Applications extends Compatibility {
17801780
def winsType2 = isAsSpecific(alt2, tp2, alt1, tp1)
17811781

17821782
overload.println(i"compare($alt1, $alt2)? $tp1 $tp2 $ownerScore $winsType1 $winsType2")
1783-
if (ownerScore == 1)
1784-
if (winsType1 || !winsType2) 1 else 0
1785-
else if (ownerScore == -1)
1786-
if (winsType2 || !winsType1) -1 else 0
1787-
else if (winsType1)
1788-
if (winsType2) 0 else 1
1783+
if winsType1 && winsType2
1784+
&& alt1.widenExpr.isStable && (alt1.widenExpr frozen_=:= alt2.widenExpr)
1785+
then
1786+
// alternatives are the same after following ExprTypes, pick one of them
1787+
// (prefer the one that is not a method, but that's arbitrary).
1788+
if alt1.widenExpr =:= alt2 then -1 else 1
1789+
else if ownerScore == 1 then
1790+
if winsType1 || !winsType2 then 1 else 0
1791+
else if ownerScore == -1 then
1792+
if winsType2 || !winsType1 then -1 else 0
1793+
else if winsType1 then
1794+
if winsType2 then 0 else 1
17891795
else
1790-
if (winsType2) -1 else 0
1796+
if winsType2 then -1 else 0
17911797
}
17921798

17931799
if alt1.symbol.is(ConstructorProxy) && !alt2.symbol.is(ConstructorProxy) then -1

tests/pos/i18768.scala

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package minimized:
2+
object Module:
3+
object Exportee:
4+
5+
opaque type Id = Long
6+
7+
def apply(): Id = ???
8+
9+
extension (e: Id)
10+
def updated: Id = ???
11+
12+
13+
object Client:
14+
export Module.*
15+
val x = Exportee().updated
16+
17+
package original:
18+
object Module:
19+
trait EntityDef:
20+
type Id
21+
type Record
22+
type Entity = (Id, Record)
23+
24+
extension (e: Entity)
25+
def updated: Entity = e
26+
27+
case class Exportee()
28+
object Exportee extends EntityDef:
29+
opaque type Id = Long
30+
type Record = Exportee
31+
32+
def apply(id: Long): Entity = (id, Exportee())
33+
34+
object Client:
35+
export Module.*
36+
val x = Exportee(1L).updated
37+
38+
39+
object ClientWorkingWithManualExport:
40+
export Module.{Exportee as _, *}
41+
type Exportee = Module.Exportee
42+
val Exportee = Module.Exportee
43+
44+
val x = Exportee(1L).updated

0 commit comments

Comments
 (0)