summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/matching/CodeFactory.scala5
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala51
-rw-r--r--src/compiler/scala/tools/nsc/matching/TransMatcher.scala135
-rw-r--r--test/files/neg/patmatexhaust.check2
5 files changed, 104 insertions, 90 deletions
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index 52258b3ae6..9aadc00fc5 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -143,7 +143,6 @@ class Settings(error: String => Unit) {
val Xlinearizer = ChoiceSetting ("-Ylinearizer", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo")
val log = PhasesSetting ("-Ylog", "Log operations in")
val logAll = BooleanSetting ("-Ylog-all", "Log all operations").hideToIDE
- val Xmatchalgo = ChoiceSetting ("-Ymatch-algo", "which match algorithm to use", List("both","par","incr"), "both")
val noimports = BooleanSetting ("-Yno-imports", "Compile without any implicit imports")
val nopredefs = BooleanSetting ("-Yno-predefs", "Compile without any implicit predefined values")
val script = StringSetting ("-Xscript", "object", "compile as a script, wrapping the code into object.main()", "").hideToIDE
diff --git a/src/compiler/scala/tools/nsc/matching/CodeFactory.scala b/src/compiler/scala/tools/nsc/matching/CodeFactory.scala
index 48d8297d5d..163c6743f3 100644
--- a/src/compiler/scala/tools/nsc/matching/CodeFactory.scala
+++ b/src/compiler/scala/tools/nsc/matching/CodeFactory.scala
@@ -79,8 +79,9 @@ trait CodeFactory {
// --------- these are new
-
+/*
final def renamingBind(defaultv: Set[Symbol], scrut: Symbol, ndefault: Tree) = {
+ Console.println("renamingbind "+defaultv+" "+scrut+" "+ndefault)
if (!defaultv.isEmpty) {
var dv: List[Symbol] = Nil
var to: List[Symbol] = Nil
@@ -92,7 +93,7 @@ trait CodeFactory {
tss.traverse(ndefault)
}
}
-
+*/
final def emptynessCheck(vsym: Symbol) = {
if (vsym.tpe.typeSymbol == definitions.SomeClass) // is Some[_]
Literal(Constant(true))
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index 581d1e1332..b65b614de1 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -85,7 +85,7 @@ trait ParallelMatching {
if(!isRightIgnoring(av)) { DBG("\n%%% MixSequence"); return new MixSequence(scrutinee, column, rest) }
else { DBG("\n%%% MixSequenceStar"); return new MixSequenceStar(scrutinee, column, rest) }
}
- if(isSimpleSwitch) { //DBG("\n%%% MixLiterals")
+ if(isSimpleSwitch) { DBG("\n%%% MixLiterals")
return new MixLiterals(scrutinee, column, rest)
}
@@ -273,7 +273,7 @@ trait ParallelMatching {
}
)}
- renamingBind(defaultV, this.scrutinee, ndefault) // each v in defaultV gets bound to scrutinee
+ //?renamingBind(defaultV, this.scrutinee, ndefault) // each v in defaultV gets bound to scrutinee
// make first case a default case.
if(this.scrutinee.tpe.typeSymbol.hasFlag(symtab.Flags.SEALED) && defaultV.isEmpty) {
@@ -382,14 +382,14 @@ trait ParallelMatching {
final def tree(implicit theOwner: Symbol, failTree: Tree): Tree = {
val (branches, defaultV, defaultRepOpt) = this.getTransition // tag body pairs
- //DBG("[[mix literal transition: branches \n"+(branches.mkString("","\n",""))+"\ndefaults:"+defaultV+"\n"+defaultRepOpt+"\n]]")
+ DBG("[[mix literal transition: branches \n"+(branches.mkString("","\n",""))+"\ndefaults:"+defaultV+"\n"+defaultRepOpt+"\n]]")
val cases = branches map {
case (tag, r) =>
- CaseDef(Literal(tag), EmptyTree, repToTree(rep.make(r.temp, r.row map { case Row(pat,bnd,g,bx) => Row(pat,bindVars(tag,bnd),g,bx) })))
+ val r2 = rep.make(r.temp, r.row map { case Row(pat,bnd,g,bx) => Row(pat,bindVars(tag,bnd),g,bx) })
+ val t2 = repToTree(r2)
+ CaseDef(Literal(tag), EmptyTree, t2)
}
var ndefault = if(defaultRepOpt.isEmpty) failTree else repToTree(defaultRepOpt.get)
-
- renamingBind(defaultV, this.scrutinee, ndefault) // each v in defaultV gets bound to scrutinee
if(cases.length == 1) {
val CaseDef(lit,_,body) = cases.head
If(Equals(mkIdent(this.scrutinee),lit), body, ndefault)
@@ -430,14 +430,14 @@ trait ParallelMatching {
val ures = newVarCapture(ua.pos, app.tpe)
val n = args.length
val uacall = typedValDef(ures, Apply(fn, mkIdent(scrutinee) :: appargs.tail))
- //Console.println("uacall:"+uacall)
+ //DBG("uacall:"+uacall)
val nrowsOther = column.tail.zip(rest.row.tail) flatMap { case (pat, Row(ps, subst, g, bx)) => strip2(pat) match {
case UnApply(app @ Apply(fn1,_),args) if fn.symbol==fn1.symbol => Nil
case _ => List(Row(pat::ps, subst, g, bx))
}}
val nrepFail = if(nrowsOther.isEmpty) None else Some(rep.make(scrutinee::rest.temp, nrowsOther))
- //Console.println("active = "+column.head+" / nrepFail = "+nrepFail)
+ //DBG("active = "+column.head+" / nrepFail = "+nrepFail)
n match {
case 0 => //special case for unapply(), app.tpe is boolean
val ntemps = scrutinee :: rest.temp
@@ -470,7 +470,7 @@ trait ParallelMatching {
vdefs += typedValDef(uresGet, Select(mkIdent(ures), nme.get))
var ts = definitions.getProductArgs(uresGet.tpe).get
var i = 1;
- //Console.println("typeargs"+ts)
+ //DBG("typeargs"+ts)
val vsyms = new ListBuffer[Symbol]
while(ts ne Nil) {
val vtpe = ts.head
@@ -684,7 +684,7 @@ trait ParallelMatching {
final def tree(implicit theOwner: Symbol, failTree: Tree) = {
val (cond, srep, fLabel, frep) = this.getTransition
- //Console.println("MixEquals::tree -- cond "+cond)
+ //DBG("MixEquals::tree -- cond "+cond)
val cond2 = typed { rep.handleOuter(cond) }
//DBG("MixEquals, srep = "+srep)
//DBG("MixEquals, frep = "+frep)
@@ -714,7 +714,7 @@ trait ParallelMatching {
val isExhaustive = !scrutinee.tpe.typeSymbol.hasFlag(symtab.Flags.SEALED) || {
//DEBUG("check exha for column "+column)
- val tpes = column.map {x => /*Console.println("--x:"+x+":"+x.tpe); */ x.tpe.typeSymbol}
+ val tpes = column.map {x => x.tpe.typeSymbol}
scrutinee.tpe.typeSymbol.children.forall { sym => tpes.contains(sym) }
}
@@ -985,13 +985,13 @@ trait ParallelMatching {
case blck @ Block(vdefs, ld @ LabelDef(name,params,body)) =>
val bx = labelIndex(ld.symbol)
if((bx >= 0) && !isReachedTwice(bx)) {
- //Console.println("removing labeldef! ")
- //Console.println("ld.symbol = "+ld.symbol)
- //Console.println("bx = "+bx)
- //Console.println("rtwice? "+isReachedTwice(bx))
- //Console.println("reached = "+reached)
- squeezedBlock(vdefs,body)
- }
+ /*Console.println("removing labeldef! ")
+ Console.println("ld.symbol = "+ld.symbol)
+ Console.println("bx = "+bx)
+ Console.println("rtwice? "+isReachedTwice(bx))
+ Console.println("reached = "+reached) */
+ squeezedBlock(vdefs,body)
+ }
else
blck
@@ -1451,11 +1451,8 @@ trait ParallelMatching {
/** creates initial clause matrix
*/
- final def initRep(selector: Tree, cases: List[Tree], checkExhaustive: Boolean, rep:RepFactory)(implicit theOwner: Symbol) = {
- val root = newVar(selector.pos, selector.tpe)
+ final def initRep(roots: List[Symbol], cases: List[Tree], rep:RepFactory)(implicit theOwner: Symbol) = {
// communicate whether exhaustiveness-checking is enabled via some flag
- if (!checkExhaustive)
- root.setFlag(symtab.Flags.TRANS_FLAG)
var bx = 0;
val targets = new ListBuffer[Tree]
val vss = new ListBuffer[SymList]
@@ -1467,12 +1464,18 @@ trait ParallelMatching {
//Console.println("dv ::"+definedVars(pat))
vss += definedVars(pat)
targets += b
- row += Row(List(pat), NoBinding, g, bx)
+ if(roots.length > 1) pat match {
+ case Apply(fn, pargs) =>
+ row += Row(pargs, NoBinding, g, bx)
+ case Ident(nme.WILDCARD) =>
+ row += Row(getDummies(roots.length), NoBinding, g, bx)
+ } else
+ row += Row(List(pat), NoBinding, g, bx)
bx += 1
cs = cs.tail
}
//Console.println("leaving initRep")
- /*val res = */rep.make(List(root), row.toList, targets.toList, vss.toList)
+ /*val res = */rep.make(roots, row.toList, targets.toList, vss.toList)
//Console.println("left initRep")
//res
}
diff --git a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
index 8d34031136..2a244f028d 100644
--- a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
+++ b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
@@ -31,32 +31,8 @@ trait TransMatcher { self: transform.ExplicitOuter with PatternNodes with Parall
// cache these
final val settings_debug = settings.debug.value
final val settings_squeeze = settings.Xsqueeze.value == "on"
- final val settings_useParallel = settings.Xmatchalgo.value != "incr"
- final val settings_useIncr = settings.Xmatchalgo.value != "par"
final val settings_casetags = settings.Xcasetags.value == "on"
- /** returns true if apply is a "sequence apply". analyzer inserts Sequence nodes if something is a
- *
- * - last update: discussion with Martin 2005-02-18
- *
- * - if true, tree.fn must be ignored. The analyzer ensures that the selector will be a subtype
- * of fn; it thus assigns the expected type from the context (which is surely a subtype,
- * but may have different flags etc.
- *
- * - so should be
- * (( tree.args.length == 1 ) && tree.args(0).isInstanceOf[Sequence])
- * but fails
- */
- final def isSeqApply(tree: Apply): Boolean = {
- tree match {
- case Apply(_, List(ArrayValue(_,_))) => (tree.tpe.typeSymbol.flags & Flags.CASE) == 0
- case _ => false;
- }
- }
-
- /**
- */
-
final def hasRegularPattern(pats1: List[Tree]): Boolean = {
var pats = pats1; while(pats ne Nil) {
if(isRegularPattern(pats.head)) { return true; } else { pats = pats.tail }
@@ -135,8 +111,16 @@ trait TransMatcher { self: transform.ExplicitOuter with PatternNodes with Parall
case UnApply(fn, args) => copy.UnApply(pat, fn, args map { isRegular1 })
- // a pattern of the form List(foo@_*)
- case app @ Apply(fn, List(pat2@ ArrayValue( tt, List(b @ Bind(id, Star(wc @ Ident(nme.WILDCARD))))))) if isSeqApply(app) =>
+ /* a pattern of the form List(foo@_*), also called "sequence apply".
+ *
+ * - last update: discussion with Martin 2005-02-18
+ *
+ * - tree.fn must be ignored. The analyzer ensures that the selector will be a subtype
+ * of fn; it thus assigns the expected type from the context (which is surely a subtype,
+ * but may have different flags etc.
+ */
+ case app @ Apply(fn, List(pat2@ ArrayValue( tt, List(b @ Bind(id, Star(wc @ Ident(nme.WILDCARD))))))) if
+ (app.tpe.typeSymbol.flags & Flags.CASE) == 0 =>
//Console.println("OPTIMIZING")
//Console.println(pat)
//Console.println(pat.tpe)
@@ -241,48 +225,76 @@ trait TransMatcher { self: transform.ExplicitOuter with PatternNodes with Parall
//sel
EmptyTree
} else {
+ implicit val theOwner = owner
+ if (settings_debug) {
+ Console.println("****")
+ Console.println("**** initalize, selector = "+selector+" selector.tpe = "+selector.tpe)
+ Console.println("**** doCheckExhaustive == "+doCheckExhaustive)
+ }
+ implicit val rep = new RepFactory(handleOuter)
+ try {
+
+ val tmps = new ListBuffer[Symbol]
+ val vds = new ListBuffer[Tree]
+ var root:Symbol = newVar(selector.pos, selector.tpe)
+ if (!doCheckExhaustive)
+ root.setFlag(symtab.Flags.TRANS_FLAG)
+
+ var vdef:Tree = typed{ValDef(root, selector)}
+ var theFailTree:Tree = ThrowMatchError(selector.pos, mkIdent(root))
+
+ if(definitions.isTupleType(selector.tpe)) selector match {
+ case app @ Apply(fn, args)
+ if (fn.symbol eq selector.tpe.decls.lookup(nme.CONSTRUCTOR)) &&
+ (cases forall { x => x match {
+ case CaseDef(Apply(fn, pargs),_,_) => true ;
+ case CaseDef(Ident(nme.WILDCARD),_,_) => true ;
+ case _ => false
+ }}) =>
+ var i = 0
+ var as = args
+ while(as ne Nil) {
+ val ti = as.head
+ val v = newVar(ti.pos, cunit.fresh.newName("tp"), selector.tpe.typeArgs(i))
+ if (!doCheckExhaustive)
+ v.setFlag(symtab.Flags.TRANS_FLAG)
+ vds += typedValDef(v, ti)
+ tmps += v
+ i = i + 1
+ as = as.tail
+ }
+ theFailTree = ThrowMatchError(selector.pos, copy.Apply(app, fn, tmps.toList map mkIdent))
+ case _ =>
+ tmps += root
+ vds += vdef
+ } else {
+ tmps += root
+ vds += vdef
+ }
+ val irep = initRep(tmps.toList, cases, rep)
+ implicit val fail: Tree = theFailTree
-//
-
- implicit val theOwner = owner
- if (settings_debug) {
- Console.println("****")
- Console.println("**** initalize, selector = "+selector+" selector.tpe = "+selector.tpe)
- Console.println("**** doCheckExhaustive == "+doCheckExhaustive)
- }
-
- implicit val rep = new RepFactory(handleOuter)
- try {
- val irep = initRep(selector, cases, doCheckExhaustive, rep)
- val root = irep.temp.head
-
- implicit val fail: Tree = ThrowMatchError(selector.pos, mkIdent(root))
- val vdef = typed{ValDef(root, selector)}
-
- val mch = typed{repToTree(irep)}
- var dfatree = typed{squeezedBlock(List(vdef), mch)}
+ val mch = typed{ repToTree(irep)}
+ var dfatree = typed{squeezedBlock(vds.toList, mch)}
- //DEBUG("**** finished\n"+dfatree.toString)
- var bx = 0; var cs = cases; while(cs ne Nil) {
- if(!rep.isReached(bx)) {
- cunit.error(cs.head.asInstanceOf[CaseDef].body.pos, "unreachable code")
+ //DEBUG("**** finished\n"+dfatree.toString)
+ var bx = 0; var cs = cases; while(cs ne Nil) {
+ if(!rep.isReached(bx)) {
+ cunit.error(cs.head.asInstanceOf[CaseDef].body.pos, "unreachable code")
+ }
+ cs = cs.tail
+ bx += 1
}
- cs = cs.tail
- bx += 1
+ dfatree = rep.cleanup(dfatree)
+ resetTrav.traverse(dfatree)
+ return dfatree
+ } catch {
+ case e => e.printStackTrace(); throw new FatalError(e.getMessage())
}
- dfatree = rep.cleanup(dfatree)
- resetTrav.traverse(dfatree)
-
- //constructParallel(cases) // ZZZ
- return dfatree
- } catch {
- case e => e.printStackTrace(); throw new FatalError(e.getMessage())
- }
-
}
- }
+ }
object resetTrav extends Traverser {
override def traverse(x:Tree): unit = x match {
@@ -296,5 +308,4 @@ trait TransMatcher { self: transform.ExplicitOuter with PatternNodes with Parall
}
}
-
}
diff --git a/test/files/neg/patmatexhaust.check b/test/files/neg/patmatexhaust.check
index 719f98b8d3..7cdf43c8ca 100644
--- a/test/files/neg/patmatexhaust.check
+++ b/test/files/neg/patmatexhaust.check
@@ -13,7 +13,7 @@ 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!
missing combination Gu
missing combination Gp