diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala | 25 | ||||
-rw-r--r-- | test/files/neg/bug3683a.check | 6 | ||||
-rw-r--r-- | test/files/neg/bug3683a.flags | 1 | ||||
-rw-r--r-- | test/files/neg/bug3683a.scala | 20 | ||||
-rw-r--r-- | test/files/neg/bug3683b.check | 6 | ||||
-rw-r--r-- | test/files/neg/bug3683b.scala | 21 | ||||
-rw-r--r-- | test/files/neg/exhausting.check | 9 | ||||
-rw-r--r-- | test/files/neg/exhausting.scala | 7 |
8 files changed, 82 insertions, 13 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala index 6141b2333c..b880dea858 100644 --- a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala +++ b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala @@ -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) => { diff --git a/test/files/neg/bug3683a.check b/test/files/neg/bug3683a.check new file mode 100644 index 0000000000..a1c5b9c56d --- /dev/null +++ b/test/files/neg/bug3683a.check @@ -0,0 +1,6 @@ +bug3683a.scala:14: error: match is not exhaustive! +missing combination XX + + w match { + ^ +one error found diff --git a/test/files/neg/bug3683a.flags b/test/files/neg/bug3683a.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/bug3683a.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/neg/bug3683a.scala b/test/files/neg/bug3683a.scala new file mode 100644 index 0000000000..6d1915213a --- /dev/null +++ b/test/files/neg/bug3683a.scala @@ -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) + } + } +}
\ No newline at end of file diff --git a/test/files/neg/bug3683b.check b/test/files/neg/bug3683b.check new file mode 100644 index 0000000000..3952633d1d --- /dev/null +++ b/test/files/neg/bug3683b.check @@ -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 diff --git a/test/files/neg/bug3683b.scala b/test/files/neg/bug3683b.scala new file mode 100644 index 0000000000..646e418121 --- /dev/null +++ b/test/files/neg/bug3683b.scala @@ -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) + } + } +}
\ No newline at end of file diff --git a/test/files/neg/exhausting.check b/test/files/neg/exhausting.check index 6383a6eaca..d3f2251f79 100644 --- a/test/files/neg/exhausting.check +++ b/test/files/neg/exhausting.check @@ -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 diff --git a/test/files/neg/exhausting.scala b/test/files/neg/exhausting.scala index 8b1ea817e4..0741d7467b 100644 --- a/test/files/neg/exhausting.scala +++ b/test/files/neg/exhausting.scala @@ -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, _) => () |