scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.83k stars 1.05k forks source link

AbstractMethodError in SAM lambdas when SAM contains method overrided with narrowed type #15402

Open Odomontois opened 2 years ago

Odomontois commented 2 years ago

Compiler version

3.1.2 and 3.2.0-RC1-bin-20220607-76a0b29-NIGHTLY

Minimized code

trait Named:
  def name: String

  def me: Named
end Named

trait Foo extends Named:
  def name = "foo"

  def me: Foo = this

  def foo(x: String): String
end Foo

class Names(xs: List[Named]):
  def mkString = xs.iterator.map(_.me.name).mkString(",")

object Names:
  def single[T <: Named](t: T): Names = Names(List(t))

@main def Repro() =
  val names = Names.single[Foo](x => x)
  println(names.mkString)

Output

Exception in thread "main" java.lang.AbstractMethodError: Receiver class Moons$package$$$Lambda$15/0x0000000800c074f8 does not define or inherit an implementation of the resolved method 'abstract .Named me()' of interface Named.
    at Names.mkString$$anonfun$1(Moons.scala:18)
    at scala.collection.Iterator$$anon$9.next(Iterator.scala:577)
    at scala.collection.IterableOnceOps.addString(IterableOnce.scala:1184)
    at scala.collection.IterableOnceOps.addString$(IterableOnce.scala:1179)
    at scala.collection.AbstractIterator.addString(Iterator.scala:1293)
    at scala.collection.IterableOnceOps.mkString(IterableOnce.scala:1129)
    at scala.collection.IterableOnceOps.mkString$(IterableOnce.scala:1127)
    at scala.collection.AbstractIterator.mkString(Iterator.scala:1293)
    at scala.collection.IterableOnceOps.mkString(IterableOnce.scala:1142)
    at scala.collection.IterableOnceOps.mkString$(IterableOnce.scala:1142)
    at scala.collection.AbstractIterator.mkString(Iterator.scala:1293)
    at Names.mkString(Moons.scala:18)
    at $package$.Repro(Moons.scala:25)
    at Repro.main(Moons.scala:23)

Scastie link

https://scastie.scala-lang.org/Odomontois/kzIirdZ1RRaDr1Wm8QN9TA/1

smarter commented 2 years ago

Scala 2 handles this by not generating an invokedynamic lambda in this situation and falling back to an anonymous class instance instead, I guess we should do the same (in https://github.com/lampepfl/dotty/blob/main/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala).

odersky commented 2 years ago

@WojciechMazur Do you think you could take this on?

tpunder commented 11 months ago

I just ran into this issue.

Here is another minimized example:

trait Adapter[T] extends Function1[T, Unit]

object Example {
  def main(args: Array[String]): Unit = {
    // In Scala 3 this causes a java.lang.AbstractMethodError
    makeAdapter[Integer](123)
  }

  // Works in Scala 2.12 and 2.13 but generates wrong bytecode for Scala 3
  // due to using `(arg: Number) => ()` instead of `(arg: T) => ()`
  def makeAdapter[T <: Number]: Adapter[T] = (arg: Number) => ()

https://scastie.scala-lang.org/cRqYj3CiSpWxGrGJNeV2Ww