summaryrefslogtreecommitdiff
path: root/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2015-07-08 15:45:03 +1000
committerJason Zaugg <jzaugg@gmail.com>2015-07-08 15:45:03 +1000
commitcca13ad0cb12669ed7a7931c5029a52486b9d6fc (patch)
treec69c77151082884a12c0144bbe6dd694ddf361cc /test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala
parentb92c3aff1ab8c76c4816bd7b1a82a0f87d787837 (diff)
downloadscala-cca13ad0cb12669ed7a7931c5029a52486b9d6fc.tar.gz
scala-cca13ad0cb12669ed7a7931c5029a52486b9d6fc.tar.bz2
scala-cca13ad0cb12669ed7a7931c5029a52486b9d6fc.zip
[indylambda] Improve test coverage
Adding tests for the selective use of boxing bridge methods and to show that specialization is not subverted by indylambda. Other aspects of indylambda are tested by tests like: - run/lambda-serialization.scala - run/indylambda-boxing When those tests were written, they only tested the old backend. However, now that we have Java 8 and the new backend avaialble by default to partest, they provide the intended coverage.
Diffstat (limited to 'test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala')
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala54
1 files changed, 54 insertions, 0 deletions
diff --git a/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala b/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala
new file mode 100644
index 0000000000..8bb003c8fb
--- /dev/null
+++ b/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala
@@ -0,0 +1,54 @@
+package scala.tools.nsc.backend.jvm
+
+import org.junit.Assert._
+import org.junit.{Assert, Test}
+
+import scala.tools.asm.{Handle, Opcodes}
+import scala.tools.asm.tree.InvokeDynamicInsnNode
+import scala.tools.nsc.backend.jvm.AsmUtils._
+import scala.tools.nsc.backend.jvm.CodeGenTools._
+import scala.tools.testing.ClearAfterClass
+import scala.collection.JavaConverters._
+
+object IndyLambdaTest extends ClearAfterClass.Clearable {
+ var compiler = newCompiler(extraArgs = "-Ybackend:GenBCode")
+
+ def clear(): Unit = {
+ compiler = null
+ }
+}
+
+class IndyLambdaTest {
+ val compiler = IndyLambdaTest.compiler
+
+ @Test def boxingBridgeMethodUsedSelectively(): Unit = {
+ def implMethodDescriptorFor(code: String): String = {
+ val method = compileMethods(compiler)(s"""def f = $code """).find(_.name == "f").get
+ val x = method.instructions.iterator.asScala.toList
+ x.flatMap {
+ case insn : InvokeDynamicInsnNode => insn.bsmArgs.collect { case h : Handle => h.getDesc }
+ case _ => Nil
+ }.head
+ }
+ // unspecialized functions that have a primitive in parameter or return position
+ // give rise to a "boxing bridge" method (which has the suffix `$adapted`).
+ // This is because Scala's unboxing of null values gives zero, whereas Java's throw a NPE.
+
+ // 1. Here we show that we are calling the boxing bridge (the lambda bodies here are compiled into
+ // methods of `(I)java/lang/Object;` / `(I)java/lang/Object;` respectively.)
+ assertEquals("(Ljava/lang/Object;)Ljava/lang/Object;", implMethodDescriptorFor("(x: Int) => new Object"))
+ assertEquals("(Ljava/lang/Object;)Ljava/lang/Object;", implMethodDescriptorFor("(x: Object) => 0"))
+
+ // 2a. We don't need such adaptations for parameters or return values with types that differ
+ // from Object due to other generic substitution, LambdaMetafactory will downcast the arguments.
+ assertEquals("(Ljava/lang/String;)Ljava/lang/String;", implMethodDescriptorFor("(x: String) => x"))
+
+ // 2b. Testing 2a. in combination with 1.
+ assertEquals("(Ljava/lang/Object;)Ljava/lang/String;", implMethodDescriptorFor("(x: Int) => \"\""))
+ assertEquals("(Ljava/lang/String;)Ljava/lang/Object;", implMethodDescriptorFor("(x: String) => 0"))
+
+ // 3. Specialized functions, don't need any of this as they implement a method like `apply$mcII$sp`,
+ // and the (un)boxing is handled in the base class in code emitted by scalac.
+ assertEquals("(I)I", implMethodDescriptorFor("(x: Int) => x"))
+ }
+}