Skip to content

Commit 0576648

Browse files
committed
Merge pull request scala#4609 from retronym/topic/indylambda-test
[indylambda] Improve test coverage
2 parents 41edbe6 + 04977b7 commit 0576648

File tree

3 files changed

+73
-1
lines changed

3 files changed

+73
-1
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
object Test {
2+
def assertApply(expected: Boolean) = {
3+
val frames = Thread.currentThread.getStackTrace.takeWhile(_.getMethodName != "main")
4+
val usesObjectApply = frames.exists(_.getMethodName == "apply")
5+
assert(expected == usesObjectApply, frames.mkString("\n"))
6+
}
7+
def assertSpecialized() = assertApply(false)
8+
def assertUnspecialized() = assertApply(true)
9+
def main(args: Array[String]): Unit = {
10+
((i: String) => {assertUnspecialized(); i}).apply("")
11+
(() => {assertSpecialized(); 0}).apply()
12+
((i: Int) => {assertSpecialized(); i}).apply(0)
13+
((i: Int, j: Int) => {assertSpecialized(); i + j}).apply(0, 0)
14+
}
15+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package scala.tools.nsc.backend.jvm
2+
3+
import org.junit.Assert._
4+
import org.junit.{Assert, Test}
5+
6+
import scala.tools.asm.{Handle, Opcodes}
7+
import scala.tools.asm.tree.InvokeDynamicInsnNode
8+
import scala.tools.nsc.backend.jvm.AsmUtils._
9+
import scala.tools.nsc.backend.jvm.CodeGenTools._
10+
import scala.tools.testing.ClearAfterClass
11+
import scala.collection.JavaConverters._
12+
13+
object IndyLambdaTest extends ClearAfterClass.Clearable {
14+
var compiler = newCompiler(extraArgs = "-Ybackend:GenBCode")
15+
16+
def clear(): Unit = {
17+
compiler = null
18+
}
19+
}
20+
21+
class IndyLambdaTest extends ClearAfterClass {
22+
ClearAfterClass.stateToClear = IndyLambdaTest
23+
val compiler = IndyLambdaTest.compiler
24+
25+
@Test def boxingBridgeMethodUsedSelectively(): Unit = {
26+
def implMethodDescriptorFor(code: String): String = {
27+
val method = compileMethods(compiler)(s"""def f = $code """).find(_.name == "f").get
28+
val x = method.instructions.iterator.asScala.toList
29+
x.flatMap {
30+
case insn : InvokeDynamicInsnNode => insn.bsmArgs.collect { case h : Handle => h.getDesc }
31+
case _ => Nil
32+
}.head
33+
}
34+
// unspecialized functions that have a primitive in parameter or return position
35+
// give rise to a "boxing bridge" method (which has the suffix `$adapted`).
36+
// This is because Scala's unboxing of null values gives zero, whereas Java's throw a NPE.
37+
38+
// 1. Here we show that we are calling the boxing bridge (the lambda bodies here are compiled into
39+
// methods of `(I)Ljava/lang/Object;` / `(I)Ljava/lang/Object;` respectively.)
40+
assertEquals("(Ljava/lang/Object;)Ljava/lang/Object;", implMethodDescriptorFor("(x: Int) => new Object"))
41+
assertEquals("(Ljava/lang/Object;)Ljava/lang/Object;", implMethodDescriptorFor("(x: Object) => 0"))
42+
43+
// 2a. We don't need such adaptations for parameters or return values with types that differ
44+
// from Object due to other generic substitution, LambdaMetafactory will downcast the arguments.
45+
assertEquals("(Ljava/lang/String;)Ljava/lang/String;", implMethodDescriptorFor("(x: String) => x"))
46+
47+
// 2b. Testing 2a. in combination with 1.
48+
assertEquals("(Ljava/lang/Object;)Ljava/lang/String;", implMethodDescriptorFor("(x: Int) => \"\""))
49+
assertEquals("(Ljava/lang/String;)Ljava/lang/Object;", implMethodDescriptorFor("(x: String) => 0"))
50+
51+
// 3. Specialized functions, don't need any of this as they implement a method like `apply$mcII$sp`,
52+
// and the (un)boxing is handled in the base class in code emitted by scalac.
53+
assertEquals("(I)I", implMethodDescriptorFor("(x: Int) => x"))
54+
}
55+
}

test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ object InlineInfoTest extends ClearAfterClass.Clearable {
2727
}
2828

2929
@RunWith(classOf[JUnit4])
30-
class InlineInfoTest {
30+
class InlineInfoTest extends ClearAfterClass {
31+
ClearAfterClass.stateToClear = InlineInfoTest
32+
3133
val compiler = InlineInfoTest.compiler
3234

3335
def compile(code: String) = {

0 commit comments

Comments
 (0)