Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this Scala code throw IllegalAccessError at runtime?

I have a simple application:

object Test extends App {
  implicit def t2mapper[X, X0 <: X, X1 <: X](t: (X0, X1)) = new {
    def map[R](f: X => R) = (f(t._1), f(t._2))
  }
  println("Hello!")
  val (foo, bar) = (1, 2) map (_ * 2)
  println((foo, bar))
}

(The t2mapper is from this answer.)

The code compiles fine:

$ scalac -version
Scala compiler version 2.9.1 -- Copyright 2002-2011, LAMP/EPFL
$ scalac -unchecked Test.scala
$ 

but when run, it throws an IllegalAccessError (before Hello! gets printed):

$ java -version
java version "1.6.0_24"
OpenJDK Runtime Environment (IcedTea6 1.11.1) (6b24-1.11.1-4ubuntu3)
OpenJDK Server VM (build 20.0-b12, mixed mode)
$ scala Test
java.lang.IllegalAccessError: tried to access field Test$.reflParams$Cache1 from class Test$delayedInit$body
        at Test$delayedInit$body.(Test.scala:6)
        at Test$.(Test.scala:1)
        at Test$.(Test.scala)
        at Test.main(Test.scala)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:616)
        at scala.tools.nsc.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:78)
        at scala.tools.nsc.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:24)
        at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:88)
        at scala.tools.nsc.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:78)
        at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:101)
        at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:33)
        at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:40)
        at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:56)
        at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:80)
        at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:89)
        at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)

Note that with the last two lines replaced with

  println((1, 2) map (_ * 2))

or

  val (foo, bar) = (2, 4)
  println((foo, bar))

or

  val intermediate = (1, 2) map (_ * 2)
  val (foo, bar) = intermediate
  println((foo, bar))

it prints (2,4) as expected. But when wrapped in a block

  {
    val intermediate = (1, 2) map (_ * 2)
    val (foo, bar) = intermediate
    println((foo, bar))
  }

or

  private val blah = {
    val intermediate = (1, 2) map (_ * 2)
    val (foo, bar) = intermediate
    println((foo, bar))
  }

it throws the exception.

Why do the first and last ways cause an the JVM to throw an error at runtime?

like image 932
Mechanical snail Avatar asked Jul 02 '12 22:07

Mechanical snail


1 Answers

It looks like there are a few relevant open bugs. For example, this one might be related:

https://issues.scala-lang.org/browse/SI-5251?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel

Note you can also create a main method instead of extending App and it will work.

EDIT:

When you use this line (I expanded the implicit):

val (foo, bar) = t2mapper((1, 2)) map (_ * 2)

And then mouseover foo or bar in Eclipse, it shows private[this] val foo.

Therefore, it seems very similar to SI-5251.

like image 93
Dave L. Avatar answered Nov 18 '22 16:11

Dave L.