Skip to content

Commit

Permalink
Detect case where two alternatives are the same after widening ExprTy…
Browse files Browse the repository at this point in the history
…pes (#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
  • Loading branch information
odersky committed Oct 30, 2023
2 parents 252e78a + c456947 commit 6dbdc74
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 7 deletions.
20 changes: 13 additions & 7 deletions compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1780,14 +1780,20 @@ trait Applications extends Compatibility {
def winsType2 = isAsSpecific(alt2, tp2, alt1, tp1)

overload.println(i"compare($alt1, $alt2)? $tp1 $tp2 $ownerScore $winsType1 $winsType2")
if (ownerScore == 1)
if (winsType1 || !winsType2) 1 else 0
else if (ownerScore == -1)
if (winsType2 || !winsType1) -1 else 0
else if (winsType1)
if (winsType2) 0 else 1
if winsType1 && winsType2
&& alt1.widenExpr.isStable && (alt1.widenExpr frozen_=:= alt2.widenExpr)
then
// alternatives are the same after following ExprTypes, pick one of them
// (prefer the one that is not a method, but that's arbitrary).
if alt1.widenExpr =:= alt2 then -1 else 1
else if ownerScore == 1 then
if winsType1 || !winsType2 then 1 else 0
else if ownerScore == -1 then
if winsType2 || !winsType1 then -1 else 0
else if winsType1 then
if winsType2 then 0 else 1
else
if (winsType2) -1 else 0
if winsType2 then -1 else 0
}

if alt1.symbol.is(ConstructorProxy) && !alt2.symbol.is(ConstructorProxy) then -1
Expand Down
44 changes: 44 additions & 0 deletions tests/pos/i18768.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package minimized:
object Module:
object Exportee:

opaque type Id = Long

def apply(): Id = ???

extension (e: Id)
def updated: Id = ???


object Client:
export Module.*
val x = Exportee().updated

package original:
object Module:
trait EntityDef:
type Id
type Record
type Entity = (Id, Record)

extension (e: Entity)
def updated: Entity = e

case class Exportee()
object Exportee extends EntityDef:
opaque type Id = Long
type Record = Exportee

def apply(id: Long): Entity = (id, Exportee())

object Client:
export Module.*
val x = Exportee(1L).updated


object ClientWorkingWithManualExport:
export Module.{Exportee as _, *}
type Exportee = Module.Exportee
val Exportee = Module.Exportee

val x = Exportee(1L).updated

0 comments on commit 6dbdc74

Please sign in to comment.