Skip to content

Commit c00dda3

Browse files
committed
Check exhaustivity of any case class
1 parent 482107b commit c00dda3

File tree

7 files changed

+31
-8
lines changed

7 files changed

+31
-8
lines changed

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -841,8 +841,6 @@ object SpaceEngine {
841841
if Nullables.unsafeNullsEnabled then self.stripNull() else self
842842

843843
private def exhaustivityCheckable(sel: Tree)(using Context): Boolean = trace(i"exhaustivityCheckable($sel ${sel.className})") {
844-
val seen = collection.mutable.Set.empty[Symbol]
845-
846844
// Possible to check everything, but be compatible with scalac by default
847845
def isCheckable(tp: Type): Boolean = trace(i"isCheckable($tp ${tp.className})"):
848846
val tpw = tp.widen.dealias.stripUnsafeNulls()
@@ -856,10 +854,7 @@ object SpaceEngine {
856854
}) ||
857855
tpw.isRef(defn.BooleanClass) ||
858856
classSym.isAllOf(JavaEnum) ||
859-
classSym.is(Case) && {
860-
if seen.add(classSym) then productSelectorTypes(tpw, sel.srcPos).exists(isCheckable(_))
861-
else true // recursive case class: return true and other members can still fail the check
862-
}
857+
classSym.is(Case)
863858

864859
!sel.tpe.hasAnnotation(defn.UncheckedAnnot)
865860
&& !sel.tpe.hasAnnotation(defn.RuntimeCheckedAnnot)

i22590.arity2.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
sealed trait T_B
2+
case class CC_A() extends T_B
3+
case class CC_C() extends T_B
4+
5+
sealed trait T_A
6+
case class CC_B[B](a: B,b:T_B) extends T_A
7+
8+
9+
@main def test() = {
10+
val v_a: CC_B[Int] = null
11+
val v_b: Int = v_a match {
12+
case CC_B(12, CC_A()) => 0
13+
case CC_B(_, CC_C()) => 0
14+
}
15+
}

i22590.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
sealed trait T_A
2+
case class CC_B[T](a: T) extends T_A
3+
4+
@main def test() = {
5+
val v_a: CC_B[Int] = CC_B(10)
6+
val v_b: Int = v_a match{
7+
case CC_B(12) => 0
8+
}
9+
}

tests/pos/switches.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class Test {
4242
case IntAnyVal(100) => 2
4343
case IntAnyVal(1000) => 3
4444
case IntAnyVal(10000) => 4
45+
case _ => -1
4546
}
4647
}
4748

tests/warn/i15662.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ case class Composite[T](v: T)
55
def m(composite: Composite[?]): Unit =
66
composite match {
77
case Composite[Int](v) => println(v) // warn: cannot be checked at runtime
8+
case _ => println("OTHER")
89
}
910

1011
def m2(composite: Composite[?]): Unit =

tests/warn/opaque-match.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ def Test[T] =
1313
case _: C => ??? // ok
1414
C() match
1515
case _: O.T => ??? // warn
16+
case _ => ???
1617
C() match
1718
case _: T => ??? // warn
19+
case _ => ???
1820

1921
(??? : Any) match
2022
case _: List[O.T] => ??? // warn

tests/pos/t10373.scala renamed to tests/warn/t10373.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//> using options -Xfatal-warnings -deprecation -feature
1+
//> using options -deprecation -feature
22

33
abstract class Foo {
44
def bar(): Unit = this match {
@@ -7,7 +7,7 @@ abstract class Foo {
77
// Works fine
88
}
99

10-
def baz(that: Foo): Unit = (this, that) match {
10+
def baz(that: Foo): Unit = (this, that) match { // warn: match may not be exhaustive.
1111
case (Foo_1(), _) => //do something
1212
case (Foo_2(), _) => //do something
1313
// match may not be exhaustive

0 commit comments

Comments
 (0)