summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-05-06 04:32:39 +0000
committerPaul Phillips <paulp@improving.org>2011-05-06 04:32:39 +0000
commit311b7de861bd2f4137e3503483177a1588cfdd12 (patch)
tree7b784b842cdf4a791a056e045eb4aa208c1e755a
parent14cd653295b5ed3f10b82193a9fb6da0867e31d6 (diff)
downloadscala-311b7de861bd2f4137e3503483177a1588cfdd12.tar.gz
scala-311b7de861bd2f4137e3503483177a1588cfdd12.tar.bz2
scala-311b7de861bd2f4137e3503483177a1588cfdd12.zip
Finally figured out what was going on with a ce...
Finally figured out what was going on with a certain class of exhaustiveness checking bugs. Hey moors, you can put away your pins, puppets, and magic sauces. Closes #3098, no review.
-rw-r--r--src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala11
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala19
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala6
-rw-r--r--test/files/neg/bug3098.check6
-rw-r--r--test/files/neg/bug3098.flags1
-rw-r--r--test/files/neg/bug3098/a.scala6
-rw-r--r--test/files/neg/bug3098/b.scala8
-rw-r--r--test/files/neg/patmatexhaust.check18
-rw-r--r--test/files/neg/patmatexhaust.scala60
-rw-r--r--test/files/pos/bug4020.flags1
-rw-r--r--test/files/pos/bug4020.scala25
11 files changed, 133 insertions, 28 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala
index c5c57938ca..d75670fd38 100644
--- a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala
+++ b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala
@@ -172,10 +172,15 @@ trait MatrixAdditions extends ast.TreeDSL {
val collected = toCollect map { case (pv, i) =>
// okay, now reset the flag
pv.sym resetFlag MUTABLE
- // have to filter out children which cannot match: see ticket #3683 for an example
- val kids = pv.tpe.typeSymbol.sealedDescendants filter (_.tpe matchesPattern pv.tpe)
- i -> kids
+ i -> (
+ pv.tpe.typeSymbol.sealedDescendants.toList sortBy (_.sealedSortName)
+ // symbols which are both sealed and abstract need not be covered themselves, because
+ // all of their children must be and they cannot otherwise be created.
+ filterNot (x => x.isSealed && x.isAbstractClass && !isValueClass(x))
+ // have to filter out children which cannot match: see ticket #3683 for an example
+ filter (_.tpe matchesPattern pv.tpe)
+ )
}
val folded =
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 281c8af4d5..d1f5cbf4d2 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -1530,19 +1530,14 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
abort("sourceFile_= inapplicable for " + this)
}
- /** If this is a sealed class, its known direct subclasses. Otherwise Set.empty */
- def children: List[Symbol] = Nil
-
- /** Recursively finds all sealed descendants and returns a sorted list.
- * Includes this symbol unless it is abstract, but as value classes are
- * marked abstract so they can't be instantiated, they are special cased.
+ /** If this is a sealed class, its known direct subclasses.
+ * Otherwise, the empty set.
*/
- def sealedDescendants: List[Symbol] = {
- val kids = children flatMap (_.sealedDescendants)
- val all = if (isAbstractClass && !isValueClass(this)) kids else this :: kids
+ def children: Set[Symbol] = Set()
- all.distinct sortBy (_.sealedSortName)
- }
+ /** Recursively assemble all children of this symbol.
+ */
+ def sealedDescendants: Set[Symbol] = children.flatMap(_.sealedDescendants) + this
// ToString -------------------------------------------------------------------
@@ -2093,7 +2088,7 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
if (isModuleClass) companionModule else NoSymbol
private var childSet: Set[Symbol] = Set()
- override def children: List[Symbol] = childSet.toList sortBy (_.sealedSortName)
+ override def children = childSet
override def addChild(sym: Symbol) { childSet = childSet + sym }
incCounter(classSymbolCount)
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
index 862e37ec2b..131c935a8a 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
@@ -144,15 +144,15 @@ abstract class Pickler extends SubComponent {
putType(sym.typeOfThis);
putSymbol(sym.alias)
if (!sym.children.isEmpty) {
- val (locals, globals) = sym.children.toList.partition(_.isLocalClass)
+ val (locals, globals) = sym.children partition (_.isLocalClass)
val children =
if (locals.isEmpty) globals
else {
val localChildDummy = sym.newClass(sym.pos, tpnme.LOCAL_CHILD)
localChildDummy.setInfo(ClassInfoType(List(sym.tpe), EmptyScope, localChildDummy))
- localChildDummy :: globals
+ globals + localChildDummy
}
- putChildren(sym, children sortBy (_.sealedSortName))
+ putChildren(sym, children.toList sortBy (_.sealedSortName))
}
for (annot <- staticAnnotations(sym.annotations.reverse))
putAnnotation(sym, annot)
diff --git a/test/files/neg/bug3098.check b/test/files/neg/bug3098.check
new file mode 100644
index 0000000000..403da281c8
--- /dev/null
+++ b/test/files/neg/bug3098.check
@@ -0,0 +1,6 @@
+b.scala:3: error: match is not exhaustive!
+missing combination C
+
+ def f = (null: T) match {
+ ^
+one error found
diff --git a/test/files/neg/bug3098.flags b/test/files/neg/bug3098.flags
new file mode 100644
index 0000000000..e8fb65d50c
--- /dev/null
+++ b/test/files/neg/bug3098.flags
@@ -0,0 +1 @@
+-Xfatal-warnings \ No newline at end of file
diff --git a/test/files/neg/bug3098/a.scala b/test/files/neg/bug3098/a.scala
new file mode 100644
index 0000000000..57a103c7a8
--- /dev/null
+++ b/test/files/neg/bug3098/a.scala
@@ -0,0 +1,6 @@
+// Traits.scala
+sealed trait T
+
+trait A extends T
+trait B extends T
+trait C extends T
diff --git a/test/files/neg/bug3098/b.scala b/test/files/neg/bug3098/b.scala
new file mode 100644
index 0000000000..84a1f9f6f4
--- /dev/null
+++ b/test/files/neg/bug3098/b.scala
@@ -0,0 +1,8 @@
+// Test.scala
+object Test {
+ def f = (null: T) match {
+ case _: A => println("A")
+ case _: B => println("B")
+ // no C
+ }
+}
diff --git a/test/files/neg/patmatexhaust.check b/test/files/neg/patmatexhaust.check
index 8aa9238d2e..5426d61d31 100644
--- a/test/files/neg/patmatexhaust.check
+++ b/test/files/neg/patmatexhaust.check
@@ -35,4 +35,20 @@ missing combination B
def ma9(x: B) = x match {
^
-7 errors found
+patmatexhaust.scala:100: error: match is not exhaustive!
+missing combination C1
+
+ def ma10(x: C) = x match { // not exhaustive: C1 is not sealed.
+ ^
+patmatexhaust.scala:114: error: match is not exhaustive!
+missing combination D1
+missing combination D2
+
+ def ma10(x: C) = x match { // not exhaustive: C1 has subclasses.
+ ^
+patmatexhaust.scala:126: error: match is not exhaustive!
+missing combination C1
+
+ def ma10(x: C) = x match { // not exhaustive: C1 is not abstract.
+ ^
+10 errors found
diff --git a/test/files/neg/patmatexhaust.scala b/test/files/neg/patmatexhaust.scala
index d49c4b207b..45aed558da 100644
--- a/test/files/neg/patmatexhaust.scala
+++ b/test/files/neg/patmatexhaust.scala
@@ -76,14 +76,56 @@ class TestSealedExhaustive { // compile only
case B1() => true // missing B, which is not abstract so must be included
case B2 => true
}
- sealed abstract class C
- abstract class C1 extends C
- object C2 extends C
- case object C6 extends C
- class C3 extends C1
- case class C4() extends C3
- def ma10(x: C) = x match { // exhaustive
- case C4() => true
- case C2 | C6 => true
+
+ object ob1 {
+ sealed abstract class C
+ sealed abstract class C1 extends C
+ object C2 extends C
+ case class C3() extends C
+ case object C4 extends C
+
+ def ma10(x: C) = x match { // exhaustive: abstract sealed C1 is dead end.
+ case C3() => true
+ case C2 | C4 => true
+ }
+ }
+
+ object ob2 {
+ sealed abstract class C
+ abstract class C1 extends C
+ object C2 extends C
+ case class C3() extends C
+ case object C4 extends C
+
+ def ma10(x: C) = x match { // not exhaustive: C1 is not sealed.
+ case C3() => true
+ case C2 | C4 => true
+ }
+ }
+ object ob3 {
+ sealed abstract class C
+ sealed abstract class C1 extends C
+ object D1 extends C1
+ case class D2() extends C1
+ object C2 extends C
+ case class C3() extends C
+ case object C4 extends C
+
+ def ma10(x: C) = x match { // not exhaustive: C1 has subclasses.
+ case C3() => true
+ case C2 | C4 => true
+ }
+ }
+ object ob4 {
+ sealed abstract class C
+ sealed class C1 extends C
+ object C2 extends C
+ case class C3() extends C
+ case object C4 extends C
+
+ def ma10(x: C) = x match { // not exhaustive: C1 is not abstract.
+ case C3() => true
+ case C2 | C4 => true
+ }
}
}
diff --git a/test/files/pos/bug4020.flags b/test/files/pos/bug4020.flags
new file mode 100644
index 0000000000..85d8eb2ba2
--- /dev/null
+++ b/test/files/pos/bug4020.flags
@@ -0,0 +1 @@
+-Xfatal-warnings
diff --git a/test/files/pos/bug4020.scala b/test/files/pos/bug4020.scala
new file mode 100644
index 0000000000..f976460191
--- /dev/null
+++ b/test/files/pos/bug4020.scala
@@ -0,0 +1,25 @@
+class A {
+ sealed trait Foo
+}
+
+object a1 extends A {
+ case class Foo1(i: Int) extends Foo
+}
+
+object a2 extends A {
+ case class Foo2(i: Int) extends Foo
+}
+
+class B {
+ def mthd(foo: a2.Foo) = {
+ foo match {
+ case a2.Foo2(i) => i
+
+ // Note: This case is impossible. In fact, scalac
+ // will (correctly) report an error if it is uncommented,
+ // but a warning if it is commented.
+
+ // case a1.Foo1(i) => i
+ }
+ }
+} \ No newline at end of file