Closed
Description
class Base
class Sub extends Base
trait A[+T] {
def get(f: T => Boolean): Unit = {}
}
trait B extends A[Base] {
override def get(f: Base => Boolean): Unit = f(new Base)
}
class C extends B with A[Sub]
object Test {
def main(args: Array[String]): Unit = {
val c = new C
c.get((x: Sub) => true) // ClassCastException: Base cannot be cast to Sub
}
}
In Scala 2 this is rejected (at erasure):
error: name clash between inherited members:
def get(f: Sub => Boolean): Unit in trait A and
override def get(f: Base => Boolean): Unit in trait B
have same type after erasure: (f: Function1): Unit
class C extends B with A[Sub]
^
1 error
And a simplified example is rejected by dotty at RefChecks in checkMemberTypesOK:
class Base
class Sub extends Base
trait A[+T] {
def get: T = ???
}
trait B extends A[Base] {
override def get: Base = new Base
}
class C extends B with A[Sub]
-- Error: try/dg3.scala:12:6 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
12 |class C extends B with A[Sub]
| ^
| method get in trait B is not a legal implementation of `get` in class C
| its type => Base
| does not conform to => Sub
The difference is that all parameter-less overrides are considered matching denotations (since they can never be valid overloads), but in the original example, from the point of view of C, the get
in A
and the one in B
are overloads, since they don't have matching signatures as seen from C.
Hopefully this is fixable by tweaking the checkMemberTypesOK logic but I don't have the bandwidth to investigate this for now, do you think you could take a look @odersky ?