diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 08dd47af56c2..a19f35a9cd9a 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -361,5 +361,14 @@ object NameOps { case raw.BANG => UNARY_! case _ => name } + + /** If this is a super accessor name, its underlying name, which is the name + * of the method that the super accessor forwards to. + */ + def originalOfSuperAccessorName: TermName = name match + case SuperAccessorName(name1) => name1.originalOfSuperAccessorName + case ExpandedName(_, name1) => name1.originalOfSuperAccessorName + case ExpandPrefixName(_, name1) => name1.originalOfSuperAccessorName + case _ => name } } diff --git a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala index 47422512823e..621935df6bb8 100644 --- a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala +++ b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala @@ -118,7 +118,10 @@ object ResolveSuper { report.error(IllegalSuperAccessor(base, memberName, targetName, acc, accTp, other.symbol, otherTp), base.srcPos) bcs = bcs.tail } - assert(sym.exists, i"cannot rebind $acc, ${acc.targetName} $memberName") - sym + sym.orElse { + val originalName = acc.name.asTermName.originalOfSuperAccessorName + report.error(em"Member method ${originalName.debugString} of mixin ${acc.owner} is missing a concrete super implementation in $base.", base.srcPos) + acc + } } } diff --git a/tests/neg/i11170.check b/tests/neg/i11170.check new file mode 100644 index 000000000000..dc54df923e74 --- /dev/null +++ b/tests/neg/i11170.check @@ -0,0 +1,4 @@ +-- Error: tests/neg/i11170.scala:7:15 ---------------------------------------------------------------------------------- +7 |abstract class A extends U[String] // error + | ^ + | Member method foo of mixin trait U is missing a concrete super implementation in class A. diff --git a/tests/neg/i11170.scala b/tests/neg/i11170.scala new file mode 100644 index 000000000000..25a0a4df3926 --- /dev/null +++ b/tests/neg/i11170.scala @@ -0,0 +1,8 @@ +trait T[X] { + def foo(x: X): X +} +trait U[X] extends T[X] { + abstract override def foo(x: X): X = super.foo(x) +} +abstract class A extends U[String] // error + diff --git a/tests/neg/i11170a.scala b/tests/neg/i11170a.scala new file mode 100644 index 000000000000..5268c506f33f --- /dev/null +++ b/tests/neg/i11170a.scala @@ -0,0 +1,28 @@ +package apackage { + + abstract class A { + protected val x: Int + } + abstract class A2 { + val x: Int + } +} + +package bpackage { + import apackage._ + + trait B extends A { + println(x) + } + trait B2 extends A2 { + println(x) + } +} + +package cpackage { + import apackage._ + import bpackage._ + + case class C(override protected val x: Int) extends A with B // error + case class C2(override val x: Int) extends A2 with B2 +} \ No newline at end of file diff --git a/tests/pos/MathSpec.scala b/tests/pos/MathSpec.scala new file mode 100644 index 000000000000..7c0fdd8a1f3a --- /dev/null +++ b/tests/pos/MathSpec.scala @@ -0,0 +1,21 @@ +trait MathSig { + def sqrt(x: Double): Double +} + +trait MathSpec extends MathSig { + val epsilon = 0.00001 + abstract override def sqrt(x: Double) = { + require(x >= 0) + super.sqrt(x) + } ensuring { result => + (x * x - result).abs < epsilon + } +} + +trait MathImpl extends MathSig { + def sqrt(x: Double): Double = + ??? +} + +object Math extends MathImpl + with MathSpec \ No newline at end of file