読者です 読者をやめる 読者になる 読者になる

Scala の match の謎の挙動

先日遭遇した不可解な挙動について。まずは以下のソース。実行すると結果はどうなるか。

trait A
class B extends A
trait C extends A
class D extends B with C

def check(x: A) = x match {
  case c: C => "C"
  case _ => "x"
}

println(check(new D))

結果:

C

D クラスは C トレイトを継承しているので当然の結果。
では、case を1つ足した以下のコードはどうなるか。

trait A
class B extends A
trait C extends A
class D extends B with C

def check(x: A) = x match {
  case b: B if false => "B"
  case c: C => "C"
  case _ => "x"
}

println(check(new D))

B クラスの case を追加したが、if false としているのでこの case は反映されないはず。
ちなみに直接 false としているけど実際に遭遇したときはちゃんと条件があって、それが false の時に発生したってだけで例として示すのに単純に false を使った。
普通に考えたら結果は変わらないはず…。

結果:

x

!? どうしてこうなった!

match の詳細な仕様は把握していない、というか一応仕様書読んでみたけど私の英語力ではちゃんと解読できなかったので、これが仕様かバグなのかはわからないけど、明らかに直感に反する挙動な気がする。
これが仕様なのかバグなのか、仕様だとしたらどういったルールの元このような挙動になるのか、詳しい方がいましたら是非教えてください…。

追記
試しに check メソッドjadデコンパイルしてみたら以下のようになった。

public String check(A x) {
  A a = x;
  return (a instanceof B) ? gd1$1((B)a) ? "B" : "x" : (a instanceof C) ? "C" : "x";
}

うーん、case b のパターン部分と if 部分の条件が分離してしまっている。これだと一度 b のパターンにマッチしてしまったら if で弾かれても次のパターンに行かない。
以下のようになるのが正しいのではないだろうか。

public String check(A x) {
  A a = x;
  return (a instanceof B) && gd1$1((B)a) ? "B" : (a instanceof C) ? "C" : "x";
}

やっぱりバグなのかなぁ。