Skip to content

Commit 640c955

Browse files
committed
Merge pull request scala#4085 from adriaanm/patmat-suppress
Suppress match analysis under -Xno-patmat-analysis
2 parents 76eac60 + 781c60f commit 640c955

File tree

5 files changed

+167
-6
lines changed

5 files changed

+167
-6
lines changed

src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -761,12 +761,12 @@ trait MatchAnalysis extends MatchApproximation {
761761
}
762762

763763
def analyzeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type, suppression: Suppression): Unit = {
764-
if (!suppression.unreachable) {
764+
if (!suppression.suppressUnreachable) {
765765
unreachableCase(prevBinder, cases, pt) foreach { caseIndex =>
766766
reportUnreachable(cases(caseIndex).last.pos)
767767
}
768768
}
769-
if (!suppression.exhaustive) {
769+
if (!suppression.suppressExhaustive) {
770770
val counterExamples = exhaustive(prevBinder, cases, pt)
771771
if (counterExamples.nonEmpty)
772772
reportMissingCases(prevBinder.pos, counterExamples)

src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ trait MatchTranslation {
208208
case _ => (cases, None)
209209
}
210210

211-
checkMatchVariablePatterns(nonSyntheticCases)
211+
if (!settings.XnoPatmatAnalysis) checkMatchVariablePatterns(nonSyntheticCases)
212212

213213
// we don't transform after uncurry
214214
// (that would require more sophistication when generating trees,

src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging {
2121
import global._
2222
import definitions._
2323

24-
final case class Suppression(exhaustive: Boolean, unreachable: Boolean)
24+
final case class Suppression(suppressExhaustive: Boolean, suppressUnreachable: Boolean)
2525
object Suppression {
2626
val NoSuppression = Suppression(false, false)
27+
val FullSuppression = Suppression(true, true)
2728
}
2829

2930
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -542,7 +543,7 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging {
542543
debug.patmat("combining cases: "+ (casesNoSubstOnly.map(_.mkString(" >> ")).mkString("{", "\n", "}")))
543544

544545
val (suppression, requireSwitch): (Suppression, Boolean) =
545-
if (settings.XnoPatmatAnalysis) (Suppression.NoSuppression, false)
546+
if (settings.XnoPatmatAnalysis) (Suppression.FullSuppression, false)
546547
else scrut match {
547548
case Typed(tree, tpt) =>
548549
val suppressExhaustive = tpt.tpe hasAnnotation UncheckedClass
@@ -574,7 +575,7 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging {
574575
(Suppression.NoSuppression, false)
575576
}
576577

577-
emitSwitch(scrut, scrutSym, casesNoSubstOnly, pt, matchFailGenOverride, suppression.exhaustive).getOrElse{
578+
emitSwitch(scrut, scrutSym, casesNoSubstOnly, pt, matchFailGenOverride, unchecked = suppression.suppressExhaustive).getOrElse{
578579
if (requireSwitch) reporter.warning(scrut.pos, "could not emit switch for @switch annotated match")
579580

580581
if (casesNoSubstOnly nonEmpty) {

test/files/pos/patmat-suppress.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-Xfatal-warnings -Xno-patmat-analysis

test/files/pos/patmat-suppress.scala

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// test that none of these warn due to -Xno-patmat-analysis
2+
// tests taken from test/files/neg/patmatexhaust.scala, test/files/neg/pat_unreachable.scala
3+
class TestSealedExhaustive { // compile only
4+
sealed abstract class Foo
5+
6+
case class Bar(x:Int) extends Foo
7+
case object Baz extends Foo
8+
9+
def ma1(x:Foo) = x match {
10+
case Bar(_) => // not exhaustive
11+
}
12+
13+
def ma2(x:Foo) = x match {
14+
case Baz => // not exhaustive
15+
}
16+
17+
sealed abstract class Mult
18+
case class Kult(s:Mult) extends Mult
19+
case class Qult() extends Mult
20+
21+
def ma33(x:Kult) = x match { // exhaustive
22+
case Kult(_) => // exhaustive
23+
}
24+
25+
def ma3(x:Mult) = (x,x) match { // not exhaustive
26+
case (Kult(_), Qult()) => // Kult missing
27+
//case (Kult(_), Kult(_)) =>
28+
case (Qult(), Kult(_)) => // Qult missing
29+
//case (Qult(), Qult()) =>
30+
}
31+
32+
def ma3u(x:Mult) = ((x,x) : @unchecked) match { // not exhaustive, but not checked!
33+
case (Kult(_), Qult()) =>
34+
case (Qult(), Kult(_)) =>
35+
}
36+
37+
sealed abstract class Deep
38+
39+
case object Ga extends Deep
40+
sealed class Gp extends Deep
41+
case object Gu extends Gp
42+
43+
def zma3(x:Deep) = x match { // exhaustive!
44+
case _ =>
45+
}
46+
def zma4(x:Deep) = x match { // exhaustive!
47+
case Ga =>
48+
case _ =>
49+
}
50+
51+
def ma4(x:Deep) = x match { // missing cases: Gu, Gp which is not abstract so must be included
52+
case Ga =>
53+
}
54+
55+
def ma5(x:Deep) = x match {
56+
case Gu =>
57+
case _ if 1 == 0 =>
58+
case Ga =>
59+
}
60+
61+
def ma6() = List(1,2) match { // give up
62+
case List(1,2) =>
63+
case x :: xs =>
64+
}
65+
66+
def ma7() = List(1,2) match { //exhaustive
67+
case 1::2::Nil =>
68+
case _ =>
69+
}
70+
71+
sealed class B
72+
case class B1() extends B
73+
case object B2 extends B
74+
def ma8(x: B) = x match {
75+
case _: B => true
76+
}
77+
def ma9(x: B) = x match {
78+
case B1() => true // missing B, which is not abstract so must be included
79+
case B2 => true
80+
}
81+
82+
object ob1 {
83+
sealed abstract class C
84+
sealed abstract class C1 extends C
85+
object C2 extends C
86+
case class C3() extends C
87+
case object C4 extends C
88+
89+
def ma10(x: C) = x match { // exhaustive: abstract sealed C1 is dead end.
90+
case C3() => true
91+
case C2 | C4 => true
92+
}
93+
}
94+
95+
object ob2 {
96+
sealed abstract class C
97+
abstract class C1 extends C
98+
object C2 extends C
99+
case class C3() extends C
100+
case object C4 extends C
101+
102+
def ma10(x: C) = x match { // not exhaustive: C1 is not sealed.
103+
case C3() => true
104+
case C2 | C4 => true
105+
}
106+
}
107+
object ob3 {
108+
sealed abstract class C
109+
sealed abstract class C1 extends C
110+
object D1 extends C1
111+
case class D2() extends C1
112+
object C2 extends C
113+
case class C3() extends C
114+
case object C4 extends C
115+
116+
def ma10(x: C) = x match { // not exhaustive: C1 has subclasses.
117+
case C3() => true
118+
case C2 | C4 => true
119+
}
120+
}
121+
object ob4 {
122+
sealed abstract class C
123+
sealed class C1 extends C
124+
object C2 extends C
125+
case class C3() extends C
126+
case object C4 extends C
127+
128+
def ma10(x: C) = x match { // not exhaustive: C1 is not abstract.
129+
case C3() => true
130+
case C2 | C4 => true
131+
}
132+
}
133+
}
134+
135+
object TestUnreachable extends App {
136+
def unreachable1(xs:Seq[Char]) = xs match {
137+
case Seq(x, y, _*) => x::y::Nil
138+
case Seq(x, y, z, w) => List(z,w) // redundant!
139+
}
140+
def unreachable2(xs:Seq[Char]) = xs match {
141+
case Seq(x, y, _*) => x::y::Nil
142+
case Seq(x, y) => List(x, y)
143+
}
144+
145+
def not_unreachable(xs:Seq[Char]) = xs match {
146+
case Seq(x, y, _*) => x::y::Nil
147+
case Seq(x) => List(x)
148+
}
149+
def not_unreachable2(xs:Seq[Char]) = xs match {
150+
case Seq(x, y) => x::y::Nil
151+
case Seq(x, y, z, _*) => List(x,y)
152+
}
153+
154+
def contrivedExample[A, B, C](a: A, b: B, c: C): Unit = a match {
155+
case b => println("matched b")
156+
case c => println("matched c")
157+
case _ => println("matched neither")
158+
}
159+
}

0 commit comments

Comments
 (0)