diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala | 8 |
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.") |