Skip to content

Unsoundness with distribution of intersection over covariant types #23435

Open
@SimonGuilloud

Description

@SimonGuilloud

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 Eis 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:varianceIssues related to covariance & contravariance.itype:bugitype:soundnessSoundness bug (it lets us compile code that crashes at runtime with a ClassCastException)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions