scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
230 stars 21 forks source link

2.13 and JDK 11 - IllegalAccessError: Update to non-static final field #12881

Closed pvlugter closed 8 months ago

pvlugter commented 9 months ago

Uncovered by https://github.com/akka/akka/issues/32128 when dropping JDK 8 in Akka (https://github.com/akka/akka/pull/32127).

Additional case for https://github.com/scala/scala-dev/issues/408 and https://github.com/scala/bug/issues/12340.

Trait fields are still marked final when implemented by an anonymous class in a lazy val.

Reproduction steps

scalaVersion := "2.13.12"
scalacOptions ++= Seq("-release", "11")
trait T {
  val foo = "foo"
}

object Test {
  def main(args: Array[String]): Unit = {
    lazy val t = new T {}
    println(t)
  }
}

Problem

java.lang.IllegalAccessError: Update to non-static final field Test$$anon$1.foo attempted from a different method (T$_setter_$foo_$eq) than the initializer method <init>

Field marked final:

:javap -p -v Test$$anon$1

...

  private final java.lang.String foo;
    descriptor: Ljava/lang/String;
    flags: (0x0012) ACC_PRIVATE, ACC_FINAL

When it's either not a lazy val or not an anonymous class, the field is non-final:

  private java.lang.String foo;
    descriptor: Ljava/lang/String;
    flags: (0x0002) ACC_PRIVATE
lrytz commented 9 months ago

This was a hard one to pin down...

Example

trait T { val foo = "foo" }
class C {
  def m = {
    lazy val t = new T {}
    /* expands to
    lazy val t = {
      class anon extends T {
        private var _foo
        def foo = _foo
        def T$_setter_$foo_= (s: String) = { _foo = s}
      }
      new anon
    }
    */
    t
  }
}

Fields info transformer:

Fields tree transformer:

When obtaining the anonymous class info in a later phase, the fields info transformer will run again because the current type is only valid until fields. A new foo field symbol is created, it doesn't have the MUTABLE flag, so it ends up final in bytecode.