Why does the trait B in the following example compile with a self-type but does not compile without it? Is there a simple explanation for this compiler behaviour? Thanks!
Welcome to Scala 2.13.3 (OpenJDK 64-Bit Server VM, Java 14.0.1).
Type in expressions for evaluation. Or try :help.
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait A { type T = Nothing }
trait B extends A { override type T = String }
// Exiting paste mode, now interpreting.
trait B extends A { override type T = String }
^
<pastie>:2: error: incompatible type in overriding
type T = Nothing (defined in trait A)
(Equivalent type required when overriding a type alias.)
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait A {
self: AnyRef =>
type T = Nothing
}
trait B extends A {
self: AnyRef =>
override type T = String
}
// Exiting paste mode, now interpreting.
trait A
trait B
When B is a trait it may still be somewhat sound because apparently those overrides are still checked afterwards:
scala> trait A {
| self: AnyRef =>
| type T = Int
| def foo: T = 42
| }
|
| trait B extends A {
| self: AnyRef =>
| override type T = String
| override def foo: T = "foo"
| }
trait A
trait B
scala> val a: A = new B{}
^
error: incompatible type in overriding
type T = Int (defined in trait A)
with override type T = String (defined in trait B) (Equivalent type required when overriding a type alias.);
other members with override errors are: foo
However when B is a class it’s clear that this is a bug:
scala> trait A {
| self: AnyRef =>
| type T = Int
| def foo: T = 42
| }
|
| class B extends A {
| self: AnyRef =>
| override type T = String
| override def foo: T = "foo"
| }
trait A
class B
scala> val a: A = new B()
val a: A = B@57bd5942
scala> a.foo
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:99)
at B.foo(<console>:6)
... 40 elided