summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBurak Emir <emir@epfl.ch>2007-02-02 11:38:44 +0000
committerBurak Emir <emir@epfl.ch>2007-02-02 11:38:44 +0000
commit9edda0088d74a33f4ec2e684b67bf0cf14ce7104 (patch)
treecab41e9040923ccef341b03fe7a785fb3432cc05
parent6a440b960c00c01f3653385417a246e359d82e01 (diff)
downloadscala-9edda0088d74a33f4ec2e684b67bf0cf14ce7104.tar.gz
scala-9edda0088d74a33f4ec2e684b67bf0cf14ce7104.tar.bz2
scala-9edda0088d74a33f4ec2e684b67bf0cf14ce7104.zip
refined exhaustivity check
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternMatchers.scala56
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternNodes.scala17
-rw-r--r--test/files/neg/patmatexhaust.scala4
3 files changed, 66 insertions, 11 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala
index 466f4e96c9..8a2bfb97cc 100644
--- a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala
+++ b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala
@@ -1026,6 +1026,7 @@ print()
// returns true if this tree is optimizable
// throws a warning if is not exhaustive
def optimize1(selType:Type, alternatives1: PatternNode ): {Boolean, collection.immutable.Set[Symbol], collection.immutable.Set[Symbol]} = {
+ var res = true
// if selType hasflag SEALED, enumerate selType.symbol.children
// to be very precise, take into account the case that a non case child is sealed.
var alts = alternatives1;
@@ -1035,27 +1036,56 @@ print()
var coveredCases: SymSet = emptySymbolSet // only case _
var remainingCases = if(alts ne null) checkExCoverage(selType.symbol) else emptySymbolSet // only case _
var cases = 0;
- while (alts ne null) {
+
+ def traverse(alts:PatternNode) {
alts match {
case ConstrPat(_) =>
+ if (alts.getTpe.symbol.hasFlag(Flags.CASE)) {
+ coveredCases = coveredCases + alts.getTpe.symbol
+ remainingCases = remainingCases - alts.getTpe.symbol
+ cases = cases + 1
+ }
+ else {
+ val covered = remainingCases.filter(x => isSubType(x.tpe, alts.getTpe))
+ coveredCases = coveredCases ++ covered
+ remainingCases = remainingCases -- covered
+ res = false
+ }
+
+ // Nil is also a "constructor pattern" somehow
+ case VariablePat(tree) if (alts.getTpe.symbol.hasFlag(Flags.CASE)) => // Nil
coveredCases = coveredCases + alts.getTpe.symbol
remainingCases = remainingCases - alts.getTpe.symbol
- if (alts.getTpe.symbol.hasFlag(Flags.CASE))
- cases = cases +1;
- else
- return {false, coveredCases, remainingCases};
+ cases = cases + 1
case DefaultPat() =>
if(andIsUnguardedBody(alts) || alts.and.isInstanceOf[Header]) {
coveredCases = emptySymbolSet
remainingCases = emptySymbolSet
}
- case _ =>
- return {false, coveredCases, remainingCases};
+
+ case UnapplyPat(_,_) | SequencePat(_, _) | RightIgnoringSequencePat(_, _, _) =>
+ res = false
+ remainingCases = emptySymbolSet
+
+ case ConstantPat(_) =>
+ res = false
+
+ case AltPat(branches) =>
+ res = false
+ traverse(branches.or)
+
+ case VariablePat(_) =>
+ res = false
}
+ }
+
+ while (alts ne null) {
+ traverse(alts)
alts = alts.or;
}
- return {cases > 2, coveredCases, remainingCases};
+
+ return {res && (cases > 2), coveredCases, remainingCases};
} // def optimize
var node = node1;
@@ -1063,6 +1093,7 @@ print()
var res: Tree = Literal(Constant(false)); //.setInfo(defs.BooleanClass);
var lastSelector: Tree = null
var carryCovered: SymSet = emptySymbolSet
+ var ignoreCovered = false // indicates whether we have given up, due to unapply
while (node ne null)
node match {
@@ -1070,12 +1101,13 @@ print()
val selector = _h.selector;
if(selector != lastSelector) {
carryCovered = emptySymbolSet;
+ ignoreCovered = false
}
//Console.println("sel:"+selector+" last"+lastSelector+" - "+(selector == lastSelector))
val next = _h.next;
//res = And(mkNegate(res), toTree(node.or, selector));
val {doOptimize, coveredCases, remainingCases} = optimize1(node.getTpe, node.or)
- if(!remainingCases.isEmpty) {
+ if(!remainingCases.isEmpty && !ignoreCovered) {
carryCovered = carryCovered ++ coveredCases // ??
if(next != null && andIsUnguardedBody(next.or)) {
// ignore, default case
@@ -1091,6 +1123,8 @@ print()
//Console.println(_h.print("", new StringBuilder()).toString())
}
}
+ } else {
+ ignoreCovered = true
}
if (doOptimize)
res = Or(res, toOptTree(node.or, selector));
@@ -1189,6 +1223,10 @@ print()
defaultCase = node
node = node.or
+ case VariablePat(tree) if node.getTpe.symbol.hasFlag(Flags.CASE) =>
+ cases = insertNode(node.getTpe().symbol.tag, node, cases)
+ node = node.or
+
case _ =>
scala.Predef.error("errare humanum est")
}
diff --git a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
index e31c8d18a0..d421c8b5a0 100644
--- a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
+++ b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
@@ -24,6 +24,9 @@ trait PatternNodes requires transform.ExplicitOuter {
def bodyToTree(): Tree = this match {
case _b:Body =>
_b.body(0)
+ case _ =>
+ error("bodyToTree called for pattern node "+this)
+ null
}
def getTpe(): Type = tpe
@@ -168,8 +171,8 @@ trait PatternNodes requires transform.ExplicitOuter {
"VariablePat"
case UnapplyPat(casted, fn) =>
"UnapplyPat(" + casted + ")"
- case _ =>
- "<unknown pat>"
+ case AltPat(alts) =>
+ "Alternative("+alts+")"
}
def print(indent: String, sb: StringBuilder): StringBuilder = {
@@ -223,6 +226,16 @@ trait PatternNodes requires transform.ExplicitOuter {
patNode.and.print(nindent, sb)
cont
+ case RightIgnoringSequencePat( casted, castedRest, plen ) =>
+ val s = ("-- ri " + patNode.getTpe().symbol.name + "(" +
+ patNode.getTpe() +
+ ", " + casted + ", " + plen + ") -> ")
+ val nindent = newIndent(s)
+ sb.append(indent + s).append('\n')
+ patNode.and.print(nindent, sb)
+ cont
+
+
case DefaultPat() =>
sb.append(indent + "-- _ -> ").append('\n')
patNode.and.print(indent.substring(0, indent.length() - 1) +
diff --git a/test/files/neg/patmatexhaust.scala b/test/files/neg/patmatexhaust.scala
index 0416749b88..aaa32cda24 100644
--- a/test/files/neg/patmatexhaust.scala
+++ b/test/files/neg/patmatexhaust.scala
@@ -52,6 +52,10 @@ class TestSealedExhaustive { // compile only
case Ga =>
}
+ def ma6 = List(1,2) match { // give up
+ case List(1,2) =>
+ case x :: xs =>
+ }
def redundant = 1 match { // include this otherwise script won't test this in files/neg
case 1 =>
case 1 =>