Description
Given:
import java.util.function.Function
object Test {
def computeScala[R](f: String => R) = f("abc")
def computeJava[R](f: Function[String, R]) = f("abc")
def main(args: Array[String]) = {
computeScala(s => println(s)) // OK
computeJava(s => println(s)) // java.lang.BootstrapMethodError: call site initialization exception
}
}
I get a BootstrapMethodError when calling computeJava
. The full output is:
~/workspace/dotty/tests/run> java Test
abc
Exception in thread "main" java.lang.BootstrapMethodError: call site initialization exception
at java.lang.invoke.CallSite.makeSite(CallSite.java:341)
at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:307)
at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:297)
at Test$.main(voidfun.scala:10)
at Test.main(voidfun.scala)
Caused by: java.lang.invoke.LambdaConversionException: Type mismatch for lambda expected return: void is not convertible to class java.lang.Object
at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:286)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303)
at java.lang.invoke.CallSite.makeSite(CallSite.java:302)
... 4 more
I printed the code abobe at phase LabelDefs, the only difference in the two calls is that the closure passed to the Java function has an expected result type this.main$$anonfun$2:java.util.function.Function
.
package <empty> {
@scala.annotation.internal.SourceFile("voidfun.scala") final module class
Test$
extends Object {
def <init>(): Unit =
{
super()
()
}
def computeScala(f: Function1): Object = f.apply("abc")
def computeJava(f: java.util.function.Function): Object = f.apply("abc")
def main(args: String[]): Unit =
{
Test.computeScala(
{
closure(this.main$$anonfun$1)
}
)
{
Test.computeJava(
{
closure(this.main$$anonfun$2:java.util.function.Function)
}
)
()
}
}
private def main$$anonfun$1(s: String): Unit = println(s)
private def main$$anonfun$2(s: String): Unit = println(s)
}
final lazy module val Test: Test$ = new Test$()
}
@retronym, @lrytz: Is there some backend transformation that handles this and that we are missing? @DarkDimius any advice how to handle this?