Skip to content

Unsound GADT constraints with pattern alternatives #22805

Closed
@lrytz

Description

@lrytz

Originally reported by @szeiger at scala/bug#13090

scala> sealed trait A[T] { def x: T }
     | final case class B(x: String) extends A[String]
     | final case class C(x: Int) extends A[Int]

scala> def f[T](a: A[T]): T = a match { case B(_) | C(_) => "plop" }

scala> f(C(1)) + 1
java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer (java.lang.String and java.lang.Integer are in module java.base of loader 'bootstrap')
  at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:99)

It seems only the constraints from the first pattern are applied, so T = String when typing the case body.

The bug report initially asked if it's possible to support this case:

scala> def f[T](a: A[T]): T = a match {
     |   case B(_) | C(_) => a match { case C(_) => 42 }
     | }
-- [E007] Type Mismatch Error: -------------------------------------------------
2 |  case B(_) | C(_) => a match { case C(_) => 42 }
  |                                             ^^
  |             Found:    (42 : Int)
  |             Required: T
  |
  |             where:    T is a type in method f which is an alias of String

Metadata

Metadata

Assignees

Labels

area:gadtitype:bugitype:soundnessSoundness bug (it lets us compile code that crashes at runtime with a ClassCastException)

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions