Massively simplified the exhaustiveness checker with no measurable loss

of fidelity.  I might be the only one who can be unsurprised by such a
bloody diff: anyone else would rightly say "how on earth..." No review.

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@23191 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
extempore 2010-10-05 02:59:06 +00:00
parent b8cde80af3
commit db8f536c20
4 changed files with 69 additions and 25 deletions

View File

@ -145,7 +145,7 @@ trait MatrixAdditions extends ast.TreeDSL
self: MatchMatrix =>
import self.context._
/** Exhaustiveness checking requires looking for sealed classes
* and if found, making sure all children are covered by a pattern.
*/
@ -155,32 +155,11 @@ trait MatrixAdditions extends ast.TreeDSL
import Flags.{ MUTABLE, ABSTRACT, SEALED, TRANS_FLAG }
private case class Combo(index: Int, sym: Symbol) {
val isBaseClass = sym.tpe.baseClasses.toSet
// is this combination covered by the given pattern?
def isCovered(p: Pattern) = {
def cmpSymbols(t1: Type, t2: Type) = t1.typeSymbol eq t2.typeSymbol
def coversSym = {
val tpe = decodedEqualsType(p.tpe)
lazy val lmoc = sym.companionModule
val symtpe =
if ((sym hasFlag Flags.MODULE) && (lmoc ne NoSymbol))
singleType(sym.tpe.prefix, lmoc) // e.g. None, Nil
else sym.tpe
/** Note to Martin should you come through this way: this
* logic looks way overcomplicated for the intention, but a little
* experimentation showed that at least most of it is serving
* some necessary purpose. It doesn't seem like much more than
* "sym.tpe matchesPattern tpe" ought to be necessary though.
*
* For the time being I tacked the matchesPattern test onto the
* end to address #3097.
*/
(tpe.typeSymbol == sym) ||
(symtpe <:< tpe) ||
(symtpe.parents exists (x => cmpSymbols(x, tpe))) || // e.g. Some[Int] <: Option[&b]
((tpe.prefix memberType sym) <:< tpe) || // outer, see combinator.lexical.Scanner
(symtpe matchesPattern tpe)
}
def coversSym = isBaseClass(decodedEqualsType(p.tpe).typeSymbol)
cond(p.tree) {
case _: UnApply | _: ArrayValue => true

View File

@ -0,0 +1,24 @@
exhausting.scala:20: error: match is not exhaustive!
missing combination * Nil
def fail1[T](xs: List[T]) = xs match {
^
exhausting.scala:24: error: match is not exhaustive!
missing combination Nil
def fail2[T](xs: List[T]) = xs match {
^
exhausting.scala:27: error: match is not exhaustive!
missing combination Bar3
def fail3[T](x: Foo[T]) = x match {
^
exhausting.scala:31: error: match is not exhaustive!
missing combination Bar1 Bar2
missing combination Bar1 Bar3
missing combination Bar2 Bar1
missing combination Bar2 Bar2
def fail4[T](xx: (Foo[T], Foo[T])) = xx match {
^
four errors found

View File

@ -0,0 +1 @@
-Xfatal-warnings

View File

@ -0,0 +1,40 @@
object Test {
sealed abstract class Foo[T]
case object Bar1 extends Foo[Int]
case object Bar2 extends Foo[String]
case object Bar3 extends Foo[Any]
def ex1[T](xs: List[T]) = xs match {
case ys: List[_] => "ok"
}
def ex2[T](xx: (Foo[T], Foo[T])) = xx match {
case (Bar1, Bar1) => ()
case (_, Bar1) => ()
case (_, Bar3) => ()
case (_, Bar2) => ()
}
def ex3[T](xx: (Foo[T], Foo[T])) = xx match {
case (_: Foo[_], _: Foo[_]) => ()
}
def fail1[T](xs: List[T]) = xs match {
case Nil => "ok"
case x :: y :: Nil => "ok"
}
def fail2[T](xs: List[T]) = xs match {
case _ :: _ => "ok"
}
def fail3[T](x: Foo[T]) = x match {
case Bar1 => "ok"
case Bar2 => "ok"
}
def fail4[T](xx: (Foo[T], Foo[T])) = xx match {
case (Bar1, Bar1) => ()
case (Bar2, Bar3) => ()
case (Bar3, _) => ()
}
def main(args: Array[String]): Unit = {
}
}