From a980fded6806f83bebe2ced31ab1ed70926254b2 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Tue, 30 Aug 2016 16:26:05 +0200 Subject: SD-143 error for super calls that cannot be implemented correctly If a call super[T].m resolves to a method A.m where A is a class, but not the direct superclass of the current class, there is no way to emit an invocation of A.m: `invokespecial A.m` will resolve to B.m where B is the superclass of the current class. This commit adds an error message in this case. Note that this is similar to an existing error message for qualified super calls to a non-direct superclass: class A { def m = 1 } class B extends A { override def m = 2 } class C extends B { override def m = super[A].m } Gives "error: A does not name a parent class of class C". If the user means to call method m in the superclass, he can write an unqualified `super.m`. An similar error message is introduced if A is a Java-defined interface (and m is a default method), and A is not a direct parent of the current class. In this case `invokespecial A.m` is invalid bytecode. The solution is to add A as a direct parent of the current class. --- .../scala/tools/nsc/typechecker/SuperAccessors.scala | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala') diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 49d892e04f..a38d21fe10 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -146,7 +146,22 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT val intermediateClasses = clazz.info.baseClasses.tail.takeWhile(_ != sym.owner) intermediateClasses.map(sym.overridingSymbol).find(s => s.isDeferred && !s.isAbstractOverride && !s.owner.isTrait).foreach { absSym => - reporter.error(sel.pos, s"${sym.fullLocationString} cannot be directly accessed from ${clazz} because ${absSym.owner} redeclares it as abstract") + reporter.error(sel.pos, s"${sym.fullLocationString} cannot be directly accessed from $clazz because ${absSym.owner} redeclares it as abstract") + } + } else if (mix != tpnme.EMPTY) { + // 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. + // 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. + val owner = sym.owner + if (!owner.isTrait && owner != 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.") + } else if (owner.isInterface && owner.isJavaDefined && !clazz.parentSymbols.contains(owner)) { + reporter.error(sel.pos, s"unable to emit super call unless interface ${owner.name} (which declares $sym) is directly extended by $clazz.") } } -- cgit v1.2.3