Closed
Description
Compiler version
3.0.0...3.1.2-RC2
Minimized code
trait Foo {
opaque type Out = Int
def out1: Out
def out2: Out = out1
}
object Bar extends Foo {
override opaque type Out = String
override def out1 = "abc"
}
@main def run() =
val x = Bar.out2
Output
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:99)
at Bar$.out1(Opaque.scala:9)
at Foo.out2(Opaque.scala:4)
at Foo.out2$(Opaque.scala:1)
at Bar$.out2(Opaque.scala:7)
at Opaque$package$.run(Opaque.scala:13)
at run.main(Opaque.scala:12)
Expectation
This should not compile. Instead a compilation error should be reported just like this happens for non-opaque types, e.g.
trait Foo {
type Out = Int
def out1: Out
def out2: Out = out1
}
object Bar extends Foo {
override type Out = String
override def out1 = "abc"
}
[error] error overriding type Out in trait Foo, which equals Int;
[error] type Out, which equals String has incompatible type
[error] override type Out = String
[error] ^
Alternatively maybe we should consider making opaque types unoverridable? It seems quite strange to me that currently it's possible to override a concrete opaque type although you cannot define an abstract one. Additionally it looks like redefining an opaque type in a subtype works as a hack to leak the opaque type's internals, e.g. the code below compiles successfully unless you comment out the marked line:
trait Foo {
opaque type Out = Int
def out1: Out
def out2: Out = out1
}
object Bar extends Foo {
override opaque type Out = Int // compilation breaks if this line gets commented out
override def out1 = 1
}