Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runtime java.lang.AbstractMethodError when combining opaque type erasure, value class erasure, and generic type erasure #17281

Open
dzanot opened this issue Apr 14, 2023 · 5 comments

Comments

@dzanot
Copy link

dzanot commented Apr 14, 2023

Compiler version

3.3.0

Minimized code

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

type IO[T] = T
opaque type NonNegLong = Long

object NonNegLong {
  def apply(l: Long): Option[NonNegLong] = if (l < 0) None else Some(l)
}

case class Baz(value: NonNegLong) extends AnyVal

trait InnerThing[F[_]]{
  def withBaz(baz: Baz): F[Unit]
}

object Main {
  val testInnerImpl = new InnerThing[IO] {
    override def withBaz(baz: Baz): IO[Unit] = println("withBaz")
  }

  @main def run = {
    println("Hello")
    NonNegLong(1l).map(Baz.apply(_)).fold(println("Nope"))(testInnerImpl.withBaz(_))
    println("Goodbye")
  }
}

Output

Hello

With excaption

java.lang.AbstractMethodError: Receiver class Main$$anon$1 does not define or inherit an implementation of the resolved method 'abstract java.lang.Object withBaz(long)' of interface InnerThing.
	at Main$.run$$anonfun$3(main.scala:22)
	at Main$.run$$anonfun$adapted$3(main.scala:22)
	at scala.Option.fold(Option.scala:263)
	at Main$.run(main.scala:22)
	at run.main(main.scala:20)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at sbt.Run.invokeMain(Run.scala:143)
	at sbt.Run.execute$1(Run.scala:93)
	at sbt.Run.$anonfun$runWithLoader$5(Run.scala:120)
	at sbt.Run$.executeSuccess(Run.scala:186)
	at sbt.Run.runWithLoader(Run.scala:120)
	at sbt.Run.run(Run.scala:127)
	at com.olegych.scastie.sbtscastie.SbtScastiePlugin$$anon$1.$anonfun$run$1(SbtScastiePlugin.scala:38)
	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
	at sbt.util.InterfaceUtil$$anon$1.get(InterfaceUtil.scala:21)
	at sbt.ScastieTrapExit$App.run(ScastieTrapExit.scala:258)
	at java.base/java.lang.Thread.run(Thread.java:833)

Expectation

No AbstractMethodError. This works as expected if you do any one of:

@nicolasstucki
Copy link
Contributor

We need to minimize this example to not have a dependency on cats.effect.IO.

@nicolasstucki nicolasstucki removed stat:needs triage Every issue needs to have an "area" and "itype" label stat:needs info labels Apr 17, 2023
@dzanot
Copy link
Author

dzanot commented Apr 17, 2023

Here is a zero dependency repro: https://scastie.scala-lang.org/PKqpEimLRYOWZmbl72myFw

@dzanot
Copy link
Author

dzanot commented May 1, 2023

@nicolasstucki does this need more information?

@dzanot
Copy link
Author

dzanot commented May 24, 2023

Tested with 3.3.0 release, updated the repro

@sjrd
Copy link
Member

sjrd commented Jun 7, 2023

Further minimization:

type IO[T] = T

opaque type NonNegLong = Long

object NonNegLong {
  def apply(l: Long): NonNegLong = l
}

class Baz(value: NonNegLong) extends AnyVal

trait InnerThing[F[_]] {
  def withBaz(baz: Baz): F[Unit]
}

class InnerThingImpl extends InnerThing[IO] {
  override def withBaz(baz: Baz): IO[Unit] = println("withBaz")
}

object Test {
  def main(args: Array[String]): Unit = {
    val testInnerImpl: InnerThing[IO] = new InnerThingImpl

    println("Hello")
    val nnl = new Baz(NonNegLong(1L))
    testInnerImpl.withBaz(nnl)
    println("Goodbye")
  }
}
  • Replacing F[Unit] by Any and IO[Unit] by Unit makes it work.
  • Removing the explicit type : InnerThing[IO] makes it work (because InnerThingImpl gets inferred and therefore we directly call its more specific withBaz).
  • Making NonNegLong a non-opaque type alias makes it work.
  • Making Baz a non-AnyVal makes it work.

@sjrd sjrd added area:erasure and removed stat:needs minimization Needs a self contained minimization labels Jun 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants