summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2012-06-10 17:51:21 +0200
committerJason Zaugg <jzaugg@gmail.com>2012-06-17 14:42:49 +0200
commit72ee06de4cc0b8c12acf07c892302a3043a1e578 (patch)
tree153a7db5f3af07974b6c797b363349653c315c48
parent277dc7cf43566f8294bde4143107d9bfaa59e8e3 (diff)
downloadscala-72ee06de4cc0b8c12acf07c892302a3043a1e578.tar.gz
scala-72ee06de4cc0b8c12acf07c892302a3043a1e578.tar.bz2
scala-72ee06de4cc0b8c12acf07c892302a3043a1e578.zip
SI-4989 Reject super.x if an intermediate class declares x abstract.
This is in line with Java's treatment. Without this, an AbstractMethodError is thrown at runtime.
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala8
-rw-r--r--test/files/neg/t4989.check7
-rw-r--r--test/files/neg/t4989.scala68
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
+ }
+}