summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2014-04-29 14:38:35 +0200
committerJason Zaugg <jzaugg@gmail.com>2014-05-07 15:45:19 +0200
commit1ba2d7bb967ded0c19ff2cf966c492adc12292bb (patch)
tree1bb3f342d8a2060b461020c9e3431bbd3eff2a58
parentca9003e453873c496c72c431f0e5f9f3eaf31511 (diff)
downloadscala-1ba2d7bb967ded0c19ff2cf966c492adc12292bb.tar.gz
scala-1ba2d7bb967ded0c19ff2cf966c492adc12292bb.tar.bz2
scala-1ba2d7bb967ded0c19ff2cf966c492adc12292bb.zip
SI-8546 Pattern matcher analysis foiled by over-widening
In the enclosed test, the prefix checkable type `ModuleTypeRef(F2.this, C)` was being inadvertently widened to `ModuleTypeRef(F2[?], C)`. This started after some misguided future-proofing in SI-6771 / 3009916. This commit changes the `dealiasWiden` to a `delias`.
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala5
-rw-r--r--test/files/neg/t6771b.check2
-rw-r--r--test/files/neg/t6771b.scala2
-rw-r--r--test/files/pos/t8546.flags1
-rw-r--r--test/files/pos/t8546.scala49
5 files changed, 54 insertions, 5 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
index 2893cbdf45..894f959319 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
@@ -149,14 +149,15 @@ trait TreeAndTypeAnalysis extends Debugging {
object typeArgsToWildcardsExceptArray extends TypeMap {
// SI-6771 dealias would be enough today, but future proofing with the dealiasWiden.
// See neg/t6771b.scala for elaboration
- def apply(tp: Type): Type = tp.dealiasWiden match {
+ def apply(tp: Type): Type = tp.dealias match {
case TypeRef(pre, sym, args) if args.nonEmpty && (sym ne ArrayClass) =>
TypeRef(pre, sym, args map (_ => WildcardType))
case _ =>
mapOver(tp)
}
}
- debug.patmatResult(s"checkableType($tp)")(typeArgsToWildcardsExceptArray(tp))
+ val result = typeArgsToWildcardsExceptArray(tp)
+ debug.patmatResult(s"checkableType($tp)")(result)
}
// a type is "uncheckable" (for exhaustivity) if we don't statically know its subtypes (i.e., it's unsealed)
diff --git a/test/files/neg/t6771b.check b/test/files/neg/t6771b.check
index ba99e9178d..0c9fae533e 100644
--- a/test/files/neg/t6771b.check
+++ b/test/files/neg/t6771b.check
@@ -1,4 +1,4 @@
-t6771b.scala:14: error: type mismatch;
+t6771b.scala:12: error: type mismatch;
found : x.type (with underlying type String)
required: Test.a.type
b = b match { case x => x }
diff --git a/test/files/neg/t6771b.scala b/test/files/neg/t6771b.scala
index 78f11f7750..9723f70290 100644
--- a/test/files/neg/t6771b.scala
+++ b/test/files/neg/t6771b.scala
@@ -6,8 +6,6 @@
// But, to the intrepid hacker who works on this, a few notes:
// You'll have to look into places in the pattern matcher that
// call `dealias`, and see if they need to be `dealiasWiden`.
-// For example, if `checkableType` used only `dealias`, `pos/t6671.scala`
-// would fail.
object Test {
val a = ""; var b: a.type = a
diff --git a/test/files/pos/t8546.flags b/test/files/pos/t8546.flags
new file mode 100644
index 0000000000..85d8eb2ba2
--- /dev/null
+++ b/test/files/pos/t8546.flags
@@ -0,0 +1 @@
+-Xfatal-warnings
diff --git a/test/files/pos/t8546.scala b/test/files/pos/t8546.scala
new file mode 100644
index 0000000000..c39d749b4c
--- /dev/null
+++ b/test/files/pos/t8546.scala
@@ -0,0 +1,49 @@
+package test
+
+class F1() {
+ private sealed abstract class T
+ private case class A(m: Int) extends T
+ private case class B() extends T
+ private case object C extends T
+
+ // No warnings here
+ private def foo(t: T) = t match {
+ case A(m) => println("A:" + m)
+ case B() => println("B")
+ case C => println("C")
+ }
+
+ def test(m: Int): Unit = {
+ foo(A(m))
+ foo(B())
+ foo(C)
+ }
+}
+
+class F2[M]() {
+ private sealed abstract class T
+ private case class A(m: M) extends T
+ private case class B() extends T
+ private case object C extends T
+
+ // match may not be exhaustive. It would fail on the following input: C
+ private def foo(t: T) = t match {
+ case A(m) => println("A:" + m)
+ case B() => println("B")
+ case C => println("C")
+ }
+
+ def test(m: M): Unit = {
+ foo(A(m))
+ foo(B())
+ foo(C)
+ }
+
+}
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ new F1().test(1)
+ new F2[Int]().test(1)
+ }
+} \ No newline at end of file