sealed abstract class A
sealed trait Foo{
sealed abstract class B extends A
final class C extends B
final class D extends B
final class E extends A
}
object Main extends Foo{
def bar = (new C(): A) match{
case _: C => "c"
case _: D => "d"
case _: E => "e"
}
}
编译说
[warn] A.scala:12: match may not be exhaustive. [warn] It would fail on the following inputs: C(), D(), E() [warn] def bar = (new C(): A) match{
但Main#bar
成功并返回"c"
。
我做错了吗?或者这是scalac bug?
答案 0 :(得分:4)
不同Foo的路径依赖性Cs是不同的。
这可能是它抱怨的原因。 (警告中存在已知的错误。)(例如this one.)
final class C extends B {
def f(c: C) = "ok" // adding this to C
}
object Test extends App {
val f = new Foo { }
Console println (X bar new f.C())
val c = new f.C
c.f(X.c) // doesn't compile
}
object X extends Foo{
val c = new C
def bar(a: A) = a match {
case _: C => "c"
case _: D => "d"
case _: E => "e"
}
}
这更好地代表了你能做的事情,并使警告沉默:
def bar(a: A) = a match {
case _: Foo#C => "c" // instanceof Foo$C etc
case _: Foo#D => "d"
case _: Foo#E => "e"
}
更新:在查看不相关的stackoverflow时,还有更多内容,即an open issue I happened to notice。 (实际的,而不是Q& A网站。)
简而言之,它尝试将嵌套类中的“外部”指针优化到它们的封闭实例,如果发生这种情况,则不能再在匹配中包含外部实例。通常它会测试instanceof和它的外部是正确的。
将bar
移入特征并删除final
会禁用优化并修复匹配。
public static java.lang.String bar(badseal.Foo, badseal.A);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=4, args_size=2
0: aload_1
1: astore_2
2: aload_2
3: instanceof #9 // class badseal/Foo$D
6: ifeq 26
9: aload_2
10: checkcast #9 // class badseal/Foo$D
13: invokevirtual #13 // Method badseal/Foo$D.badseal$Foo$D$$$outer:()Lbadseal/Foo;
16: aload_0
17: if_acmpne 26
20: ldc #15 // String d
如果内部类是最终的,scalac至少会抱怨:
badseal.scala:17: warning: The outer reference in this type test cannot be checked at run time.
case _: C => "c"
^
但是如果匹配在对象中,则此消息的启发式似乎会中断,因此您不再看到它。
sealed abstract class A
trait Foo {
sealed abstract class B extends A
class C extends B
class D extends B
class E extends A
def bar(a: A) = a match {
case _: C => "c"
case _: D => "d"
case _: E => "e"
}
}
object X extends Foo
然后
val f1 = new Foo { }
Console println X.bar(new f1.C)
正确警告并正确抛出。
apm@mara:~/tmp$ skalac -unchecked badseal.scala ; skala badseal.Test
badseal.scala:11: warning: match may not be exhaustive.
It would fail on the following inputs: C(), D(), E()
def bar(a: A) = a match {
^
one warning found
scala.MatchError: badseal.Foo$C@756bc09d (of class badseal.Foo$C)