Skip to content

Commit 6ed018b

Browse files
author
Adriaan Moors
committed
Merge pull request scala#650 from adriaanm/topic-virtpatmat
Unreachability analysis for pattern matches Thanks for reviewing, @retronym!
2 parents 488ed39 + 3cb72fa commit 6ed018b

13 files changed

+916
-365
lines changed

src/compiler/scala/reflect/internal/settings/MutableSettings.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,5 @@ abstract class MutableSettings extends AbsSettings {
4444
def maxClassfileName: IntSetting
4545
def Xexperimental: BooleanSetting
4646
def XoldPatmat: BooleanSetting
47+
def XnoPatmatAnalysis: BooleanSetting
4748
}

src/compiler/scala/reflect/runtime/Settings.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,5 @@ class Settings extends internal.settings.MutableSettings {
3535
val Xexperimental = new BooleanSetting(false)
3636
val deepCloning = new BooleanSetting (false)
3737
val XoldPatmat = new BooleanSetting(false)
38+
val XnoPatmatAnalysis = new BooleanSetting(false)
3839
}

src/compiler/scala/tools/nsc/settings/ScalaSettings.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ trait ScalaSettings extends AbsScalaSettings
109109
val sourceReader = StringSetting ("-Xsource-reader", "classname", "Specify a custom method for reading source files.", "")
110110

111111
val XoldPatmat = BooleanSetting ("-Xoldpatmat", "Use the pre-2.10 pattern matcher. Otherwise, the 'virtualizing' pattern matcher is used in 2.10.")
112+
val XnoPatmatAnalysis = BooleanSetting ("-Xno-patmat-analysis", "Don't perform exhaustivity/unreachability analysis. Also, ignore @switch annotation.")
112113

113114
/** Compatibility stubs for options whose value name did
114115
* not previously match the option name.

src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala

Lines changed: 812 additions & 361 deletions
Large diffs are not rendered by default.

src/compiler/scala/tools/nsc/util/Statistics.scala

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ class Statistics extends scala.reflect.internal.util.Statistics {
6060

6161
val macroExpandCount = new Counter
6262
val macroExpandNanos = new Timer
63+
64+
val patmatNanos = new Timer
65+
val patmatAnaDPLL = new Timer
66+
val patmatAnaVarEq = new Timer
67+
val patmatCNF = new Timer
68+
val patmatAnaExhaust = new Timer
69+
val patmatAnaReach = new Timer
70+
val patmatCNFSizes = new collection.mutable.HashMap[Int, Int] withDefaultValue 0
6371
}
6472

6573
object Statistics extends Statistics
@@ -71,7 +79,7 @@ abstract class StatisticsInfo {
7179
val global: Global
7280
import global._
7381

74-
var phasesShown = List("parser", "typer", "erasure", "cleanup")
82+
var phasesShown = List("parser", "typer", "patmat", "erasure", "cleanup")
7583

7684
def countNodes(tree: Tree, counts: ClassCounts) {
7785
for (t <- tree) counts(t.getClass) += 1
@@ -83,10 +91,15 @@ abstract class StatisticsInfo {
8391
def showRelTyper(timer: Timer) =
8492
timer+showPercent(timer.nanos, typerNanos.nanos)
8593

86-
def showCounts(counts: ClassCounts) =
94+
def showRelPatmat(timer: Timer) =
95+
timer+showPercent(timer.nanos, patmatNanos.nanos)
96+
97+
def showCounts[T](counts: scala.collection.mutable.Map[T, Int]) =
8798
counts.toSeq.sortWith(_._2 > _._2).map {
88-
case (cls, cnt) =>
99+
case (cls: Class[_], cnt) =>
89100
cls.toString.substring(cls.toString.lastIndexOf("$") + 1)+": "+cnt
101+
case (o, cnt) =>
102+
o.toString +": "+cnt
90103
}
91104

92105
def print(phase: Phase) = if (phasesShown contains phase.name) {
@@ -169,6 +182,16 @@ abstract class StatisticsInfo {
169182
if (timer1 != null) inform("#timer1 : " + timer1)
170183
if (timer2 != null) inform("#timer2 : " + timer2)
171184
//for (t <- uniques.iterator) println("unique: "+t)
185+
186+
if (phase.name == "patmat") {
187+
inform("time spent in patmat : " + patmatNanos )
188+
inform(" of which DPLL : " + showRelPatmat(patmatAnaDPLL ))
189+
inform("of which in CNF conversion : " + showRelPatmat(patmatCNF ))
190+
inform(" CNF size counts : " + showCounts(patmatCNFSizes ))
191+
inform("of which variable equality : " + showRelPatmat(patmatAnaVarEq ))
192+
inform(" of which in exhaustivity : " + showRelPatmat(patmatAnaExhaust))
193+
inform("of which in unreachability : " + showRelPatmat(patmatAnaReach ))
194+
}
172195
}
173196
}
174197
}

test/files/neg/patmatexhaust.check

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ patmatexhaust.scala:49: error: match may not be exhaustive.
1414
It would fail on the following inputs: Gp(), Gu
1515
def ma4(x:Deep) = x match { // missing cases: Gu, Gp
1616
^
17+
patmatexhaust.scala:55: error: unreachable code
18+
case _ if 1 == 0 =>
19+
^
1720
patmatexhaust.scala:53: error: match may not be exhaustive.
1821
It would fail on the following input: Gp()
1922
def ma5(x:Deep) = x match {
@@ -34,4 +37,4 @@ patmatexhaust.scala:126: error: match may not be exhaustive.
3437
It would fail on the following input: C1()
3538
def ma10(x: C) = x match { // not exhaustive: C1 is not abstract.
3639
^
37-
9 errors found
40+
10 errors found
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
virtpatmat_reach_null.scala:13: error: unreachable code
2+
case _ => // unreachable
3+
^
4+
one error found
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-Xfatal-warnings
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
sealed abstract class Const {
2+
final def excludes(other: Const) =
3+
(this, other) match {
4+
case (_, NullConst) =>
5+
case (NullConst, _) =>
6+
case (_: ValueConst, _: ValueConst) =>
7+
case (_: ValueConst, _: TypeConst) =>
8+
case (_: TypeConst, _: ValueConst) =>
9+
case (_: TypeConst, _: TypeConst) =>
10+
case (null, _) =>
11+
case (_, null) =>
12+
case null =>
13+
case _ => // unreachable
14+
}
15+
}
16+
17+
sealed class TypeConst extends Const
18+
sealed class ValueConst extends Const
19+
case object NullConst extends Const
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
virtpatmat_reach_sealed_unsealed.scala:16: error: match may not be exhaustive.
2+
It would fail on the following input: false
3+
(true: Boolean) match { case true => } // not exhaustive, but reachable
4+
^
5+
virtpatmat_reach_sealed_unsealed.scala:18: error: unreachable code
6+
(true: Boolean) match { case true => case false => case _ => } // exhaustive, last case is unreachable
7+
^
8+
virtpatmat_reach_sealed_unsealed.scala:19: error: unreachable code
9+
(true: Boolean) match { case true => case false => case _: Boolean => } // exhaustive, last case is unreachable
10+
^
11+
virtpatmat_reach_sealed_unsealed.scala:20: error: unreachable code
12+
(true: Boolean) match { case true => case false => case _: Any => } // exhaustive, last case is unreachable
13+
^
14+
four errors found

0 commit comments

Comments
 (0)