summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan@lightbend.com>2016-09-06 10:24:45 +0200
committerGitHub <noreply@github.com>2016-09-06 10:24:45 +0200
commitf43cc1382610a3be7d8d6ed485a7410d7a1f1aa3 (patch)
tree04052ca7a13877ed8d38a3b84960567a0f8d7cef
parentd29df860e5b10181f6c37bde3bd7539bdc843e0d (diff)
parent0a840380aa47d52d2addd2b96dbbb68b874c3a67 (diff)
downloadscala-f43cc1382610a3be7d8d6ed485a7410d7a1f1aa3.tar.gz
scala-f43cc1382610a3be7d8d6ed485a7410d7a1f1aa3.tar.bz2
scala-f43cc1382610a3be7d8d6ed485a7410d7a1f1aa3.zip
Merge pull request #5377 from lrytz/sd143-relax
SD-143 allow super calls to methods defined in indirect super classes
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala8
-rw-r--r--test/junit/scala/lang/traits/BytecodeTest.scala23
2 files changed, 30 insertions, 1 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index a38d21fe10..963a9dea02 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -152,11 +152,17 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
// SD-143: a call super[T].m that resolves to A.m cannot be translated to correct bytecode if
// - A is a class (not a trait / interface), but not the direct superclass. Invokespecial
// would select an overriding method in the direct superclass, rather than A.m.
+ // We allow this if there are statically no intervening overrides.
// https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokespecial
// - A is a java-defined interface and not listed as direct parent of the class. In this
// case, `invokespecial A.m` would be invalid.
+ def hasClassOverride(member: Symbol, subclass: Symbol): Boolean = {
+ if (subclass == ObjectClass || subclass == member.owner) false
+ else if (member.overridingSymbol(subclass) != NoSymbol) true
+ else hasClassOverride(member, subclass.superClass)
+ }
val owner = sym.owner
- if (!owner.isTrait && owner != clazz.superClass) {
+ if (!owner.isTrait && owner != clazz.superClass && hasClassOverride(sym, clazz.superClass)) {
reporter.error(sel.pos,
s"cannot emit super call: the selected $sym is declared in $owner, which is not the direct superclass of $clazz.\n" +
s"An unqualified super call (super.${sym.name}) would be allowed.")
diff --git a/test/junit/scala/lang/traits/BytecodeTest.scala b/test/junit/scala/lang/traits/BytecodeTest.scala
index 7bfa3362d4..cf658288c4 100644
--- a/test/junit/scala/lang/traits/BytecodeTest.scala
+++ b/test/junit/scala/lang/traits/BytecodeTest.scala
@@ -277,6 +277,29 @@ class BytecodeTest extends BytecodeTesting {
}
@Test
+ def sd143c(): Unit = {
+ // Allow super calls to class methods of indirect super classes
+ val code =
+ """class A { def f = 1 }
+ |class B extends A
+ |trait T extends A { override def f = 2 }
+ |class C extends B with T {
+ | def t1 = super[B].f
+ | def t2 = super.f
+ | def t3 = super[T].f
+ |}
+ """.stripMargin
+ val List(_, _, c, _) = compileClasses(code)
+ val t1 = getInstructions(c, "t1")
+ assert(t1 contains Invoke(INVOKESPECIAL, "A", "f", "()I", false), t1.stringLines)
+ val t2 = getInstructions(c, "t2")
+ val invStat = Invoke(INVOKESTATIC, "T", "f$", "(LT;)I", true)
+ assert(t2 contains invStat, t2.stringLines)
+ val t3 = getInstructions(c, "t3")
+ assert(t3 contains invStat, t3.stringLines)
+ }
+
+ @Test
def sd210(): Unit = {
val forwardersCompiler = newCompiler(extraArgs = "-Xmixin-force-forwarders:true")
val jCode = List("interface A { default int m() { return 1; } }" -> "A.java")