Open
Description
Example:
import scala.reflect.runtime.universe._
import scala.reflect.runtime._
object F {
def f(n: => Int): Int = n + 5
}
object App extends App {
val hi: () => Int = { () => println("hi"); 5 }
F.f(hi())
// res0: Int = 10
(currentMirror: universe.Mirror)
.reflect(F)
.reflectMethod(
symbolOf[F.type].asClass.module
.info.member(TermName("f")).asMethod)
.apply(hi)
/*
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(scratch_159.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke(scratch_159.scala:58)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(scratch_159.scala:39)
at java.lang.reflect.Method.invoke(scratch_159.scala:494)
at scala.reflect.runtime.JavaMirrors$JavaMirror$JavaMethodMirror.jinvokeraw(scratch_159.scala:332)
at scala.reflect.runtime.JavaMirrors$JavaMirror$JavaMethodMirror.jinvoke(scratch_159.scala:336)
at scala.reflect.runtime.JavaMirrors$JavaMirror$JavaTransformingMethodMirror.apply(scratch_159.scala:436)
at #worksheet#.#worksheet#(scratch_159.scala:19)
Caused by: java.lang.ClassCastException: A$A6$A$A6$$Lambda$17755/412629211 cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:101)
at scala.Function0.apply$mcI$sp(Function0.scala:34)
at A$A6$A$A6$F$.f(scratch_159.scala:9)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at scala.reflect.runtime.JavaMirrors$JavaMirror$JavaMethodMirror.jinvokeraw(JavaMirrors.scala:336)
at scala.reflect.runtime.JavaMirrors$JavaMirror$JavaMethodMirror.jinvoke(JavaMirrors.scala:340)
at scala.reflect.runtime.JavaMirrors$JavaMirror$JavaTransformingMethodMirror.apply(JavaMirrors.scala:440)
at A$A6$A$A6.get$$instance$$res1(scratch_159.scala:23)
at A$A6$.main(scratch_159.scala:48)
at A$A6.main(scratch_159.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.jetbrains.jps.incremental.scala.local.worksheet.WorksheetInProcessRunnerFactory$WorksheetInProcessRunnerImpl.$anonfun$loadAndRun$5(WorksheetInProcessRunnerFactory.scala:64)
at scala.Option.map(Option.scala:146)
at org.jetbrains.jps.incremental.scala.local.worksheet.WorksheetInProcessRunnerFactory$WorksheetInProcessRunnerImpl.loadAndRun(WorksheetInProcessRunnerFactory.scala:62)
at org.jetbrains.jps.incremental.scala.local.worksheet.WorksheetServer.$anonfun$loadAndRun$1(WorksheetServer.scala:31)
at org.jetbrains.jps.incremental.scala.local.worksheet.WorksheetServer.$anonfun$loadAndRun$1$adapted(WorksheetServer.scala:31)
at scala.Option.foreach(Option.scala:257)
at org.jetbrains.jps.incremental.scala.local.worksheet.WorksheetServer.loadAndRun(WorksheetServer.scala:31)
at org.jetbrains.jps.incremental.scala.remote.Main$.make(Main.scala:85)
*/
}
Expected being able to pass a delayed value to a by-name method, but got an exception!
The error is in scala.reflect.runtime.JavaMirrors
:
private class JavaTransformingMethodMirror(val receiver: Any, symbol: MethodSymbol, metadata: MethodMetadata)
extends JavaMethodMirror(symbol, metadata.ret) {
def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new MethodMetadata(symbol))
override def bind(newReceiver: Any) = new JavaTransformingMethodMirror(newReceiver, symbol, metadata)
import metadata._
def apply(args: Any*): Any = {
val args1 = new Array[Any](args.length)
var i = 0
while (i < args1.length) {
val arg = args(i)
args1(i) = (
if (i >= paramCount) arg // don't transform varargs
else if (isByName(i)) () => arg // don't transform by-name value class params
else if (isDerivedValueClass(i)) paramUnboxers(i).invoke(arg) // do get the underlying value
else arg // don't molest anything else
)
i += 1
}
jinvoke(args1)
}
}
Where in .apply
else if (isByName(i)) () => arg // don't transform by-name value class params
The argument is always assumed to be a computed value, not a delayed Function0
, therefore it's impossible to call a method with a delayed by-name
Something like this could fix it:
else if (isByName(i) && arg.getClass == classOf[Function0]) arg
else if (isByName(i)) () => arg // don't transform by-name value class params