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.