diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala | 11 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Symbols.scala | 19 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala | 6 | ||||
-rw-r--r-- | test/files/neg/bug3098.check | 6 | ||||
-rw-r--r-- | test/files/neg/bug3098.flags | 1 | ||||
-rw-r--r-- | test/files/neg/bug3098/a.scala | 6 | ||||
-rw-r--r-- | test/files/neg/bug3098/b.scala | 8 | ||||
-rw-r--r-- | test/files/neg/patmatexhaust.check | 18 | ||||
-rw-r--r-- | test/files/neg/patmatexhaust.scala | 60 | ||||
-rw-r--r-- | test/files/pos/bug4020.flags | 1 | ||||
-rw-r--r-- | test/files/pos/bug4020.scala | 25 |
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 |