Skip to content

Commit

Permalink
Improve overload resolution
Browse files Browse the repository at this point in the history
`resolveOverloaded1` starts with `narrowMostSpecific(candidates)`
which compares the alternatives based on the 1st argument list.
If more than one result if found, we can continue with the 2nd argument list.
But we do so with the original candidates, rather than with the result of `narrowMostSpecific`.
This can lead to choosing an alternative which is not the most specific,
by now disregarding the 1st argument list.

In i120053, the 1st pass correctly eliminated the 3rd `def ^^^`,
but could not resolve between the 1st two (having the same argument list).
The 2nd pass then disregarded this and restarted the comparison
based on the 2nd argument list alone, which incorrectly yielded the 3rd option.

The change is simply using the initial result of `narrowMostSpecific` in the recursive resolution based on subsequent argument lists.
I'm not sure however if the same changes should apply to the rest of the cases attempting further narrowing ?
  • Loading branch information
EugeneFlesselle committed Mar 31, 2024
1 parent c8c3bde commit 946401c
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 40 deletions.
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2184,11 +2184,11 @@ trait Applications extends Compatibility {
deepPt match
case pt @ FunProto(_, PolyProto(targs, resType)) =>
// try to narrow further with snd argument list and following type params
resolveMapped(candidates,
resolveMapped(found,
skipParamClause(pt.typedArgs().tpes, targs.tpes), resType)
case pt @ FunProto(_, resType: FunOrPolyProto) =>
// try to narrow further with snd argument list
resolveMapped(candidates,
resolveMapped(found,
skipParamClause(pt.typedArgs().tpes, Nil), resType)
case _ =>
// prefer alternatives that need no eta expansion
Expand Down
1 change: 1 addition & 0 deletions compiler/test/dotc/pos-test-pickling.blacklist
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,5 @@ i7445b.scala

# more aggresive reduce projection makes a difference
i15525.scala
i20053.scala

36 changes: 0 additions & 36 deletions tests/neg/i10901.check
Original file line number Diff line number Diff line change
@@ -1,39 +1,3 @@
-- [E008] Not Found Error: tests/neg/i10901.scala:45:38 ----------------------------------------------------------------
45 | val pos1: Point2D[Int,Double] = x º y // error
| ^^^
| value º is not a member of object BugExp4Point2D.IntT.
| An extension method was tried, but could not be fully constructed:
|
| º(x)
|
| failed with:
|
| Ambiguous overload. The overloaded alternatives of method º in object dsl with types
| [T1, T2]
| (x: BugExp4Point2D.ColumnType[T1])
| (y: BugExp4Point2D.ColumnType[T2])
| (implicit evidence$1: Numeric[T1], evidence$2: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2]
| [T1, T2]
| (x: T1)
| (y: BugExp4Point2D.ColumnType[T2])
| (implicit evidence$1: Numeric[T1], evidence$2: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2]
| both match arguments ((x : BugExp4Point2D.IntT.type))((y : BugExp4Point2D.DoubleT.type))
-- [E008] Not Found Error: tests/neg/i10901.scala:48:38 ----------------------------------------------------------------
48 | val pos4: Point2D[Int,Double] = x º 201.1 // error
| ^^^
|value º is not a member of object BugExp4Point2D.IntT.
|An extension method was tried, but could not be fully constructed:
|
| º(x)
|
| failed with:
|
| Ambiguous overload. The overloaded alternatives of method º in object dsl with types
| [T1, T2]
| (x: BugExp4Point2D.ColumnType[T1])
| (y: T2)(implicit evidence$1: Numeric[T1], evidence$2: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2]
| [T1, T2](x: T1)(y: T2)(implicit evidence$1: Numeric[T1], evidence$2: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2]
| both match arguments ((x : BugExp4Point2D.IntT.type))((201.1d : Double))
-- [E008] Not Found Error: tests/neg/i10901.scala:62:16 ----------------------------------------------------------------
62 | val y = "abc".foo // error
| ^^^^^^^^^
Expand Down
4 changes: 2 additions & 2 deletions tests/neg/i10901.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ object BugExp4Point2D {
val x = IntT
val y = DoubleT

val pos1: Point2D[Int,Double] = x º y // error
val pos1: Point2D[Int,Double] = x º y // ok
val pos2: Point2D[Int,Double] = 100 º 200.1 // ok
val pos3: Point2D[Int,Double] = 101 º y // ok
val pos4: Point2D[Int,Double] = x º 201.1 // error
val pos4: Point2D[Int,Double] = x º 201.1 // ok

}
}
Expand Down
79 changes: 79 additions & 0 deletions tests/pos/i20053.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@

trait Summon[R, T <: R]:
type Out
object Summon:
given [R, T <: R]: Summon[R, T] with
type Out = R

sealed class Modifier[+A, +P]
type ModifierAny = Modifier[Any, Any]
sealed trait ISCONST[T <: Boolean]
type CONST = ISCONST[true]

trait DFTypeAny
trait DFBits[W <: Int] extends DFTypeAny
trait DFVal[+T <: DFTypeAny, +M <: ModifierAny]
type DFValAny = DFVal[DFTypeAny, ModifierAny]
type DFValTP[+T <: DFTypeAny, +P] = DFVal[T, Modifier[Any, P]]
type DFConstOf[+T <: DFTypeAny] = DFVal[T, Modifier[Any, CONST]]

trait Candidate[R]:
type OutW <: Int
type OutP
object Candidate:
given [W <: Int, P, R <: DFValTP[DFBits[W], P]]: Candidate[R] with
type OutW = W
type OutP = P

extension [L <: DFValAny](lhs: L)(using icL: Candidate[L])
def ^^^[R](rhs: R)(using
icR: Candidate[R]
): DFValTP[DFBits[icL.OutW], icL.OutP | icR.OutP] = ???
def ^^^ : Unit = ???
extension [L](lhs: L)
def ^^^[RW <: Int, RP](
rhs: DFValTP[DFBits[RW], RP]
)(using es: Summon[L, lhs.type])(using
c: Candidate[L]
)(using check: c.OutW =:= c.OutW): DFValTP[DFBits[c.OutW], c.OutP | RP] = ???

val x: DFConstOf[DFBits[8]] = ???
val zzz = x ^^^ x ^^^ x


object Minimized:
trait DFVal[+T <: Int, +P]

trait Summon[R, T <: R]
given [R, T <: R]: Summon[R, T] with {}

trait Candidate[R]:
type OutW <: Int
type OutP
given [W <: Int, P, R <: DFVal[W, P]]: Candidate[R] with
type OutW = W
type OutP = P

extension [L <: DFVal[Int, Any]](lhs: L)(using icL: Candidate[L])
def ^^^[R](rhs: R)
(using icR: Candidate[R])
: DFVal[icL.OutW, icL.OutP | icR.OutP] = ???
def ^^^ : Unit = ???

extension [L](lhs: L)
def ^^^[RW <: Int, RP](rhs: DFVal[RW, RP])
(using es: Summon[L, lhs.type])
(using c: Candidate[L])
(using check: c.OutW =:= c.OutW)
: DFVal[c.OutW, c.OutP | RP] = ???

val x: DFVal[8, true] = ???
val z1 = x ^^^ x // Ok
val z2 = z1 ^^^ x // Ok
val zzz = x ^^^ x ^^^ x // Error before changes

/* Before the changes, when `def ^^^ : Unit = ???` is present,
* all of z1, z2, zzz attempt to use the last `def ^^^`,
* despite it being less specific than the 1st one.
*/
end Minimized

0 comments on commit 946401c

Please sign in to comment.