From a4e71b188fe8069b4de3a0753defb624b8b1eb8c Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Mon, 9 Feb 2015 19:33:20 +0100 Subject: Cast receiver if necessary when rewriting trait calls to impl method The self parameter type may be incompatible with the trait type. trait T { self: S => def foo = 1 } The $self parameter type of T$class.foo is S, which may be unrelated to T. If we re-write a call to T.foo to T$class.foo, we need to cast the receiver to S, otherwise we get a VerifyError. --- .../tools/nsc/backend/jvm/opt/CallGraphTest.scala | 1 - .../tools/nsc/backend/jvm/opt/InlinerTest.scala | 25 ++++++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala index 16f09db189..d7344ae61f 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/CallGraphTest.scala @@ -11,7 +11,6 @@ import org.junit.Assert._ import scala.tools.asm.tree._ import scala.tools.asm.tree.analysis._ -import scala.tools.nsc.backend.jvm.opt.BytecodeUtils.BasicAnalyzer import scala.tools.testing.AssertUtil._ import CodeGenTools._ 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 694dff8dee..7f58f77b15 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala @@ -13,7 +13,7 @@ import org.junit.Assert._ import scala.tools.asm.tree._ import scala.tools.asm.tree.analysis._ -import scala.tools.nsc.backend.jvm.opt.BytecodeUtils.BasicAnalyzer +import scala.tools.nsc.backend.jvm.opt.BytecodeUtils.AsmAnalyzer import scala.tools.nsc.io._ import scala.tools.testing.AssertUtil._ @@ -84,7 +84,7 @@ class InlinerTest extends ClearAfterClass { val List(f, g) = cls.methods.asScala.filter(m => Set("f", "g")(m.name)).toList.sortBy(_.name) val fCall = g.instructions.iterator.asScala.collect({ case i: MethodInsnNode if i.name == "f" => i }).next() - val analyzer = new BasicAnalyzer(g, clsBType.internalName) + val analyzer = new AsmAnalyzer(g, clsBType.internalName) val r = inliner.inline( fCall, @@ -222,7 +222,7 @@ class InlinerTest extends ClearAfterClass { case m: MethodInsnNode if m.name == "g" => m }).next() - val analyzer = new BasicAnalyzer(h, dTp.internalName) + val analyzer = new AsmAnalyzer(h, dTp.internalName) val r = inliner.inline( gCall, @@ -374,7 +374,7 @@ class InlinerTest extends ClearAfterClass { val f = c.methods.asScala.find(_.name == "f").get val callsiteIns = f.instructions.iterator().asScala.collect({ case c: MethodInsnNode => c }).next() val clsBType = classBTypeFromParsedClassfile(c.name).get - val analyzer = new BasicAnalyzer(f, clsBType.internalName) + val analyzer = new AsmAnalyzer(f, clsBType.internalName) val integerClassBType = classBTypeFromInternalName("java/lang/Integer") val lowestOneBitMethod = byteCodeRepository.methodNode(integerClassBType.internalName, "lowestOneBit", "(I)I").get._1 @@ -720,4 +720,21 @@ class InlinerTest extends ClearAfterClass { assertNoInvoke(getSingleMethod(d, "m")) assertNoInvoke(getSingleMethod(c, "m")) } + + @Test + def inlineTraitCastReceiverToSelf(): Unit = { + val code = + """class C { def foo(x: Int) = x } + |trait T { self: C => + | @inline final def f(x: Int) = foo(x) + | def t1 = f(1) + | def t2(t: T) = t.f(2) + |} + """.stripMargin + val List(c, t, tc) = compile(code) + val t1 = getSingleMethod(tc, "t1") + val t2 = getSingleMethod(tc, "t2") + val cast = TypeOp(CHECKCAST, "C") + Set(t1, t2).foreach(m => assert(m.instructions.contains(cast), m.instructions)) + } } -- cgit v1.2.3