From 62713964b96f64f9c0fd0070c89aa6571679856d Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 23 Apr 2013 23:55:05 +0200 Subject: SI-7369 Avoid spurious unreachable warnings in patterns Unreachability analysis draws on the enumerated domain of types (e.g sealed subclasses + null, or true/false), and also looks at all stable identifier patterns tested for equality against the same 'slot' in a pattern. It was drawing the wrong conclusions about stable identifier patterns. Unlike the domain constants, two such values may hold the same value, so we can't assume that matching X precludes matching Y in the same slot in a subsequent case. For example: val X: Boolean = true; val Y: Boolean = true def m1(t1: Tuple1[Boolean]) = t1 match { case Tuple1(true) => case Tuple1(false) => case Tuple1(false) => // correctly unreachable } def m2(t1: Tuple1[Boolean]) = t1 match { case Tuple1(X) => case Tuple1(Y) => // spurious unreachable warning } // // Before // reachability, vars: V2: Boolean ::= true | false// Set(false, Y, X, true) // = x1._1 V1: (Boolean,) ::= null | ... // = x1 equality axioms: V2=true#4 \/ V2=false#5 /\ -V2=false#5 \/ -V2=Y#3 /\ -V2=false#5 \/ -V2=X#2 /\ -V2=false#5 \/ -V2=true#4 /\ -V2=Y#3 \/ -V2=X#2 /\ -V2=Y#3 \/ -V2=true#4 /\ -V2=X#2 \/ -V2=true#4 // // After // reachability, vars: V2: Boolean ::= true | false// Set(false, Y, X, true) // = x1._1 V1: (Boolean,) ::= null | ... // = x1 equality axioms: V2=true#4 \/ V2=false#5 /\ -V2=false#5 \/ -V2=true#4 --- test/files/neg/t7369.check | 13 +++++++++++++ test/files/neg/t7369.flags | 1 + test/files/neg/t7369.scala | 43 +++++++++++++++++++++++++++++++++++++++++++ test/files/pos/t7369.flags | 1 + test/files/pos/t7369.scala | 37 +++++++++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+) create mode 100644 test/files/neg/t7369.check create mode 100644 test/files/neg/t7369.flags create mode 100644 test/files/neg/t7369.scala create mode 100644 test/files/pos/t7369.flags create mode 100644 test/files/pos/t7369.scala (limited to 'test') diff --git a/test/files/neg/t7369.check b/test/files/neg/t7369.check new file mode 100644 index 0000000000..4f101e145a --- /dev/null +++ b/test/files/neg/t7369.check @@ -0,0 +1,13 @@ +t7369.scala:6: error: unreachable code + case Tuple1(X) => // unreachable + ^ +t7369.scala:13: error: unreachable code + case Tuple1(true) => // unreachable + ^ +t7369.scala:31: error: unreachable code + case Tuple1(X) => // unreachable + ^ +t7369.scala:40: error: unreachable code + case Tuple1(null) => // unreachable + ^ +four errors found diff --git a/test/files/neg/t7369.flags b/test/files/neg/t7369.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/neg/t7369.flags @@ -0,0 +1 @@ +-Xfatal-warnings \ No newline at end of file diff --git a/test/files/neg/t7369.scala b/test/files/neg/t7369.scala new file mode 100644 index 0000000000..87ddfe98b7 --- /dev/null +++ b/test/files/neg/t7369.scala @@ -0,0 +1,43 @@ +object Test { + val X, Y = true + (null: Tuple1[Boolean]) match { + case Tuple1(X) => + case Tuple1(Y) => + case Tuple1(X) => // unreachable + case _ => + } + + (null: Tuple1[Boolean]) match { + case Tuple1(true) => + case Tuple1(false) => + case Tuple1(true) => // unreachable + case _ => + } +} + + +sealed abstract class B; +case object True extends B; +case object False extends B; + +object Test2 { + + val X: B = True + val Y: B = False + + (null: Tuple1[B]) match { + case Tuple1(X) => + case Tuple1(Y) => + case Tuple1(X) => // unreachable + case _ => + } +} + +object Test3 { + (null: Tuple1[B]) match { + case Tuple1(null) => + case Tuple1(True) => + case Tuple1(null) => // unreachable + case _ => + } +} diff --git a/test/files/pos/t7369.flags b/test/files/pos/t7369.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/pos/t7369.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/pos/t7369.scala b/test/files/pos/t7369.scala new file mode 100644 index 0000000000..2f31c93d29 --- /dev/null +++ b/test/files/pos/t7369.scala @@ -0,0 +1,37 @@ +object Test { + val X, Y = true + (null: Tuple1[Boolean]) match { + case Tuple1(X) => + case Tuple1(Y) => // unreachable + case _ => + } +} + + +sealed abstract class B; +case object True extends B; +case object False extends B; + +object Test2 { + + val X: B = True + val Y: B = False + + (null: Tuple1[B]) match { + case Tuple1(X) => + case Tuple1(Y) => // no warning + case _ => + } +} + +object Test3 { + val X, O = true + def classify(neighbourhood: (Boolean, Boolean, Boolean)): String = { + neighbourhood match { + case (X, X, X) => "middle" + case (X, X, O) => "right" + case (O, X, X) => "left" + case _ => throw new IllegalArgumentException("Invalid") + } + } +} \ No newline at end of file -- cgit v1.2.3