Java – why does this Scala code throw an 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)) }
(t2mapper starts with this answer.)
Code compilation is normal:
$scalac -version Scala compiler version 2.9.1 -- Copyright 2002-2011,LAMP/EPFL $scalac -unchecked Test.scala $
However, at run time, it will throw illegalaccesserror (before Hello! Is 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)
Notice that the last two lines are 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 as expected (2,4) But when the package is one block away
{ val intermediate = (1,2) map (_ * 2) val (foo,bar) = intermediate println((foo,bar)) }
or
private val blah = { val intermediate = (1,bar)) }
It threw an exception
Why do the first and last methods cause the JVM to throw errors at runtime?
Solution
It seems that there are some related open loopholes For example, this may be relevant:
https://issues.scala-lang.org/browse/SI-5251?page=com.atlassian.jira.plugin.system.issuetabpanels:all -tabpanel
Note that you can also create a main method instead of extending the app, which will work
Edit:
When you use this line (I extend the implicit):
val (foo,bar) = t2mapper((1,2)) map (_ * 2)
Then hover over foo or bar in eclipse, which displays private [this] Val foo
Therefore, it seems to be very similar to si-5251