summaryrefslogtreecommitdiff
path: root/test/junit
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2016-04-05 22:01:43 +0200
committerLukas Rytz <lukas.rytz@gmail.com>2016-04-12 12:01:31 +0200
commit33e71061d63d08ee23e28d9a43ad601afa74e043 (patch)
tree83c4279524ae3aa6d5a270fc6bd1662102742a26 /test/junit
parentb932419f07c0d747d868ebc3b51ccc54573a5827 (diff)
downloadscala-33e71061d63d08ee23e28d9a43ad601afa74e043.tar.gz
scala-33e71061d63d08ee23e28d9a43ad601afa74e043.tar.bz2
scala-33e71061d63d08ee23e28d9a43ad601afa74e043.zip
SD-98 don't emit unnecessary mixin forwarders
In most cases when a class inherits a concrete method from a trait we don't need to generate a forwarder to the default method in the class. t5148 is moved to pos as it compiles without error now. the error message ("missing or invalid dependency") is still tested by t6440b.
Diffstat (limited to 'test/junit')
-rw-r--r--test/junit/scala/issues/BytecodeTest.scala133
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala23
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala4
3 files changed, 139 insertions, 21 deletions
diff --git a/test/junit/scala/issues/BytecodeTest.scala b/test/junit/scala/issues/BytecodeTest.scala
index 18f8b44391..08b984a622 100644
--- a/test/junit/scala/issues/BytecodeTest.scala
+++ b/test/junit/scala/issues/BytecodeTest.scala
@@ -3,11 +3,14 @@ package scala.issues
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.Test
+
import scala.tools.asm.Opcodes._
import scala.tools.nsc.backend.jvm.AsmUtils
import scala.tools.nsc.backend.jvm.CodeGenTools._
import org.junit.Assert._
+
import scala.collection.JavaConverters._
+import scala.tools.asm.tree.ClassNode
import scala.tools.partest.ASMConverters._
import scala.tools.testing.ClearAfterClass
@@ -208,4 +211,134 @@ class BytecodeTest extends ClearAfterClass {
Label(14), Op(ICONST_0),
Label(17), Op(IRETURN)))
}
+
+ object forwarderTestUtils {
+ def findMethods(cls: ClassNode, name: String): List[Method] = cls.methods.iterator.asScala.find(_.name == name).map(convertMethod).toList
+
+ import language.implicitConversions
+ implicit def s2c(s: Symbol)(implicit classes: Map[String, ClassNode]): ClassNode = classes(s.name)
+
+ def checkForwarder(c: ClassNode, target: String) = {
+ val List(f) = findMethods(c, "f")
+ assertSameCode(f, List(VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, target, "f", "()I", false), Op(IRETURN)))
+ }
+ }
+
+ @Test
+ def traitMethodForwarders(): Unit = {
+ import forwarderTestUtils._
+ val code =
+ """trait T1 { def f = 1 }
+ |trait T2 extends T1 { override def f = 2 }
+ |trait T3 { self: T1 => override def f = 3 }
+ |
+ |abstract class A1 { def f: Int }
+ |class A2 { def f: Int = 4 }
+ |
+ |trait T4 extends A1 { def f = 5 }
+ |trait T5 extends A2 { override def f = 6 }
+ |
+ |trait T6 { def f: Int }
+ |trait T7 extends T6 { abstract override def f = super.f + 1 }
+ |
+ |trait T8 { override def clone() = super.clone() }
+ |
+ |class A3 extends T1 { override def f = 7 }
+ |
+ |class C1 extends T1
+ |class C2 extends T2
+ |class C3 extends T1 with T2
+ |class C4 extends T2 with T1
+ |class C5 extends T1 with T3
+ |
+ |// traits extending a class that defines f
+ |class C6 extends T4
+ |class C7 extends T5
+ |class C8 extends A1 with T4
+ |class C9 extends A2 with T5
+ |
+ |// T6: abstract f in trait
+ |class C10 extends T6 with T1
+ |class C11 extends T6 with T2
+ |abstract class C12 extends A1 with T6
+ |class C13 extends A2 with T6
+ |class C14 extends T4 with T6
+ |class C15 extends T5 with T6
+ |
+ |// superclass overrides a trait method
+ |class C16 extends A3
+ |class C17 extends A3 with T1
+ |
+ |// abstract override
+ |class C18 extends T6 { def f = 22 }
+ |class C19 extends C18 with T7
+ |
+ |class C20 extends T8
+ """.stripMargin
+
+ implicit val classes = compileClasses(compiler)(code).map(c => (c.name, c)).toMap
+
+ val noForwarder = List('C1, 'C2, 'C3, 'C4, 'C10, 'C11, 'C12, 'C13, 'C16, 'C17)
+ for (c <- noForwarder) assertEquals(findMethods(c, "f"), Nil)
+
+ checkForwarder('C5, "T3")
+ checkForwarder('C6, "T4")
+ checkForwarder('C7, "T5")
+ checkForwarder('C8, "T4")
+ checkForwarder('C9, "T5")
+ checkForwarder('C14, "T4")
+ checkForwarder('C15, "T5")
+ assertSameSummary(getSingleMethod('C18, "f"), List(BIPUSH, IRETURN))
+ checkForwarder('C19, "T7")
+ assertSameCode(getSingleMethod('C19, "T7$$super$f"), List(VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, "C18", "f", "()I", false), Op(IRETURN)))
+ assertInvoke(getSingleMethod('C20, "clone"), "T8", "clone") // mixin forwarder
+ }
+
+ @Test
+ def noTraitMethodForwardersForOverloads(): Unit = {
+ import forwarderTestUtils._
+ val code =
+ """trait T1 { def f(x: Int) = 0 }
+ |trait T2 { def f(x: String) = 1 }
+ |class C extends T1 with T2
+ """.stripMargin
+ val List(c, t1, t2) = compileClasses(compiler)(code)
+ assertEquals(findMethods(c, "f"), Nil)
+ }
+
+ @Test
+ def traitMethodForwardersForJavaDefaultMethods(): Unit = {
+ import forwarderTestUtils._
+ val j1 = ("interface J1 { int f(); }", "J1.java")
+ val j2 = ("interface J2 { default int f() { return 1; } }", "J2.java")
+ val j3 = ("interface J3 extends J1 { default int f() { return 2; } }", "J3.java")
+ val j4 = ("interface J4 extends J2 { default int f() { return 3; } }", "J4.java")
+ val code =
+ """trait T1 extends J2 { override def f = 4 }
+ |trait T2 { self: J2 => override def f = 5 }
+ |
+ |class K1 extends J2
+ |class K2 extends J1 with J2
+ |class K3 extends J2 with J1
+ |
+ |class K4 extends J3
+ |class K5 extends J3 with J1
+ |class K6 extends J1 with J3
+ |
+ |class K7 extends J4
+ |class K8 extends J4 with J2
+ |class K9 extends J2 with J4
+ |
+ |class K10 extends T1 with J2
+ |class K11 extends J2 with T1
+ |
+ |class K12 extends J2 with T2
+ """.stripMargin
+ implicit val classes = compileClasses(compiler)(code, List(j1, j2, j3, j4)).map(c => (c.name, c)).toMap
+
+ val noForwarder = List('K1, 'K2, 'K3, 'K4, 'K5, 'K6, 'K7, 'K8, 'K9, 'K10, 'K11)
+ for (c <- noForwarder) assertEquals(findMethods(c, "f"), Nil)
+
+ checkForwarder('K12, "T2")
+ }
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
index 9079ca248a..15665fca33 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
@@ -458,19 +458,6 @@ class InlinerTest extends ClearAfterClass {
}
@Test
- def inlineMixinMethods(): Unit = {
- val code =
- """trait T {
- | @inline final def f = 1
- |}
- |class C extends T
- """.stripMargin
- val List(c, t) = compile(code)
- // the static implementation method is inlined into the mixin, so there's no invocation in the mixin
- assertNoInvoke(getSingleMethod(c, "f"))
- }
-
- @Test
def inlineTraitInherited(): Unit = {
val code =
"""trait T {
@@ -545,7 +532,7 @@ class InlinerTest extends ClearAfterClass {
val List(c, oMirror, oModule, t) = compile(code, allowMessage = i => {count += 1; i.msg contains warn})
assert(count == 1, count)
- assertNoInvoke(getSingleMethod(oModule, "f"))
+ assertNoInvoke(getSingleMethod(t, "f"))
assertNoInvoke(getSingleMethod(c, "t1"))
assertNoInvoke(getSingleMethod(c, "t2"))
@@ -1497,10 +1484,12 @@ class InlinerTest extends ClearAfterClass {
@Test
def sd86(): Unit = {
val code =
- """trait T { @inline def f = 1 } // note that f is not final
- |class C extends T
+ """trait T1 { @inline def f = 999 }
+ |trait T2 { self: T1 => @inline override def f = 1 } // note that f is not final
+ |class C extends T1 with T2
""".stripMargin
- val List(c, t) = compile(code, allowMessage = _ => true)
+ val List(c, t1, t2) = compile(code, allowMessage = _ => true)
+ // the forwarder C.f is inlined, so there's no invocation
assertSameSummary(getSingleMethod(c, "f"), List(ICONST_1, IRETURN))
}
}
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 4db2657c1b..46b3ad3f8e 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala
@@ -113,10 +113,6 @@ class ScalaInlineInfoTest extends ClearAfterClass {
val infoC = inlineInfo(c)
val expectC = InlineInfo(false, None, Map(
"O()LT$O$;" -> MethodInlineInfo(true ,false,false),
- "f1()I" -> MethodInlineInfo(false,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,false),
"x1()I" -> MethodInlineInfo(false,false,false),
"T$_setter_$x1_$eq(I)V" -> MethodInlineInfo(false,false,false),