diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala | 12 | ||||
-rw-r--r-- | test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala | 15 |
2 files changed, 23 insertions, 4 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala index 929e8b5ca4..4744cb9ab1 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala @@ -65,12 +65,13 @@ class InlinerHeuristics[BT <: BTypes](val bTypes: BT) { } private def isTraitStaticSuperAccessorName(s: String) = s.endsWith("$") + private def traitStaticSuperAccessorName(s: String) = s + "$" private def isTraitSuperAccessor(method: MethodNode, owner: ClassBType): Boolean = { owner.isInterface == Right(true) && BytecodeUtils.isStaticMethod(method) && isTraitStaticSuperAccessorName(method.name) } - private def findCall(method: MethodNode, such: MethodInsnNode => Boolean): Option[MethodInsnNode] = { + private def findSingleCall(method: MethodNode, such: MethodInsnNode => Boolean): Option[MethodInsnNode] = { @tailrec def noMoreInvoke(insn: AbstractInsnNode): Boolean = { insn == null || (!insn.isInstanceOf[MethodInsnNode] && noMoreInvoke(insn.getNext)) } @@ -87,12 +88,15 @@ class InlinerHeuristics[BT <: BTypes](val bTypes: BT) { find(method.instructions.getFirst) } private def superAccessorInvocation(method: MethodNode): Option[MethodInsnNode] = - findCall(method, mi => mi.itf && mi.getOpcode == Opcodes.INVOKESTATIC && isTraitStaticSuperAccessorName(mi.name)) + findSingleCall(method, mi => mi.itf && mi.getOpcode == Opcodes.INVOKESTATIC && isTraitStaticSuperAccessorName(mi.name)) private def isMixinForwarder(method: MethodNode, owner: ClassBType): Boolean = { owner.isInterface == Right(false) && !BytecodeUtils.isStaticMethod(method) && - superAccessorInvocation(method).nonEmpty + (superAccessorInvocation(method) match { + case Some(mi) => mi.name == traitStaticSuperAccessorName(method.name) + case _ => false + }) } private def isTraitSuperAccessorOrMixinForwarder(method: MethodNode, owner: ClassBType): Boolean = { @@ -138,7 +142,7 @@ class InlinerHeuristics[BT <: BTypes](val bTypes: BT) { if (isTraitSuperAccessor(callee.callee, callee.calleeDeclarationClass)) { // scala-dev#259: when inlining a trait super accessor, also inline the callsite to the default method val implName = callee.callee.name.dropRight(1) - findCall(callee.callee, mi => mi.itf && mi.getOpcode == Opcodes.INVOKESPECIAL && mi.name == implName) + findSingleCall(callee.callee, mi => mi.itf && mi.getOpcode == Opcodes.INVOKESPECIAL && mi.name == implName) } else { // scala-dev#259: when inlining a mixin forwarder, also inline the callsite to the static super accessor superAccessorInvocation(callee.callee) 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 90a938be35..7be88816d5 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala @@ -1738,4 +1738,19 @@ class InlinerTest extends BytecodeTesting { val List(a, c, t) = compile(code, allowMessage = _.msg contains warn) assertInvoke(getMethod(c, "t"), "T", "m$") } + + @Test + def sd259d(): Unit = { + val code = + """trait T { + | @inline final def m = 1 + |} + |class C extends T { + | def t = super.m // inline call to T.m$ here, we're not in the mixin forwarder C.m + |} + """.stripMargin + val List(c, t) = compileClasses(code) + assertNoInvoke(getMethod(c, "t")) + assertInvoke(getMethod(c, "m"), "T", "m$") + } } |