Сопоставление с шаблоном и вывод типа в Scala

Может ли кто-нибудь объяснить, почему компилируется следующий код?

Option("foo") match {
  case x: List[String] => println("A")
  case _ => println("B")
}

Это дает мне (ожидаемое) предупреждение об удалении типа, но оно все равно компилируется. Я ожидал, что это вызовет ошибку типа, как если бы я нашел "foo" вместо Option("foo").

Спасибо!


person sidnair09    schedule 09.09.2012    source источник
comment
Похоже на ошибку. Я бы доложил об этом.   -  person kiritsuku    schedule 10.09.2012


Ответы (3)


Код прокомментирован, так что давайте посмотрим на это:

  /** If we can absolutely rule out a match we can fail early.
   *  This is the case if the scrutinee has no unresolved type arguments
   *  and is a "final type", meaning final + invariant in all type parameters.
   */

Обратите внимание, что, например, None не является окончательным. Я точно знаю?

Если вы когда-нибудь попробуете scalac -Ypatmat-debug, комментарий здесь может помочь:

https://github.com/scala/scala/pull/650

Достижимость почти достижима:

https://issues.scala-lang.org/browse/SI-6146

Но я не вижу никаких обещаний относительно того, о чем можно было бы когда-нибудь предупредить. По соображениям производительности? Можно также сказать, почему он должен предупреждать об instanceOf [Foo [_]]?

На данный момент разделы спецификации 8.2 - 8.4 объясняют, почему сопоставление с Foo [a] интересно (из-за ограничений, которые a получает). Думаю, я пойду это еще раз. После кофе.

trait Foo[+A]
final class Fuzz[+A] extends Foo[A]
final object Fooz extends Foo[Nothing]
object Futz extends Foo[Nothing]

//error
Fooz match {
  case x: List[_] => println("A")
  case _ => println("B")
}
//no error
Futz match { ... }
person som-snytt    schedule 10.09.2012
comment
Приятно, подумал, что это будет какая-то причуда с сопоставителем шаблонов, но вчера поздно вечером не заметил :-) - person timothy; 10.09.2012

Я предполагаю, что компилятор рассматривает и Option, и List как Product, поэтому он компилируется. Как вы говорите, ожидается предупреждение об стирании типа. Вот пример, в котором используется другой продукт:

scala> Option("foo") match {
 | case x: Tuple2[String,String] => println("TUPLE")
 | case x: List[String] => println("LIST")
 | case _ => println("OTHER")
 | }
<console>:9: warning: non variable type-argument String in type pattern (String, String)       is unchecked since it is eliminated by erasure
          case x: Tuple2[String,String] => println("TUPLE")
                  ^
<console>:10: warning: non variable type-argument String in type pattern List[String] is unchecked since it is eliminated by erasure
          case x: List[String] => println("LIST")
                  ^

ОБНОВЛЕНИЕ с классами case (из-за комментария ниже):

scala> case class Foo(bar: Int)
defined class Foo

scala> val y: Product = Foo(123)
y: Product = Foo(123)
person timothy    schedule 09.09.2012
comment
Похоже, это не имеет отношения к Product. Я заменил Option("foo") своим собственным классом case, принимающим единственный параметр, и ошибки нет. - person ghik; 10.09.2012
comment
Errr, классы case автоматически расширяют Product. См. Ответ отредактировать. - person timothy; 10.09.2012
comment
Ну ладно, но на самом деле это не обязательно должен быть класс case. Обычный не финальный класс также не вызывает ошибки. - person ghik; 10.09.2012
comment
@ user1296806 прав, дело в дисперсии - это интересный случай. Извините за путаницу; со мной это не случилось вчера поздно вечером! - person timothy; 10.09.2012

Я заметил, что отображается ошибка, когда класс соответствующего значения объявлен как final (и мы знаем, что String является окончательным). Я до сих пор не знаю, почему без него не было бы ошибок.

person ghik    schedule 09.09.2012