Type of type patterns in match blocks


#1

Recently, we observed that the type of a type pattern inside a match block is different to what we expected.
Let’s consider the following match block:

val a: A
a match {
  x: B => ...
}

In Scala 2.12.6, the type of x appears to be A with B now. We would have expected it to be B and we also understand the standard like this: https://scala-lang.org/files/archive/spec/2.12/08-pattern-matching.html#typed-patterns.
This can also be tested in the following minified example:

trait A { def a: Int }
trait B { def b: Int }
val c: A with B = ???
c match {
   case x: B =>
      x.a
}

In Scala 2.12.6, this code compiles, while in Dotty it fails with a compile error (a is not a member of B).

Generally, the feature of mixing outer and inner type appears useful to me, as it allows to omit type refinements like in this example:

val a: Seq[Int] = ???
a match { 
  case x: List[_] => x.head: Int
}

But it also means that a match block behaves quite differently to a PartialFunction.

So is this a bug in the specification or in the implementation?
And what’s the plan with this in Dotty? To me it sounds like in Dotty this would even make more sense as in Scala 2.12 as with is commutative and mixes in types better.


#2

There’s an open issue for this in Dotty: https://github.com/lampepfl/dotty/issues/3208 The consensus so far seems to be that we should imitate the behavior of scalac and update the spec.


#3

Thanks for the clarification, @smarter.


#4

How so? Partial functions are compiled into match blocks (tho the translation isn’t maybe trivial).


#5

indeed, PartialFunctions appear to work similarly, as this code also compiles:

val x: PartialFunction[Seq[Int], Int] = {
   case z: List[_] => z.head: Int
}

So, I think I was wrong about this difference.