(Not a full answer, but a few notes and links; Maybe it can serve as a starting point for someone else)
In 2.12.13, the compiler seems to be able to prove that F[_ <: X]
and F[X]
are the same type if X
occurs in covariant position:
println(implicitly[Option[_ <: ChildA] =:= Option[ChildA]])
This compiles (with warnings, but it compiles):
trait Parent
class ChildA extends Parent
class ChildB extends Parent
def whatIsInside(opt: Option[_ <: Parent]): String = {
opt match {
case _: Option[ChildA] => "ChildA"
case _: Option[ChildB] => "ChildB"
case None => "None"
case _ => throw new Error("meh")
}
}
This does not compile:
trait Parent
class ChildA extends Parent
class ChildB extends Parent
def whatIsInside(opt: Option[_ <: Parent]): String = {
opt match {
case _: Option[_ <: ChildA] => "ChildA"
case _: Option[_ <: ChildB] => "ChildB"
case None => "None"
case _ => throw new Error("meh")
}
}
So, it seems that it must have something to do with the bounds inference for the synthetic _$2
type-variable.
Also, this compiles:
def testConforms[A >: Nothing <: ChildA](ca: Option[A]): Option[_ <: Parent] = ca
so, unless I'm misinterpreting the spec:
If there exists a substitution σ
over the type variables a_i,…,a_n
such that σT
conforms to pt
, one determines the weakest subtype constraints C1
over the type variables a1,…,an
such that C0 ∧ C1
implies that T
conforms to [the expected type] pt
.
, the pt
would be Option[_ <: Parent]
, then a1,...,an
would be the single synthetic type _$2
, and the constraints _$2 >: Nothing <: ChildA
should make the type Option[_$2]
conform to Option[_ <: Parent]
. So, it seems that it should work, but doesn't.
Bonus
If you just wanted to make it work, then just skip all those wildcards, they aren't needed:
trait Parent
class ChildA extends Parent
class ChildB extends Parent
def whatIsInside(opt: Option[Parent]): String = {
opt match {
case Some(_: ChildA) => "ChildA"
case Some(_: ChildB) => "ChildB"
case None => "None"
case _ => throw new Error("meh")
}
}
whatIsInside(Some(new ChildA))
whatIsInside(Some(new ChildB))
whatIsInside(None)