@@ -115,15 +115,39 @@ class SuperAccessors(thisPhase: DenotTransformer) {
115115 sel.sourcePos)
116116 else ctx.log(i " ok super $sel ${sym.showLocated} $member $clazz ${member.isIncompleteIn(clazz)}" )
117117 }
118- else if (mix.name.isEmpty && ! (sym.owner is Trait ))
119- // SI-4989 Check if an intermediate class between `clazz` and `sym.owner` redeclares the method as abstract.
120- for (intermediateClass <- clazz.info.baseClasses.tail.takeWhile(_ != sym.owner)) {
121- val overriding = sym.overridingSymbol(intermediateClass)
122- if ((overriding is (Deferred , butNot = AbsOverride )) && ! (overriding.owner is Trait ))
123- ctx.error(
124- s " ${sym.showLocated} cannot be directly accessed from ${clazz} because ${overriding.owner} redeclares it as abstract " ,
118+ else {
119+ val owner = sym.owner
120+ if (! owner.is(Trait )) {
121+ if (mix.name.isEmpty) {
122+ // scala/bug#4989 Check if an intermediate class between `clazz` and `sym.owner` redeclares the method as abstract.
123+ for (intermediateClass <- clazz.info.baseClasses.tail.takeWhile(_ != sym.owner)) {
124+ val overriding = sym.overridingSymbol(intermediateClass)
125+ if ((overriding is (Deferred , butNot = AbsOverride )) && ! (overriding.owner is Trait ))
126+ ctx.error(
127+ s " ${sym.showLocated} cannot be directly accessed from ${clazz} because ${overriding.owner} redeclares it as abstract " ,
128+ sel.sourcePos)
129+ }
130+ } else {
131+ // scala/scala-dev#143:
132+ // a call `super[T].m` that resolves to `A.m` cannot be translated to correct bytecode if
133+ // `A` is a class (not a trait / interface), but not the direct superclass. Invokespecial
134+ // would select an overriding method in the direct superclass, rather than `A.m`.
135+ // We allow this if there are statically no intervening overrides.
136+ def hasClassOverride (member : Symbol , subCls : ClassSymbol ): Boolean = {
137+ if (subCls == defn.ObjectClass || subCls == member.owner) false
138+ else if (member.overridingSymbol(subCls).exists) true
139+ else hasClassOverride(member, subCls.superClass.asClass)
140+ }
141+ val superCls = clazz.asClass.superClass.asClass
142+ if (owner != superCls && hasClassOverride(sym, superCls)) {
143+ ctx.error(
144+ hl """ Super call cannot be emitted: the selected $sym is declared in $owner, which is not the direct superclass of $clazz.
145+ |An unqualified super call (super. ${sym.name}) would be allowed. """ ,
125146 sel.sourcePos)
147+ }
148+ }
126149 }
150+ }
127151 if (name.isTermName && mix.name.isEmpty &&
128152 ((clazz is Trait ) || clazz != ctx.owner.enclosingClass || ! validCurrentClass))
129153 superAccessorCall(sel)(ctx.withPhase(thisPhase.next))
0 commit comments