diff options
Diffstat (limited to 'test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala')
-rw-r--r-- | test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala | 153 |
1 files changed, 125 insertions, 28 deletions
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala index f8e887426b..8dd23ec3ce 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala @@ -9,26 +9,43 @@ import scala.tools.asm.Opcodes._ import org.junit.Assert._ import CodeGenTools._ +import scala.tools.asm.tree.ClassNode import scala.tools.nsc.backend.jvm.BTypes.{MethodInlineInfo, InlineInfo} import scala.tools.partest.ASMConverters import ASMConverters._ -import scala.collection.convert.decorateAsScala._ +import scala.collection.JavaConverters._ +import scala.tools.testing.ClearAfterClass -object ScalaInlineInfoTest { - var compiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:none") +object ScalaInlineInfoTest extends ClearAfterClass.Clearable { + var compiler = newCompiler(extraArgs = "-Yopt:l:none") def clear(): Unit = { compiler = null } } @RunWith(classOf[JUnit4]) -class ScalaInlineInfoTest { - val compiler = newCompiler() +class ScalaInlineInfoTest extends ClearAfterClass { + ClearAfterClass.stateToClear = ScalaInlineInfoTest + val compiler = ScalaInlineInfoTest.compiler + + def inlineInfo(c: ClassNode): InlineInfo = c.attrs.asScala.collect({ case a: InlineInfoAttribute => a.inlineInfo }).head + + def mapDiff[A, B](a: Map[A, B], b: Map[A, B]) = { + val r = new StringBuilder + for ((a, av) <- a) { + if (!b.contains(a)) r.append(s"missing in b: $a\n") + else if (av != b(a)) r.append(s"different for $a: $av != ${b(a)}\n") + } + for (b <- b.keys.toList diff a.keys.toList) { + r.append(s"missing in a: $b\n") + } + r.toString + } @Test def traitMembersInlineInfo(): Unit = { val code = """trait T { | def f1 = 1 // concrete method - | private def f2 = 1 // implOnly method (does not end up in the interface) + | private def f2 = 1 // default method only (not in subclass) | def f3 = { | def nest = 0 // nested method (does not end up in the interface) | nest @@ -38,13 +55,13 @@ class ScalaInlineInfoTest { | def f4 = super.toString // super accessor | | object O // module accessor (method is generated) - | def f5 = { + | final def f5 = { | object L { val x = 0 } // nested module (just flattened out) | L.x | } | | @noinline - | def f6: Int // abstract method (not in impl class) + | def f6: Int // abstract method | | // fields | @@ -55,31 +72,111 @@ class ScalaInlineInfoTest { | | final val x5 = 0 |} + |class C extends T { + | def f6 = 0 + | var x3 = 0 + |} """.stripMargin - val cs @ List(t, tl, to, tCls) = compileClasses(compiler)(code) - val List(info) = t.attrs.asScala.collect({ case a: InlineInfoAttribute => a.inlineInfo }).toList - val expect = InlineInfo( - None, // self type + val cs @ List(c, t, tl, to) = compileClasses(compiler)(code) + val infoT = inlineInfo(t) + val expectT = InlineInfo ( false, // final class + None, // not a sam Map( - ("O()LT$O$;", MethodInlineInfo(true, false,false,false)), - ("T$$super$toString()Ljava/lang/String;",MethodInlineInfo(false,false,false,false)), - ("T$_setter_$x1_$eq(I)V", MethodInlineInfo(false,false,false,false)), - ("f1()I", MethodInlineInfo(false,true, false,false)), - ("f3()I", MethodInlineInfo(false,true, false,false)), - ("f4()Ljava/lang/String;", MethodInlineInfo(false,true, true, false)), - ("f5()I", MethodInlineInfo(false,true, false,false)), - ("f6()I", MethodInlineInfo(false,false,false,true )), - ("x1()I", MethodInlineInfo(false,false,false,false)), - ("x3()I", MethodInlineInfo(false,false,false,false)), - ("x3_$eq(I)V", MethodInlineInfo(false,false,false,false)), - ("x4()I", MethodInlineInfo(false,false,false,false)), - ("x5()I", MethodInlineInfo(true, false,false,false)), - ("y2()I", MethodInlineInfo(false,false,false,false)), - ("y2_$eq(I)V", MethodInlineInfo(false,false,false,false))), + ("O()LT$O$;", MethodInlineInfo(true ,false,false)), // the accessor is abstract in bytecode, but still effectivelyFinal because there's no (late)DEFERRED flag, https://github.com/scala/scala-dev/issues/126 + ("T$$super$toString()Ljava/lang/String;", MethodInlineInfo(true ,false,false)), + ("T$_setter_$x1_$eq(I)V", MethodInlineInfo(false,false,false)), + ("f1()I", MethodInlineInfo(false,false,false)), + ("f2()I", MethodInlineInfo(true, false,false)), + ("f3()I", MethodInlineInfo(false,false,false)), + ("f4()Ljava/lang/String;", MethodInlineInfo(false,true, false)), + ("f5()I", MethodInlineInfo(true ,false,false)), + ("f6()I", MethodInlineInfo(false,false,true )), + ("x1()I", MethodInlineInfo(false,false,false)), + ("y2()I", MethodInlineInfo(false,false,false)), + ("y2_$eq(I)V", MethodInlineInfo(false,false,false)), + ("x3()I", MethodInlineInfo(false,false,false)), + ("x3_$eq(I)V", MethodInlineInfo(false,false,false)), + ("x4()I", MethodInlineInfo(false,false,false)), + ("x5()I", MethodInlineInfo(true, false,false)), + ("L$lzycompute$1(Lscala/runtime/VolatileObjectRef;)LT$L$2$;", MethodInlineInfo(true, false,false)), + ("L$1(Lscala/runtime/VolatileObjectRef;)LT$L$2$;", MethodInlineInfo(true ,false,false)), + ("nest$1()I", MethodInlineInfo(true, false,false)), + ("$init$()V", MethodInlineInfo(false,false,false))), None // warning ) - assert(info == expect, info) + + assert(infoT == expectT, mapDiff(expectT.methodInfos, infoT.methodInfos) + infoT) + + val infoC = inlineInfo(c) + val expectC = InlineInfo(false, None, Map( + "O()LT$O$;" -> MethodInlineInfo(true ,false,false), + "O$lzycompute()LT$O$;" -> MethodInlineInfo(true, false,false), + "f6()I" -> MethodInlineInfo(false,false,false), + "x1()I" -> MethodInlineInfo(false,false,false), + "T$_setter_$x1_$eq(I)V" -> MethodInlineInfo(false,false,false), + "y2()I" -> MethodInlineInfo(false,false,false), + "y2_$eq(I)V" -> MethodInlineInfo(false,false,false), + "x3()I" -> MethodInlineInfo(false,false,false), + "x3_$eq(I)V" -> MethodInlineInfo(false,false,false), + "x4$lzycompute()I" -> MethodInlineInfo(true ,false,false), + "x4()I" -> MethodInlineInfo(false,false,false), + "x5()I" -> MethodInlineInfo(true ,false,false), + "T$$super$toString()Ljava/lang/String;" -> MethodInlineInfo(true ,false,false), + "<init>()V" -> MethodInlineInfo(false,false,false)), + None) + + assert(infoC == expectC, mapDiff(expectC.methodInfos, infoC.methodInfos) + infoC) + } + + @Test + def inlineInfoSam(): Unit = { + val code = + """trait C { // expected to be seen as sam: g(I)I + | def f = 0 + | def g(x: Int): Int + | val foo = "hi" + |} + |abstract class D { + | val biz: Int + |} + |trait T { // expected to be seen as sam: h(Ljava/lang/String;)I + | def h(a: String): Int + |} + |trait E extends T { // expected to be seen as sam: h(Ljava/lang/String;)I + | def hihi(x: Int) = x + |} + |class F extends T { + | def h(a: String) = 0 + |} + |trait U { + | def conc() = 10 + | def nullary: Int + |} + """.stripMargin + val cs = compileClasses(compiler)(code) + val sams = cs.map(c => (c.name, inlineInfo(c).sam)) + assertEquals(sams, + List( + ("C",Some("g(I)I")), + ("D",None), + ("E",Some("h(Ljava/lang/String;)I")), + ("F",None), + ("T",Some("h(Ljava/lang/String;)I")), + ("U",None))) + + } + + @Test + def lzyComputeInlineInfo(): Unit = { + val code = "class C { object O }" + val List(c, om) = compileClasses(compiler)(code) + val infoC = inlineInfo(c) + val expected = Map( + "<init>()V" -> MethodInlineInfo(false,false,false), + "O$lzycompute()LC$O$;" -> MethodInlineInfo(true,false,false), + "O()LC$O$;" -> MethodInlineInfo(true,false,false)) + assert(infoC.methodInfos == expected, mapDiff(infoC.methodInfos, expected)) } } |