Description
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
becausepat
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:
scala3/compiler/src/dotty/tools/dotc/typer/Typer.scala
Lines 3905 to 3913 in 515c3e1
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
.