Improves exhaustiveness analysis to not warn about types which

cannot match due to nonconformant type parameters.  Also, look at the
different warnings emitted in the test case based on the presence
of a constraint.  Nifty! Closes #3683, no review.

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@23199 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
extempore 2010-10-05 15:34:37 +00:00
parent cf13f6d046
commit 4a5e28e666
8 changed files with 82 additions and 13 deletions

View File

@ -173,19 +173,24 @@ trait MatrixAdditions extends ast.TreeDSL
private def rowCoversCombo(row: Row, combos: List[Combo]) =
row.guard.isEmpty && (combos forall (c => c isCovered row.pats(c.index)))
private def requiresExhaustive(s: Symbol) = {
(s hasFlag MUTABLE) && // indicates that have not yet checked exhaustivity
!(s hasFlag TRANS_FLAG) && // indicates @unchecked
(s.tpe.typeSymbol.isSealed) && {
s resetFlag MUTABLE // side effects MUTABLE flag
!isValueClass(s.tpe.typeSymbol) // but make sure it's not a primitive, else (5: Byte) match { case 5 => ... } sees no Byte
}
private def requiresExhaustive(sym: Symbol) = {
(sym.isMutable) && // indicates that have not yet checked exhaustivity
!(sym hasFlag TRANS_FLAG) && // indicates @unchecked
(sym.tpe.typeSymbol.isSealed) &&
!isValueClass(sym.tpe.typeSymbol) // make sure it's not a primitive, else (5: Byte) match { case 5 => ... } sees no Byte
}
private lazy val inexhaustives: List[List[Combo]] = {
val collected =
for ((pv, i) <- tvars.zipWithIndex ; val sym = pv.lhs ; if requiresExhaustive(sym)) yield
i -> sym.tpe.typeSymbol.sealedDescendants
// let's please not get too clever side-effecting the mutable flag.
val toCollect = tvars.zipWithIndex filter { case (pv, i) => requiresExhaustive(pv.sym) }
val collected = toCollect map { case (pv, i) =>
// okay, now reset the flag
pv.sym resetFlag MUTABLE
// have to filter out children which cannot match: see ticket #3683 for an example
val kids = pv.tpe.typeSymbol.sealedDescendants filter (_.tpe matchesPattern pv.tpe)
i -> kids
}
val folded =
collected.foldRight(List[List[Combo]]())((c, xs) => {

View File

@ -0,0 +1,6 @@
bug3683a.scala:14: error: match is not exhaustive!
missing combination XX
w match {
^
one error found

View File

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

View File

@ -0,0 +1,20 @@
sealed trait Foo
sealed trait Bar extends Foo
sealed trait W[T >: Bar <: Foo]
case class X() extends W[Foo]
case class XX() extends W[Bar]
case class Y() extends W[Bar]
case class Z[T >: Bar <: Foo](
z1: W[T]
) extends W[T]
object Main {
// should warn for not including XX()
def f1(w: W[Bar]): Int = {
w match {
// case XX() => 2
case Y() => 1
case Z(z) => f1(z)
}
}
}

View File

@ -0,0 +1,6 @@
bug3683b.scala:15: error: constructor cannot be instantiated to expected type;
found : X
required: W[Bar]
case X() => 1
^
one error found

View File

@ -0,0 +1,21 @@
sealed trait Foo
sealed trait Bar extends Foo
sealed trait W[T >: Bar <: Foo]
case class X() extends W[Foo]
case class XX() extends W[Bar]
case class Y() extends W[Bar]
case class Z[T >: Bar <: Foo](
z1: W[T]
) extends W[T]
object Main {
// should fail for including X()
def f1(w: W[Bar]): Int = {
w match {
case X() => 1
case XX() => 2
case Y() => 1
case Z(z) => f1(z)
}
}
}

View File

@ -14,11 +14,16 @@ missing combination Bar3
def fail3[T](x: Foo[T]) = x match {
^
exhausting.scala:31: error: match is not exhaustive!
missing combination Bar2 Bar2
def fail4[T <: AnyRef](xx: (Foo[T], Foo[T])) = xx match {
^
exhausting.scala:36: 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 {
def fail5[T](xx: (Foo[T], Foo[T])) = xx match {
^
four errors found
5 errors found

View File

@ -28,7 +28,12 @@ object Test {
case Bar1 => "ok"
case Bar2 => "ok"
}
def fail4[T](xx: (Foo[T], Foo[T])) = xx match {
def fail4[T <: AnyRef](xx: (Foo[T], Foo[T])) = xx match {
case (Bar1, Bar1) => ()
case (Bar2, Bar3) => ()
case (Bar3, _) => ()
}
def fail5[T](xx: (Foo[T], Foo[T])) = xx match {
case (Bar1, Bar1) => ()
case (Bar2, Bar3) => ()
case (Bar3, _) => ()