diff options
author | Paul Phillips <paulp@improving.org> | 2011-04-30 20:01:25 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2011-04-30 20:01:25 +0000 |
commit | b4749d3b1afb1df236ec48fd3a773aab24a6f74d (patch) | |
tree | 81792bd4de8dfb8c2beb6ad1418880947fb6e371 | |
parent | 793796eee0769926a3162d69dd23c282ca2d8ba4 (diff) | |
download | scala-b4749d3b1afb1df236ec48fd3a773aab24a6f74d.tar.gz scala-b4749d3b1afb1df236ec48fd3a773aab24a6f74d.tar.bz2 scala-b4749d3b1afb1df236ec48fd3a773aab24a6f74d.zip |
Completely to my surprise, found that fixing al...
Completely to my surprise, found that fixing all those sequence issues
revealed that the pattern matcher can catch a lot more inexhaustive
cases than it has been catching. Fixed most of the inexhaustive matches
in the compiler, which had become a bit warnier. No review.
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/ParallelMatching.scala | 9 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/Patterns.scala | 11 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Erasure.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/LambdaLift.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 2 | ||||
-rw-r--r-- | test/files/neg/exhausting.check | 6 | ||||
-rw-r--r-- | test/files/neg/patmatexhaust.check | 25 | ||||
-rw-r--r-- | test/files/neg/patmatexhaust.flags | 1 | ||||
-rw-r--r-- | test/files/neg/patmatexhaust.scala | 6 |
11 files changed, 40 insertions, 38 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala index f29618c7cf..3d3097e497 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala @@ -321,9 +321,9 @@ abstract class ICodeCheckers { } } - def popStack = { checkStack(1) ; popStackN(1) match { case List(x) => x } } - def popStack2 = { checkStack(2) ; popStackN(2) match { case List(x, y) => (x, y) } } - def popStack3 = { checkStack(3) ; popStackN(3) match { case List(x, y, z) => (x, y, z) } } + def popStack = { checkStack(1) ; (popStackN(1): @unchecked) match { case List(x) => x } } + def popStack2 = { checkStack(2) ; (popStackN(2): @unchecked) match { case List(x, y) => (x, y) } } + def popStack3 = { checkStack(3) ; (popStackN(3): @unchecked) match { case List(x, y, z) => (x, y, z) } } /** Called by faux instruction LOAD_EXCEPTION to wipe out the stack. */ def clearStack() = { diff --git a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala index e59d8c7858..c5c57938ca 100644 --- a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala +++ b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala @@ -136,7 +136,7 @@ trait MatrixAdditions extends ast.TreeDSL { /** Exhaustiveness checking requires looking for sealed classes * and if found, making sure all children are covered by a pattern. */ - class ExhaustivenessChecker(rep: Rep) { + class ExhaustivenessChecker(rep: Rep, matchPos: Position) { val Rep(tvars, rows) = rep import Flags.{ MUTABLE, ABSTRACT, SEALED } @@ -201,7 +201,7 @@ trait MatrixAdditions extends ast.TreeDSL { def check = { def errMsg = (inexhaustives map mkMissingStr).mkString if (inexhaustives.nonEmpty) - cunit.warning(tvars.head.lhs.pos, "match is not exhaustive!\n" + errMsg) + cunit.warning(matchPos, "match is not exhaustive!\n" + errMsg) rep } diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 89ca99de86..fb617908c7 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -70,7 +70,11 @@ trait ParallelMatching extends ast.TreeDSL val newRows = rows1 flatMap (_ expandAlternatives classifyPat) if (rows1.length != newRows.length) make(roots1, newRows) // recursive call if any change - else Rep(roots1, newRows).checkExhaustive + else { + val rep = Rep(roots1, newRows) + new ExhaustivenessChecker(rep, roots.head.sym.pos).check + rep + } } override def toString() = "MatchMatrix(%s) { %s }".format(matchResultType, indentAll(targets)) @@ -722,9 +726,6 @@ trait ParallelMatching extends ast.TreeDSL lazy val guardedRest = if (guard.isEmpty) Rep(Nil, Nil) else make(tvars, rows.tail) lazy val (defaults, others) = pats span (_.isDefault) - /** Sealed classes. */ - def checkExhaustive = new ExhaustivenessChecker(this).check - /** Cut out the column containing the non-default pattern. */ class Cut(index: Int) { /** The first two separate out the 'i'th pattern in each row from the remainder. */ diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala index 750fdb3c3f..e0734e7f2e 100644 --- a/src/compiler/scala/tools/nsc/matching/Patterns.scala +++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala @@ -173,9 +173,16 @@ trait Patterns extends ast.TreeDSL { // 8.1.7 / 8.1.8 (unapply and unapplySeq calls) case class ExtractorPattern(tree: UnApply) extends UnapplyPattern { - override def simplify(pv: PatternVar) = + override def simplify(pv: PatternVar) = { + if (pv.sym hasFlag NO_EXHAUSTIVE) () + else { + TRACE("Setting NO_EXHAUSTIVE on " + pv.sym + " due to extractor " + tree) + pv.sym setFlag NO_EXHAUSTIVE + } + if (pv.tpe <:< arg.tpe) this else this rebindTo uaTyped + } override def description = "Unapply(%s => %s)".format(necessaryType, resTypesString) } @@ -205,8 +212,6 @@ trait Patterns extends ast.TreeDSL { override def necessaryType = if (nonStarPatterns.nonEmpty) consRef else listRef override def simplify(pv: PatternVar) = { - pv.sym setFlag NO_EXHAUSTIVE - if (pv.tpe <:< necessaryType) foldedPatterns else diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 36552894e5..007ab36e5e 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -458,7 +458,7 @@ abstract class Erasure extends AddInterfaces else if (sym.name == nme.apply) tp else if (sym.name == nme.update) - tp match { + (tp: @unchecked) match { case MethodType(List(index, tvar), restpe) => MethodType(List(index.cloneSymbol.setInfo(erasure(index.tpe)), tvar), erasedTypeRef(UnitClass)) @@ -987,7 +987,7 @@ abstract class Erasure extends AddInterfaces case Apply(fn, args) => if (fn.symbol == Any_asInstanceOf) - fn match { + (fn: @unchecked) match { case TypeApply(Select(qual, _), List(targ)) => if (qual.tpe <:< targ.tpe) { atPos(tree.pos) { Typed(qual, TypeTree(targ.tpe)) } diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index e837af42fd..9cfd497c76 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -271,11 +271,11 @@ abstract class LambdaLift extends InfoTransform { case Some(ps) => val freeParams = ps map (p => ValDef(p) setPos tree.pos setType NoType) tree match { - case DefDef(mods, name, tparams, List(vparams), tpt, rhs) => + case DefDef(mods, name, tparams, vparamss, tpt, rhs) => val addParams = cloneSymbols(ps).map(_.setFlag(PARAM)) sym.updateInfo( lifted(MethodType(sym.info.params ::: addParams, sym.info.resultType))) - treeCopy.DefDef(tree, mods, name, tparams, List(vparams ::: freeParams), tpt, rhs) + treeCopy.DefDef(tree, mods, name, tparams, List(vparamss.head ++ freeParams), tpt, rhs) case ClassDef(mods, name, tparams, impl @ Template(parents, self, body)) => // Disabled attempt to to add getters to freeParams // this does not work yet. Problem is that local symbols need local names diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 2c89647c88..4a62c7c70d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2740,7 +2740,7 @@ trait Typers extends Modes { fun1clazz, List(selfsym.info, annClass.tpe)) - typed(func, mode, funcType) match { + (typed(func, mode, funcType): @unchecked) match { case t @ Function(List(arg), rhs) => val subs = new TreeSymSubstituter(List(arg.symbol),List(selfsym)) diff --git a/test/files/neg/exhausting.check b/test/files/neg/exhausting.check index d3f2251f79..0bef21e077 100644 --- a/test/files/neg/exhausting.check +++ b/test/files/neg/exhausting.check @@ -2,7 +2,7 @@ exhausting.scala:20: error: match is not exhaustive! missing combination * Nil def fail1[T](xs: List[T]) = xs match { - ^ + ^ exhausting.scala:24: error: match is not exhaustive! missing combination Nil @@ -17,7 +17,7 @@ exhausting.scala:31: error: match is not exhaustive! missing combination Bar2 Bar2 def fail4[T <: AnyRef](xx: (Foo[T], Foo[T])) = xx match { - ^ + ^ exhausting.scala:36: error: match is not exhaustive! missing combination Bar1 Bar2 missing combination Bar1 Bar3 @@ -25,5 +25,5 @@ missing combination Bar2 Bar1 missing combination Bar2 Bar2 def fail5[T](xx: (Foo[T], Foo[T])) = xx match { - ^ + ^ 5 errors found diff --git a/test/files/neg/patmatexhaust.check b/test/files/neg/patmatexhaust.check index 83c4279b0a..8aa9238d2e 100644 --- a/test/files/neg/patmatexhaust.check +++ b/test/files/neg/patmatexhaust.check @@ -1,37 +1,38 @@ -patmatexhaust.scala:7: warning: match is not exhaustive! +patmatexhaust.scala:7: error: match is not exhaustive! missing combination Baz def ma1(x:Foo) = x match { ^ -patmatexhaust.scala:11: warning: match is not exhaustive! +patmatexhaust.scala:11: error: match is not exhaustive! missing combination Bar def ma2(x:Foo) = x match { ^ -patmatexhaust.scala:23: warning: match is not exhaustive! +patmatexhaust.scala:23: error: match is not exhaustive! missing combination Kult Kult missing combination Qult Qult def ma3(x:Mult) = (x,x) match { // not exhaustive - ^ -patmatexhaust.scala:49: warning: match is not exhaustive! + ^ +patmatexhaust.scala:49: error: match is not exhaustive! missing combination Gp missing combination Gu def ma4(x:Deep) = x match { // missing cases: Gu, Gp ^ -patmatexhaust.scala:53: warning: match is not exhaustive! +patmatexhaust.scala:53: error: match is not exhaustive! missing combination Gp def ma5(x:Deep) = x match { // Gp ^ -patmatexhaust.scala:75: warning: match is not exhaustive! +patmatexhaust.scala:59: error: match is not exhaustive! +missing combination Nil + + def ma6() = List(1,2) match { // give up + ^ +patmatexhaust.scala:75: error: match is not exhaustive! missing combination B def ma9(x: B) = x match { ^ -patmatexhaust.scala:92: error: unreachable code - case 1 => - ^ -6 warnings found -one error found +7 errors found diff --git a/test/files/neg/patmatexhaust.flags b/test/files/neg/patmatexhaust.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/neg/patmatexhaust.flags @@ -0,0 +1 @@ +-Xfatal-warnings
\ No newline at end of file diff --git a/test/files/neg/patmatexhaust.scala b/test/files/neg/patmatexhaust.scala index 4a66649a18..d49c4b207b 100644 --- a/test/files/neg/patmatexhaust.scala +++ b/test/files/neg/patmatexhaust.scala @@ -86,10 +86,4 @@ class TestSealedExhaustive { // compile only case C4() => true case C2 | C6 => true } - - def redundant() = 1 match { // include this otherwise script won't test this in files/neg - case 1 => - case 1 => - } - } |