Open
Description
Compiler version
3.3.6 and 3.7.0
Minimized code
trait L[+A]{val a:A}
trait R[+B]{val b: B}
class LR(val a: Int, val b: String) extends L[Int] with R[String]
type E[+A] = L[A] | R[A]
val x: E[Int] & E[String] = LR(4, "hi")
val y: E[Int&String] = x
val z = y match
case l : L[Int&String] => l.a
case r : R[Int&String] => r.b
z:String // java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String
Expectation
I expect line val y: E[Int&String] = x
to raise an error.
The problem is due to the normalization
E[Int] & E[String] =:= E[Int&String]
as described in https://dotty.epfl.ch/docs/reference/new-types/intersection-types-spec.html
"if C is covariant, C[A] & C[B] ~> C[A & B]
"
I found this rule logically dubious (it certainly does not hold in a set-theoretic model), even if it is convenient for typechecking. So I tried to explicitely construct an unsoundness.
Note that the same issue happen if E
is replaced by a trait with
sealed trait E[+A]
trait L[+A] extends E[A] :
def a : A
trait R[+A] extends E[A] :
def b : A
class LR(val a: Int, val b: String) extends L[Int] with R[String]
summon[(E[Int] & E[String]) =:= E[Int&String]]
val x: E[Int] & E[String] = LR(4, "hi")
val y: E[Int&String] = x
val z = y match
case l : L[Int&String] => l.a
case r : R[Int&String] => r.b
z:String
Note also that the matching over x
is proven exhaustive.