Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runtime crash for Unit-returning closures passed to Java functions #3984

Closed
odersky opened this issue Feb 12, 2018 · 1 comment
Closed

Runtime crash for Unit-returning closures passed to Java functions #3984

odersky opened this issue Feb 12, 2018 · 1 comment
Assignees

Comments

@odersky
Copy link
Contributor

odersky commented Feb 12, 2018

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?

@smarter
Copy link
Member

smarter commented Feb 12, 2018

There's already a bunch of code in Erasure I wrote to deal with closure adaptation, I think we just need to properly handle boxing unit in here: https://github.com/lampepfl/dotty/blob/master/compiler/src/dotty/tools/dotc/transform/Erasure.scala#L593-L632

smarter added a commit to dotty-staging/dotty that referenced this issue Feb 12, 2018
If the abstract method in a SAM trait has a generic result type that is
instantiated to Unit, we need to adapt closures implementing this trait
to return BoxedUnit. This isn't necessary for
`scala.Function*[...,Unit]` because in the backend they're implemented
using the `JProcedure*` SAMs (see DottyBackendInterface#Closure) that
already handle adapting to BoxedUnit.
smarter added a commit to dotty-staging/dotty that referenced this issue Feb 12, 2018
If the abstract method in a SAM trait has a generic result type that is
instantiated to Unit, we need to adapt closures implementing this trait
to return BoxedUnit. This isn't necessary for
`scala.Function*[...,Unit]` because in the backend they're implemented
using the `JProcedure*` SAMs (see DottyBackendInterface#Closure) that
already handle adapting to BoxedUnit.
smarter added a commit to dotty-staging/dotty that referenced this issue Feb 12, 2018
If the abstract method in a SAM trait has a generic result type that is
instantiated to Unit, we need to adapt closures implementing this trait
to return BoxedUnit. This isn't necessary for
`scala.Function*[...,Unit]` because in the backend they're implemented
using the `JProcedure*` SAMs (see DottyBackendInterface#Closure) that
already handle adapting to BoxedUnit.
smarter added a commit to dotty-staging/dotty that referenced this issue Feb 12, 2018
If the abstract method in a SAM trait has a generic result type that is
instantiated to Unit, we need to adapt closures implementing this trait
to return BoxedUnit. This isn't necessary for Unit-returning closures
without an explicit SAM type because in the backend they're implemented
using the `JProcedure*` SAMs (see DottyBackendInterface#Closure) that
already handle adapting to BoxedUnit.
smarter added a commit to dotty-staging/dotty that referenced this issue Feb 12, 2018
If the abstract method in a SAM trait has a generic result type that is
instantiated to Unit, we need to adapt closures implementing this trait
to return BoxedUnit. This isn't necessary for Unit-returning closures
without an explicit SAM type because in the backend they're implemented
using the `JProcedure*` SAMs (see DottyBackendInterface#Closure) that
already handle adapting to BoxedUnit.
smarter added a commit that referenced this issue Feb 13, 2018
Fix #3984: SAM closures returning Unit may need adaptation
odersky added a commit to dotty-staging/dotty that referenced this issue Feb 27, 2018
odersky added a commit to dotty-staging/dotty that referenced this issue Mar 9, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants