summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala8
1 files changed, 7 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.")