-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[indylambda] Relieve LambdaMetafactory of boxing duties
`LambdaMetafactory` generates code to perform a limited number of type adaptations when delegating from its implementation of the functional interface method to the lambda target method. These adaptations are: numeric widening, casting, boxing and unboxing. However, the semantics of unboxing numerics in Java differs to Scala: they treat `UNBOX(null)` as cause to raise a `NullPointerException`, Scala (in `BoxesRuntime.unboxTo{Byte,Short,...}`) reinterprets the null as zero. Furthermore, Java has no idea how to adapt between a value class and its wrapped type, nor from a void return to `BoxedUnit`. This commit detects when the lambda target method would require such adaptation. If it does, an extra method, `$anonfun$1$adapted` is created to perform the adaptation, and this is used as the target of the lambda. This obviates the use of `JProcedureN` for `Unit` returning lambdas, we know use `JFunctionN` as the functional interface and bind this to an `$adapted` method that summons the instance of `BoxedUnit` after calling the `void` returning lambda target. The enclosed test cases fail without boxing changes. They don't execute with indylambda enabled under regular partest runs yet, you need to add scala-java8-compat to scala-library and pass the SCALAC_OPTS to partest manually to try this out, as described in #4463. Once we enable indylambda by default, however, this test will exercise the code in this patch all the time. It is also possible to run the tests with: ``` % curl https://oss.sonatype.org/content/repositories/releases/org/scala-lang/modules/scala-java8-compat_2.11/0.4.0/scala-java8-compat_2.11-0.4.0.jar > scala-java8-compat_2.11-0.4.0.jar % export INDYLAMBDA="-Ydelambdafy:method -Ybackend:GenBCode -target:jvm-1.8 -classpath .:scala-java8-compat_2.11-0.4.0.jar" qscalac $INDYLAMBDA test/files/run/indylambda-boxing/*.scala && qscala $INDYLAMBDA Test ```
- Loading branch information
Showing
6 changed files
with
157 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
object Test { | ||
def main(args: Array[String]): Unit = { | ||
val i2s = (x: Int) => "" | ||
assert(i2s.asInstanceOf[AnyRef => String].apply(null) == "") | ||
val i2i = (x: Int) => x + 1 | ||
assert(i2i.asInstanceOf[AnyRef => Int].apply(null) == 1) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
|
||
class VC(private val i: Int) extends AnyVal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
class Capture | ||
class Test { | ||
def test1 = (i: Int) => "" | ||
def test2 = (i: VC) => i | ||
def test3 = (i: Int) => i | ||
|
||
def test4 = {val c = new Capture; (i: Int) => {(c, Test.this.toString); 42} } | ||
def test5 = {val c = new Capture; (i: VC) => (c, Test.this.toString) } | ||
def test6 = {val c = new Capture; (i: Int) => (c, Test.this.toString) } | ||
|
||
def test7 = {val vc = new Capture; (i: Int) => vc } | ||
def test8 = {val c = 42; (s: String) => (s, c)} | ||
def test9 = {val c = 42; (s: String) => ()} | ||
} | ||
|
||
object Test { | ||
def main(args: Array[String]): Unit = { | ||
val t = new Test | ||
assert(t.test1.apply(42) == "") | ||
assert(t.test2.apply(new VC(42)) == new VC(42)) | ||
assert(t.test3.apply(-1) == -1) | ||
t.test4.apply(0) | ||
t.test5.apply(new VC(42)) | ||
t.test6.apply(42) | ||
t.test7.apply(0) | ||
t.test8.apply("") | ||
t.test9.apply("") | ||
} | ||
} |