summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBurak Emir <emir@epfl.ch>2007-06-18 13:40:24 +0000
committerBurak Emir <emir@epfl.ch>2007-06-18 13:40:24 +0000
commit2ec348815b8b39be06ee09481cc6eb3531a8af51 (patch)
tree510d7e75bb1a6aaaaf16f0dd9efdafaad348055f
parent52ccdc5627e3d3d34019b57560601a7e3ec89483 (diff)
downloadscala-2ec348815b8b39be06ee09481cc6eb3531a8af51.tar.gz
scala-2ec348815b8b39be06ee09481cc6eb3531a8af51.tar.bz2
scala-2ec348815b8b39be06ee09481cc6eb3531a8af51.zip
added setting Xmatchalgo + cleanup of PatternMa...
added setting Xmatchalgo + cleanup of PatternMatchers * more control on which algo get used * removed some obsolete code * added test case
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala5
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternMatchers.scala141
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternNodes.scala3
-rw-r--r--test/files/run/patmatnew.scala51
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
}
+
}