Pattern matching seems to work differently depending on if type parameter comes from the enclosing method versus enclosing class. Here is a simplified example where using class type parameter A
trait Base[T]
case class Derived(v: Int) extends Base[Int]
class Test[A] {
def method(arg: Base[A]) = {
arg match {
case Derived(_) => 42
}
}
}
raises error
Error:(7, 12) constructor cannot be instantiated to expected type;
found : A$A87.this.Derived
required: A$A87.this.Base[A]
case Derived(_) => 42
^
whilst it works using method type parameter A
class Test {
def method[A](arg: Base[A]) = {
arg match {
case Derived(_) => 42
}
}
}
SLS 8.4: Pattern Matching Expressions seems to explain what happens in the method scenario
Let be the type of the selector expression and let 1,…, be
the type parameters of all methods enclosing the pattern matching
expression. For every , let be its lower bound and be
its higher bound. Every pattern ∈1,,…, can be typed in two
ways. First, it is attempted to type with as its expected type.
If this fails, is instead typed with a modified expected type ′
which results from by replacing every occurrence of a type
parameter by undefined.
AFAIU, we have
e = arg
a1 = A
T = Base[A]
p1 = Derived(_)
First, it attempts to type with as its expected type, however Derived does not conform to Base[A]. Thus it attempts the second rule
If this fails, is instead typed with a modified expected type ′
which results from by replacing every occurrence of a type
parameter by undefined.
Assuming undefined means something like existential type, then we have T' = Base[_], and because the following indeed holds
implicitly[Derived <:< Base[_]]
then pattern matching in the case of method type parameter becomes something like
class Test {
def method[A](arg: Base[A]) = {
(arg: Base[_]) match {
case Derived(_) => 42
}
}
}
which indeed compiles. This seems to be confirmed by making the class type parameter case successfully compile like so
class Test[A] {
def method(arg: Base[A]) = {
(arg: Base[_]) match {
case Derived(_) => 42
}
}
}
Therefore it seems the second rule is not attempted in type parameter inference for constructor patterns when type parameter comes from enclosing class.
At least these seems to be some of the moving pieces which hopefully someone with actual knowledge can assemble into coherent explanation, as I am mostly guessing.