Open
Description
scalafiddle; repros on 2.12.8 and 2.13.0
sealed trait A[+T]
case class A1[+T](t : T ) extends A[T]
case class A2[+T](t1: T, t2: T) extends A[T]
sealed trait B[+T] {
type AA[+U] <: A[U]
def a: AA[T]
}
object B {
type Aux[+_A[+_], +T] = B[T] { type AA[+U] <: _A[U] }
object Aux {
def unapply[_A[+U] <: A[U], T](b: Aux[_A, T]): Option[_A[T]] = Some(b.a)
}
def apply[_A[+U] <: A[U], T](_a: _A[T]): Aux[_A, T] =
new B[T] { type AA[+U] = _A[U] ; val a: _A[T] = _a }
def unapply[T](b: B[T]): Option[b.AA[T]] = Some(b.a)
}
def foo[T](b: B[T]) = b match {
case B(A1(t)) ⇒ t
case B(A2(t, _)) ⇒ t
}
def foo2[_A[+U] <: A[U], T](b: B.Aux[_A, T]) = b match {
case B.Aux(a @ A1(_ )) ⇒ a.t
case B.Aux(a @ A2(_, _)) ⇒ a.t1 // 👎 (false-positive): unreachable code
}
def foo3[_A[+U] <: A[U], T](b: B.Aux[_A, T]) = b match {
case B.Aux(a: A1[T]) ⇒ a.t
case B.Aux(a: A2[T]) ⇒ a.t1 // 👎 (false-positive): unreachable code
}
def foo4[T](b: B[T]) = b match {
case B(A1(t)) ⇒ t // 👎 (false-negative): incomplete match
}
val b1: B.Aux[A1, Int] = B(A1(111))
val b2: B.Aux[A2, Int] = B(A2(222, 333))
println(s"${foo (b1)} ${foo (b2)}")
println(s"${foo2(b1)} ${foo2(b2)}")
println(s"${foo3(b1)} ${foo3(b2)}")
Compilation generates false-positive warnings as annotated above:
[warn] case B.Aux(a @ A2(_, _)) ⇒ a.t1 // 👎 (false-positive): unreachable code
[warn] ^
[warn] case B.Aux(a: A2[T]) ⇒ a.t1 // 👎 (false-positive): unreachable code
[warn] ^
(scalafiddle doesn't display these for some reason)
All three println
s work as expected, reaching the "unreachable code":
111 222
111 222
111 222
The compiler also fails to flag the inexhaustive match in foo4
.