Why does the following code work when Foo is invariant, but not when it is covariant? The covariant version of Foo produces a type error saying that in the call of useF1, the argument has type Foo[T] but F1 is required. A similar error is produced for useF2.
If the variance annotation is removed from Foo, the code works. The pattern match against F1 exposes the fact that T = Int, so that x has type Foo[Int]. The implicit conversion function is used to convert Foo[Int] to F1 in the argument of useF1. Similarly for F2. What part of this process is different when Foo is covariant, and why?
// A GADT with two constructors
sealed abstract class Foo[+T]
final case class F1() extends Foo[Int]
final case class F2() extends Foo[Unit]
object Example {
// A Foo[Int] can only be an F1
implicit def refineGADT(x : Foo[Int]) : F1 = x.asInstanceOf[F1]
// A Foo[Unit] can only be an F2
implicit def refineGADT(x : Foo[Unit]) : F2 = x.asInstanceOf[F2]
def useF1(x : F1) = ()
def useF2(x : F2) = ()
def demo[T](x : Foo[T]) = x match {
case F1() => useF1(x) // error
case F2() => useF2(x) // error
}
}
Although GADTs make subtyping more complicated in general, in this case the only two possible concrete types are Foo[Int] and Foo[Unit], and no subtyping relationship holds between them, so subtyping shouldn't affect this example.