diff options
author | Burak Emir <emir@epfl.ch> | 2007-02-03 14:29:11 +0000 |
---|---|---|
committer | Burak Emir <emir@epfl.ch> | 2007-02-03 14:29:11 +0000 |
commit | 4077f049359e931b5dfb03ac9213686499047721 (patch) | |
tree | 80e4b6486c7db68281562b2a5bd5570077025381 /src | |
parent | e92807e3128c0299798eedef18436596bdab2f56 (diff) | |
download | scala-4077f049359e931b5dfb03ac9213686499047721.tar.gz scala-4077f049359e931b5dfb03ac9213686499047721.tar.bz2 scala-4077f049359e931b5dfb03ac9213686499047721.zip |
hacking matcher to death 4 exhaustivity
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/PatternMatchers.scala | 67 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/PatternNodes.scala | 17 |
2 files changed, 68 insertions, 16 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala index 8a2bfb97cc..931e9d9ca7 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala @@ -321,8 +321,23 @@ trait PatternMatchers requires (transform.ExplicitOuter with PatternNodes) { target.and = pBody(caseDef.pos, env.getBoundVars(), guard, body) else if (target.and.isInstanceOf[Body]) updateBody(target.and.asInstanceOf[Body], env.getBoundVars(), guard, body) - else - cunit.error(pat.pos, "duplicate case") + else target.and match { + case _h: Header => + val h = _h.findLast; + + // target.and is a header + // + //print() + //cunit.error(pat.pos, "duplicate case") + h.or = pDefaultPat(caseDef.pos, target.getTpe) + h.or.and = pBody(caseDef.pos, env.getBoundVars(), guard, body) + //print() + //Console.println("tao = "+target.and.or) + //Console.println("tao = "+target.and.or.or) + case _ => + Predef.error("overlapping match at unit = " + cunit + "; cdef = " + caseDef); + + } } protected def updateBody(tree: Body, bound: Array[ValDef], @@ -501,7 +516,7 @@ trait PatternMatchers requires (transform.ExplicitOuter with PatternNodes) { if (ts.length < 2) Predef.error("ill-formed Alternative") val subroot = pConstrPat(header.pos, header.getTpe()) - subroot.and = pHeader(header.pos, header.getTpe(), header.selector.duplicate) + subroot.and = { val h = pHeader(header.pos, header.getTpe(), header.selector.duplicate); h.isSubHeader = true; h } val subenv = new CaseEnv var i = 0; while (i < ts.length) { val target = enter1(ts(i), -1, subroot, subroot.symbol, subenv) @@ -623,6 +638,7 @@ print() bodycond = {h => b.or = h; b} // depends on the side-effect to curHeader (*) null } + case _ => Predef.error("cannot happen"); } if (curHeader eq null) { // check if we have to add a new header //Console.println(" -- adding new header") @@ -930,6 +946,7 @@ print() var patNode = root.and while (patNode ne null) { var node = patNode.or + // we have checked beforehand that certain pattern nodes do not appear while (node ne null) { node match { case DefaultPat() => @@ -959,6 +976,8 @@ print() mappings = insert1(value.toInt,node.and.bodyToTree(),mappings); node = node.or; */ // these correct? + case _ => + Predef.error("cannot happen") } } patNode = patNode.nextH() @@ -1011,7 +1030,10 @@ print() emptySymbolSet else { //Console.println("/"+tpesym) //Console.println(tpesym.children) - tpesym.children.flatMap { x => if(x.hasFlag(Flags.CASE)) (emptySymbolSet+x) else checkExCoverage(x) } + tpesym.children.flatMap { x => + //if(x.hasFlag(Flags.CASE)) (emptySymbolSet+x) else checkExCoverage(x) + checkExCoverage(x) + x + } } def andIsUnguardedBody(p1:PatternNode) = p1.and match { case p: Body => p.guard.length == 1 && p.guard(0) == EmptyTree @@ -1026,6 +1048,9 @@ 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]} = { + if(alternatives1 eq null) return {false, emptySymbolSet, emptySymbolSet} // only case _ + + //Console.println("optimize1("+selType+","+alternatives1+")") 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. @@ -1034,19 +1059,28 @@ print() return {false, null, emptySymbolSet}; // contains cases that have not been covered var coveredCases: SymSet = emptySymbolSet // only case _ - var remainingCases = if(alts ne null) checkExCoverage(selType.symbol) else emptySymbolSet // only case _ + var remainingCases = checkExCoverage(selType.symbol) var cases = 0; def traverse(alts:PatternNode) { + //Console.println("traverse, alts="+alts) alts match { case ConstrPat(_) => + //Console.print("ConstPat! of"+alts.getTpe.symbol) 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)) + } else { + val covered = remainingCases.filter { x => + val enclClass = owner.enclClass + //Console.println("x.tpe is "+x.tpe) + val y = alts.getTpe.prefix.memberType(x) + //Console.println(y + " is sub of "+alts.getTpe+" ? "+isSubType(y, alts.getTpe)); + isSubType(y, alts.getTpe) + } + //Console.println(" covered : "+covered) + coveredCases = coveredCases ++ covered remainingCases = remainingCases -- covered res = false @@ -1071,20 +1105,21 @@ print() case ConstantPat(_) => res = false - case AltPat(branches) => + case AltPat(branchesHeader) => res = false - traverse(branches.or) + //Console.println("----------bfore: "+coveredCases) + branchesHeader.or.forEachAlternative(traverse) + //Console.println("----------after: "+coveredCases) case VariablePat(_) => res = false - } - } - while (alts ne null) { - traverse(alts) - alts = alts.or; + case _:Header | _:Body => + Predef.error("cannot happen") + } } + alts.forEachAlternative(traverse) return {res && (cases > 2), coveredCases, remainingCases}; } // def optimize @@ -1114,7 +1149,7 @@ print() } else if(next ne null) { // ignore, more headers to come // Console.println(next.print("", new StringBuilder()).toString()) - } else { + } else if(! _h.isSubHeader) { // don't check twice (AlternativePat creates subheaders) val realRemainingCases = remainingCases -- carryCovered //Console.println("remain "+remainingCases+" carry covered "+ carryCovered + "real "+realRemainingCases) if(!realRemainingCases.isEmpty) { diff --git a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala index d421c8b5a0..ffe011e458 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala @@ -21,6 +21,13 @@ trait PatternNodes requires transform.ExplicitOuter { var or: PatternNode = _ var and: PatternNode = _ + def forEachAlternative(f: PatternNode => Unit) { // only for header? + var z = this; + while(z ne null) { + f(z) + z = z.or + } + } def bodyToTree(): Tree = this match { case _b:Body => _b.body(0) @@ -276,6 +283,16 @@ trait PatternNodes requires transform.ExplicitOuter { class Header(sel1: Tree, next1: Header) extends PatternNode { var selector: Tree = sel1 var next: Header = next1 + + def findLast: PatternNode = { + var h: Header = this; + while(h.next != null) { h = h.next } + var g: PatternNode = h + while(g.or != null) { g = g.or } + g + } + + var isSubHeader = false; } class Body(bound1: Array[Array[ValDef]], guard1:Array[Tree], body1:Array[Tree]) extends PatternNode { |