diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/Settings.scala | 5 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/PatternMatchers.scala | 141 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/PatternNodes.scala | 3 | ||||
-rw-r--r-- | test/files/run/patmatnew.scala | 51 |
4 files changed, 118 insertions, 82 deletions
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala index dd404250fd..b5dab7c2cf 100644 --- a/src/compiler/scala/tools/nsc/Settings.scala +++ b/src/compiler/scala/tools/nsc/Settings.scala @@ -144,7 +144,10 @@ class Settings(error: String => Unit) { val Xexperimental = BooleanSetting("-Xexperimental", "enable experimental extensions") val Xplugtypes = BooleanSetting("-Xplugtypes", "process annotations on types") //Xplugtypes.value = true // just while experimenting - val Xkilloption = BooleanSetting("-Xkilloption", "optimizes option types") + + // for benchmarking purposes + val Xmatchalgo = ChoiceSetting("-Xmatchalgo", "which match algorithm to use", List("both","par","incr"), + /*default*/"both") /** scaladoc specific options */ val windowtitle = StringSetting("-windowtitle", "windowtitle", diff --git a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala index cbdb58633e..49ba0e5593 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala @@ -122,32 +122,28 @@ trait PatternMatchers { self: transform.ExplicitOuter with PatternNodes with Par /** enters a sequence of cases into the pattern matcher */ def construct(cases: List[Tree]): Unit = { nPatterns = nPatterns + 1 - try { - object hasUnapply extends Traverser { - override def traverse(x:Tree) = { - //Console.println("pat:'"+x+"' / "+x.getClass) - x match { - case _:ArrayValue => throw CantHandleSeq - case _:UnApply => throw CantHandleUnapply - case Ident(n) if n!= nme.WILDCARD => - //DEBUG("I can't handle IDENT pattern:"+x) - //DEBUG("x.tpe.symbols:"+x.tpe.symbol) - throw CantHandleIdent - case p:Select => - //case p:Select => - // //DEBUG("I can't handle SELECT pattern:"+p) - // //DEBUG("p.tpe.symbols:"+p.tpe.symbol) - //throw CantHandleUnapply - case p@Apply(_,_) if !p.tpe.symbol.hasFlag(symtab.Flags.CASE) => - //DEBUG("I can't handle APPLY pattern:"+p) - //DEBUG("p.tpe.symbols:"+p.tpe.symbol) - throw CantHandleApply - //case p@Apply(_,_) if !p.tpe.symbol.hasFlag(symtab.Flags.CASE) => throw CantHandleUnapply //@todo - case _ => super.traverse(x) + if(global.settings.Xmatchalgo.value != "incr") + try { + constructParallel(cases) + return + } catch { + case e => + if(global.settings.Xmatchalgo.value == "par") + throw e + if (settings.debug.value) { + e.printStackTrace() + Console.println("****") + Console.println("**** falling back, cause " + e.getMessage) + Console.println("****") + for (CaseDef(pat,guard,_) <- cases) + Console.println(pat.toString) } } - } + constructIncremental(cases) + } + + def constructParallel(cases: List[Tree]) { cases foreach { case CaseDef(pat,_,_) => hasUnapply.traverse(pat) } if(cases.forall{case CaseDef(_,x,_) => x == EmptyTree}) { val irep = initRep(selector, cases, doCheckExhaustive) @@ -174,46 +170,60 @@ trait PatternMatchers { self: transform.ExplicitOuter with PatternNodes with Par cunit.error(b.pos, "unreachable code") } - object resetTrav extends Traverser { - override def traverse(x:Tree): unit = x match { - case vd @ ValDef(_,_,_,_)=> - vd.symbol.resetFlag(symtab.Flags.CAPTURED) - if(vd.symbol.hasFlag(symtab.Flags.TRANS_FLAG)) { - vd.symbol.resetFlag(symtab.Flags.TRANS_FLAG) - vd.symbol.resetFlag(symtab.Flags.MUTABLE) - } - case _ => - super.traverse(x) - } - } resetTrav.traverse(dfatree) //constructParallel(cases) // ZZZ nParallel = nParallel + 1 - return - } else throw CantHandleGuard - } catch { - case e: CantHandle => // fall back - //DEBUG("****") - //DEBUG("**** falling back, "+e.getClass) - //DEBUG("****") - - case CantHandleGuard => // fall back (actually already fell back before) - case e => - //throw e - if (settings.debug.value) { - e.printStackTrace() - Console.println("****") - Console.println("**** falling back, cause " + e.getMessage) - Console.println("****") - for (CaseDef(pat,guard,_) <- cases) - Console.println(pat.toString) - } + } else { + throw CantHandleGuard } + } + + /** constructs match-translation incrementally */ + private def constructIncremental(cases:List[Tree]) { doCheckExhaustive = false cases foreach enter } + object resetTrav extends Traverser { + override def traverse(x:Tree): unit = x match { + case vd @ ValDef(_,_,_,_)=> + vd.symbol.resetFlag(symtab.Flags.CAPTURED) + if(vd.symbol.hasFlag(symtab.Flags.TRANS_FLAG)) { + vd.symbol.resetFlag(symtab.Flags.TRANS_FLAG) + vd.symbol.resetFlag(symtab.Flags.MUTABLE) + } + case _ => + super.traverse(x) + } + } + + object hasUnapply extends Traverser { + override def traverse(x:Tree) = { + //Console.println("pat:'"+x+"' / "+x.getClass) + x match { + case _:ArrayValue => throw CantHandleSeq + case _:UnApply => throw CantHandleUnapply + case Ident(n) if n!= nme.WILDCARD => + //DEBUG("I can't handle IDENT pattern:"+x) + //DEBUG("x.tpe.symbols:"+x.tpe.symbol) + throw CantHandleIdent + case p:Select => + //case p:Select => + // //DEBUG("I can't handle SELECT pattern:"+p) + // //DEBUG("p.tpe.symbols:"+p.tpe.symbol) + //throw CantHandleUnapply + case p@Apply(_,_) if !p.tpe.symbol.hasFlag(symtab.Flags.CASE) => + //DEBUG("I can't handle APPLY pattern:"+p) + //DEBUG("p.tpe.symbols:"+p.tpe.symbol) + throw CantHandleApply + + //case p@Apply(_,_) if !p.tpe.symbol.hasFlag(symtab.Flags.CASE) => throw CantHandleUnapply //@todo + case _ => super.traverse(x) + } + } + } + /** enter a single case into the pattern matcher */ protected def enter(caseDef: Tree): Unit = caseDef match { case CaseDef(pat, guard, body) => @@ -295,7 +305,6 @@ trait PatternMatchers { self: transform.ExplicitOuter with PatternNodes with Par node case t @ UnApply(fn, args) => - doCheckExhaustive = false // just seeing unapply pattern disables exhaustiveness check for whole match pUnapplyPat(tree.pos, fn) case t @ Apply(fn, args) => // pattern with args @@ -895,7 +904,6 @@ print() var res: Tree = Literal(Constant(false)); //.setInfo(defs.BooleanClass); var lastSelector: Tree = null var carryCovered: SymSet = emptySymbolSet - val oldDoCheckExhaustive = doCheckExhaustive while (node ne null) node match { @@ -906,31 +914,11 @@ print() if(selector != lastSelector) { carryCovered = emptySymbolSet; } - doCheckExhaustive = doCheckExhaustive && !_h.catchesAll // nice global variable here - //Console.print("doCheckExhaustive? "+doCheckExhaustive+ " ") //Console.println(" catches all?"+_h.catchesAll) //Console.println("sel:"+selector+" last"+lastSelector+" - "+(selector == lastSelector)) val next = _h.next; //res = And(mkNegate(res), toTree(node.or, selector)); val (doOptimize, coveredCases, remainingCases) = _h.optimize1() - if(!remainingCases.isEmpty && doCheckExhaustive) { - carryCovered = carryCovered ++ coveredCases // ?? - if(next != null && next.or.and.isUnguardedBody) { - // ignore, default case - } else if(next ne null) { - // ignore, more headers to come - // Console.println(next.print("", new StringBuilder()).toString()) - } 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) { - val word = if(realRemainingCases.size > 1) "cases " else "case " - cunit.warning(node.pos, "does not cover "+word+realRemainingCases.elements.mkString("{",",","}")) - //Console.println("full"); print() - //Console.println(_h.print("", new StringBuilder()).toString()) - } - } - } if (doOptimize) res = Or(res, toOptTree(node.or, selector)); else @@ -975,7 +963,6 @@ print() case _ => scala.Predef.error("error in toTree"); } - doCheckExhaustive = oldDoCheckExhaustive return res } diff --git a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala index ad6de9ca1c..6562204488 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala @@ -339,13 +339,14 @@ trait PatternNodes { self: transform.ExplicitOuter => } var isSubHeader = false; - // returns true if this header node has a catch all case + /* returns true if this header node has a catch all case def catchesAll: Boolean = { //Console.println(this.print(" catchesAll %%%%", new StringBuilder()).toString) val p = findLast (p.isDefaultPat && p.and.isUnguardedBody) } + */ // executes an action for every or branch def forEachBranch(f: PatternNode => Unit) { if(or ne null) or.forEachAlternative(f) } diff --git a/test/files/run/patmatnew.scala b/test/files/run/patmatnew.scala index f8216177cd..0e7359a2b8 100644 --- a/test/files/run/patmatnew.scala +++ b/test/files/run/patmatnew.scala @@ -22,10 +22,10 @@ object Test extends TestConsoleMain { new Test717, new TestGuards, new TestStream, + new Test903, new Test1163_Order ) - class Foo(j:Int) { case class Bar(i:Int) } @@ -122,8 +122,52 @@ object Test extends TestConsoleMain { trait NodeImpl; trait IfImpl; private def coerceIf(node : Node) = node match { - case node : IfImpl => node; // var node is of type Node with IfImpl! - case _ => null; + case node : IfImpl => node; // var node is of type Node with IfImpl! + case _ => null; + } + } + } + + + class Person(_name : String, _father : Person) { + def name = _name + def father = _father + } + + object PersonFather { + def unapply(p : Person) : Option[Person] = + if (p.father == null) + None + else + Some(p.father) + } + + class Test903 extends TestCase("bug903") { + + override def runTest = { + val p1 = new Person("p1",null) + val p2 = new Person("p2",p1) + assertEquals((p2.name, p1.name), p2 match { + case aPerson@PersonFather(f) => (aPerson.name,f.name) + case _ => "No father" + }) + } + } + + + object Foo1 { + class Bar1(val x : String) + def p(b : Bar1) = Console.println(b.x) + + def unapply(s : String) : Option[Bar1] = + Some(new Bar1(s)) + } + + object bug881 extends TestCase("881") { + override def runTest = { + "baz" match { + case Foo1(x) => + Foo1.p(x) } } } @@ -178,5 +222,6 @@ object Test extends TestConsoleMain { def lala() = 42 match { case FooBar => true } + } |