diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala | 8 | ||||
-rw-r--r-- | test/files/neg/t4989.check | 7 | ||||
-rw-r--r-- | test/files/neg/t4989.scala | 68 |
3 files changed, 83 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index daae69590f..f67cec730b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -124,7 +124,15 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT !(member.isAbstractOverride && member.isIncompleteIn(clazz))) unit.error(sel.pos, ""+sym.fullLocationString+" is accessed from super. It may not be abstract "+ "unless it is overridden by a member declared `abstract' and `override'"); + } else if (mix == tpnme.EMPTY && !sym.owner.isTrait){ + // SI-4989 Check if an intermediate class between `clazz` and `sym.owner` redeclares the method as abstract. + val intermediateClasses = clazz.info.baseClasses.tail.takeWhile(_ != sym.owner) + intermediateClasses.map(sym.overridingSymbol).find(s => s.isDeferred && !s.isAbstractOverride && !s.owner.isTrait).foreach { + absSym => + unit.error(sel.pos, s"${sym.fullLocationString} cannot be directly accessed from ${clazz} because ${absSym.owner} redeclares it as abstract") + } } + if (name.isTermName && mix == tpnme.EMPTY && (clazz.isTrait || clazz != currentClass || !validCurrentOwner)) ensureAccessor(sel) else sel diff --git a/test/files/neg/t4989.check b/test/files/neg/t4989.check new file mode 100644 index 0000000000..814507fc3f --- /dev/null +++ b/test/files/neg/t4989.check @@ -0,0 +1,7 @@ +t4989.scala:14: error: method print in class A cannot be directly accessed from class C because class B redeclares it as abstract + override def print(): String = super.print() // should be an error + ^ +t4989.scala:18: error: method print in class A cannot be directly accessed from trait T because class B redeclares it as abstract + override def print(): String = super.print() // should be an error + ^ +two errors found diff --git a/test/files/neg/t4989.scala b/test/files/neg/t4989.scala new file mode 100644 index 0000000000..e7ff80ed74 --- /dev/null +++ b/test/files/neg/t4989.scala @@ -0,0 +1,68 @@ +abstract class A0 { + def print(): String +} + +class A extends A0 { + def print(): String = "A" +} + +abstract class B extends A { + def print() : String +} + +class C extends B { + override def print(): String = super.print() // should be an error +} + +trait T extends B { + override def print(): String = super.print() // should be an error +} + +class D extends A { + override def print(): String = super.print() // okay +} + + +// it's okay do this when trait are in the mix, as the +// suitable super accessor methods are used. +object ConcreteMethodAndIntermediaryAreTraits { + trait T1 { + def print(): String = "" + } + + trait T2 extends T1 { + def print(): String + } + + class C3 extends T2 { + def print(): String = super.print() // okay + } +} + +object IntermediaryIsTrait { + class T1 { + def print(): String = "" + } + + trait T2 extends T1 { + def print(): String + } + + class C3 extends T2 { + override def print(): String = super.print() // okay + } +} + +object ConcreteMethodIsTrait { + trait T1 { + def print(): String = "" + } + + abstract class T2 extends T1 { + def print(): String + } + + class C3 extends T2 { + override def print(): String = super.print() // okay + } +} |