False error in pattern matching "pattern's type TC[_] is more specialized than the right hand side expression's type TC[?]"
Compiler version
3.7.0 (and latest nightly)
Minimized code
//> using scala 3.7.0
trait TC[A]
object Test:
def test1(foo: TC[?]): Unit = foo match
case _: TC[?] => // ok
def test2: Unit =
for
(_: TC[?]) <- List[TC[?]]() // error
do ()
Output
-- Error: try/ttp.scala:10:7 ---------------------------------------------------
10 | (_: TC[?]) <- List[TC[?]]() // error
| ^^^^^^^^
|pattern's type TC[_] is more specialized than the right hand side expression's type TC[?]
|
|If the narrowing is intentional, this can be communicated by adding the `case` keyword before the full pattern,
|which will result in a filtering for expression (using `withFilter`).
|This patch can be rewritten automatically under -rewrite -source 3.2-migration.
Expectation
No error, the pattern is not more specialized and will always match.
The problem is easier to debug if we give a name to the type pattern instead of using ?:
for
(_: TC[xx]) <- List[TC[?]]() // error
do ()
10 | (_: TC[xx]) <- List[TC[?]]() // error
| ^^^^^^^^^
|pattern's type TC[xx] is more specialized than the right hand side expression's type TC[?]
The subtype check that fails is https://github.com/scala/scala3/blob/515c3e1c166b308554e6f9bdb5bf43c591f89652/compiler/src/dotty/tools/dotc/typer/Checking.scala#L1031 because pat is Typed(Ident(_),AppliedTypeTree(Ident(TC),List(Bind(xx,Ident(_))))) with pat.tpe being AppliedType(TypeRef(ThisType(TypeRef(NoPrefix,module class <empty>)),trait TC),List(TypeRef(NoPrefix,type xx)))
In both cases, the problem is that pattern matching introduces a local TypeRef and symbol to represent the pattern-bound type variable (if we write ? then we get a pattern-bound type variable called _ which is a bit confusing). They are introduced in:
https://github.com/scala/scala3/blob/515c3e1c166b308554e6f9bdb5bf43c591f89652/compiler/src/dotty/tools/dotc/typer/Typer.scala#L2814 for named pattern-bound type variables and in
https://github.com/scala/scala3/blob/515c3e1c166b308554e6f9bdb5bf43c591f89652/compiler/src/dotty/tools/dotc/typer/Typer.scala#L3905-L3913 for wildcards (the comment claims that they are subsequently eliminated by indexPattern but this is no longer the case since https://github.com/scala/scala3/commit/7801c578301201e3c4c9663a529b3fddec3191ea which harmonized non-wildcard and wildcard handling).
This could be fixed by carefully transforming pattern types in checkIrrefutable to replace TypeRefs of pattern-bound type variables by their bounds. That feels a bit ad-hoc and inefficient, but I can't think of a more general fix that wouldn't break actual use of pattern-bound type variables.
Workaround
Define type AnyTC = TC[?] and match on AnyTC.