Skip to content

Commit 1f836e5

Browse files
committed
Fix #4661: Missing unreachable case warnings
1 parent b4670b7 commit 1f836e5

File tree

6 files changed

+97
-25
lines changed

6 files changed

+97
-25
lines changed

compiler/src/dotty/tools/dotc/tastyreflect/CaseDefOpsImpl.scala

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,7 @@ trait CaseDefOpsImpl extends scala.tasty.reflect.CaseDefOps with TastyCoreImpl w
1111
}
1212

1313
object CaseDef extends CaseDefExtractor {
14-
def unapply(x: CaseDef): Option[(Pattern, Option[Term], Term)] = x match {
15-
case x: tpd.CaseDef =>
16-
Some(x.pat, optional(x.guard), x.body)
17-
case _ => None
18-
}
14+
def unapply(x: CaseDef): Some[(Pattern, Option[Term], Term)] = Some(x.pat, optional(x.guard), x.body)
1915
}
2016

2117
}

compiler/src/dotty/tools/dotc/tastyreflect/ConstantOpsImpl.scala

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,11 @@ trait ConstantOpsImpl extends scala.tasty.reflect.ConstantOps with TastyCoreImpl
1313
object Constant extends ConstantModule {
1414

1515
object Unit extends UnitExtractor {
16-
def unapply(x: Constant): Boolean = x match {
17-
case x: Constants.Constant => x.tag == Constants.UnitTag
18-
case _ => false
19-
}
16+
def unapply(x: Constant): Boolean = x.tag == Constants.UnitTag
2017
}
2118

2219
object Null extends NullExtractor {
23-
def unapply(x: Constant): Boolean = x match {
24-
case x: Constants.Constant => x.tag == Constants.NullTag
25-
case _ => false
26-
}
20+
def unapply(x: Constant): Boolean = x.tag == Constants.NullTag
2721
}
2822

2923
object Boolean extends BooleanExtractor {

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

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -292,18 +292,23 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
292292
private val nullType = ConstantType(Constant(null))
293293
private val nullSpace = Typ(nullType)
294294

295-
override def intersectUnrelatedAtomicTypes(tp1: Type, tp2: Type): Space = {
296-
val and = AndType(tp1, tp2)
297-
// Precondition: !(tp1 <:< tp2) && !(tp2 <:< tp1)
298-
// Then, no leaf of the and-type tree `and` is a subtype of `and`.
299-
val res = inhabited(and)
300-
301-
debug.println(s"atomic intersection: ${and.show} = ${res}")
302-
303-
if (!res) Empty
304-
else if (tp1.isSingleton) Typ(tp1, true)
305-
else if (tp2.isSingleton) Typ(tp2, true)
306-
else Typ(and, true)
295+
override def intersectUnrelatedAtomicTypes(tp1: Type, tp2: Type) = {
296+
// Precondition: !isSubType(tp1, tp2) && !isSubType(tp2, tp1)
297+
if (tp1 == nullType || tp2 == nullType) {
298+
// Since projections of types don't include null, intersection with null is empty.
299+
Empty
300+
} else {
301+
val and = AndType(tp1, tp2)
302+
// Then, no leaf of the and-type tree `and` is a subtype of `and`.
303+
val res = inhabited(and)
304+
305+
debug.println(s"atomic intersection: ${and.show} = ${res}")
306+
307+
if (!res) Empty
308+
else if (tp1.isSingleton) Typ(tp1, true)
309+
else if (tp2.isSingleton) Typ(tp2, true)
310+
else Typ(and, true)
311+
}
307312
}
308313

309314
/** Whether the extractor is irrefutable */

tests/patmat/i4880a.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
14: Match case Unreachable

tests/patmat/t4661.check

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
9: Match case Unreachable
2+
10: Match case Unreachable
3+
11: Match case Unreachable
4+
26: Match case Unreachable
5+
27: Match case Unreachable
6+
28: Match case Unreachable
7+
33: Match case Unreachable
8+
36: Match case Unreachable
9+
37: Match case Unreachable
10+
38: Match case Unreachable
11+
39: Match case Unreachable
12+
40: Only null matched
13+
46: Match case Unreachable
14+
52: Match case Unreachable
15+
59: Only null matched

tests/patmat/t4661.scala

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
trait Foo
2+
class One extends Foo
3+
class Two extends Foo
4+
class Three extends Foo
5+
6+
object Test {
7+
def test(f: Foo) = f match {
8+
case f: Foo =>
9+
case f: One => // unreachable
10+
case f: Two => // unreachable
11+
case f: Three => // unreachable
12+
}
13+
}
14+
15+
trait Prefix {
16+
sealed trait Bar
17+
class BarOne extends Bar
18+
class BarTwo extends Bar
19+
class BarThree extends Bar
20+
}
21+
22+
class TestPrefix(val p: Prefix) {
23+
import p._
24+
def test(b: Bar) = b match {
25+
case b: Bar =>
26+
case b: BarOne => // unreachable
27+
case b: BarTwo => // unreachable
28+
case b: BarThree => // unreachable
29+
}
30+
31+
def test2(b: Bar) = b match {
32+
case b: Prefix#BarOne =>
33+
case b: BarOne => // unreachable
34+
case b: Prefix#BarTwo =>
35+
case b: Prefix#BarThree =>
36+
case b: BarTwo => // unreachable
37+
case b: BarThree => // unreachable
38+
case b: Bar => // unreachable
39+
case b: Prefix#Bar => // unreachable
40+
case _ => // only null matches
41+
}
42+
43+
def test3(b: Prefix#Bar) = b match {
44+
case b: Bar =>
45+
case b: Prefix#BarOne =>
46+
case b: BarOne => // unreachable
47+
case _ =>
48+
}
49+
50+
def test4(b: Bar) = b match {
51+
case b: Bar =>
52+
case b:Prefix#Bar => // unreachable
53+
}
54+
55+
def test5(b: Bar) = b match {
56+
case b: Prefix#BarOne =>
57+
case b: Prefix#BarTwo =>
58+
case b: Prefix#BarThree =>
59+
case _ => // only null matches
60+
}
61+
}

0 commit comments

Comments
 (0)