scala/scala3

Compiler resolve wrong implicit method when "-source 3.0-migration" is enabled

Closed this issue · 2 comments

Compiler version

Reproduced on 3.0.0 and 3.4.2

Suggest all versions in-between are affected.

Minimized code

object Bug {

  case class Wrapper[+E, +A](either: Either[E, A]) {
    def withFilter[EE >: E](p: A => Boolean)(implicit noE: A => EE): Wrapper[EE, A] = Wrapper(either match {
      case Right(a) => if (p(a)) Right(a) else Left(noE(a))
      case Left(e) => Left(e)
    })
  }

  def main(args: Array[String]): Unit = {

    val w1: Wrapper[String, Int] = Wrapper(Right(3))

    import scala.language.implicitConversions
    implicit def noE(i: Int): String = "No such element"

    val w4 = w1.withFilter(_ == 5)

    println((w4.either, Left(noE(1))))
    assert(w4.either == Left("No such element"))
  }
}
scala -source 3.0-migration Bug.scala

Output

(Left(3),Left(No such element))
Exception in thread "main" java.lang.AssertionError: assertion failed

Expectation

Should correctly execute the noE method as it should be passed via the implicit declaration in Wrapper.withFilter

(Left(No such element),Left(No such element))

It works again by defining

implicit def noE: Int => String = _ => "No such element"

Maybe it's the combination of inferring a union in Scala 3 plus not having a level test to prefer the local implicit to conforms.

(It works in Scala 2.)

As for the -source option, x.y-migration arguments are only supported as far as the oldest-still-supported LTS' minor version.
So in this case, we do not guarantee anything older than -source 3.3-migration would work.
And it does work for 3.3-migration.

This will not be worked on.