summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBurak Emir <emir@epfl.ch>2007-08-21 15:34:22 +0000
committerBurak Emir <emir@epfl.ch>2007-08-21 15:34:22 +0000
commit2ddb10dfa4f88208ed651a3d9a0e79720c74462c (patch)
tree2533a2c468cca7090c2daf94a1f5b4c8c0269c84
parent082e881d0aa519228027bb8cdcfea864af484680 (diff)
downloadscala-2ddb10dfa4f88208ed651a3d9a0e79720c74462c.tar.gz
scala-2ddb10dfa4f88208ed651a3d9a0e79720c74462c.tar.bz2
scala-2ddb10dfa4f88208ed651a3d9a0e79720c74462c.zip
fix #1282, optimized translation of List.unappl...
fix #1282, optimized translation of List.unapplySeq / List(p1...pN) patterns
-rw-r--r--src/compiler/scala/tools/nsc/matching/CodeFactory.scala8
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala363
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternMatchers.scala120
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternNodes.scala59
-rw-r--r--src/compiler/scala/tools/nsc/matching/TransMatcher.scala6
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Scopes.scala3
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala9
-rw-r--r--test/files/run/patmatnew.scala9
9 files changed, 364 insertions, 215 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/CodeFactory.scala b/src/compiler/scala/tools/nsc/matching/CodeFactory.scala
index ee5741dfa1..d2facaf2a9 100644
--- a/src/compiler/scala/tools/nsc/matching/CodeFactory.scala
+++ b/src/compiler/scala/tools/nsc/matching/CodeFactory.scala
@@ -132,12 +132,12 @@ trait CodeFactory {
/** for tree of sequence type, returns tree that drops first i elements */
final def seqDrop(sel:Tree, ix: Int) = if (ix == 0) sel else
- Apply(Select(Select(sel, nme.toList), nme.drop),
- List(Literal(Constant(ix))))
+ typed { Apply(Select(Select(sel, nme.toList), nme.drop),
+ List(Literal(Constant(ix)))) }
/** for tree of sequence type, returns tree that drops first i elements */
- final def seqElement(sel:Tree, ix: Int) = if (ix == 0) sel else
- Apply(Select(sel, sel.tpe.member(nme.apply)), List(Literal(Constant(ix))))
+ final def seqElement(sel:Tree, ix: Int) =
+ typed { Apply(Select(sel, sel.tpe.member(nme.apply)), List(Literal(Constant(ix)))) }
/** for tree of sequence type, returns boolean tree that has length i */
final def seqHasLength(sel: Tree, ntpe: Type, i: Int) =
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index 72b8645e7e..9677fe9c1d 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -11,8 +11,16 @@ import collection.mutable.ListBuffer
/** Translation of Match Expressions
*
+ * `p': pattern
* `bx': body index
*
+ * internal representation is (temp:List[Symbol], row:List[Row])
+ *
+ * tmp1 tmp_n
+ * Row( p_11 ... p_1n g_1 b_1 ) + subst
+ *
+ * Row( p_m1 ... p_mn g_m b_m ) + subst
+ *
* @author Burak Emir
*/
trait ParallelMatching {
@@ -25,7 +33,7 @@ trait ParallelMatching {
/** here, we distinguish which rewrite rule to apply
* @pre column does not contain alternatives (ensured by initRep)
*/
- def MixtureRule(scrutinee:Symbol, column:List[Tree], rest:Rep): RuleApplication = {
+ def MixtureRule(scrutinee:Symbol, column:List[Tree], rest:Rep)(implicit rep:RepFactory): RuleApplication = {
def isSimpleSwitch: Boolean = {
(isSameType(scrutinee.tpe.widen, definitions.IntClass.tpe)||
@@ -82,10 +90,10 @@ trait ParallelMatching {
return new MixEquals(scrutinee, column, rest)
}
// the next condition is never true, @see isImplemented/CantHandleSeq
- //if(column.head.isInstanceOf[ArrayValue]) { DBG("\n%%% MixArrayValue");
- // Console.println("STOP"); System.exit(-1); // EXPERIMENTAL
+ if(column.head.isInstanceOf[ArrayValue]) { DBG("\n%%% MixSequence");
+ throw new FatalError("not implemented yet");
//return new MixSequence(scrutinee, column, rest)
- //}
+ }
if(isSimpleSwitch) { DBG("\n%%% MixLiterals")
return new MixLiterals(scrutinee, column, rest)
}
@@ -107,11 +115,11 @@ trait ParallelMatching {
// ---------------------------------- data
- sealed trait RuleApplication {
+ sealed abstract class RuleApplication(rep:RepFactory) {
def scrutinee:Symbol
// used in MixEquals and MixSequence
- final protected def repWithoutHead(col:List[Tree],rest:Rep): Rep = {
+ final protected def repWithoutHead(col:List[Tree],rest:Rep)(implicit theOwner:Symbol): Rep = {
var fcol = col.tail
var frow = rest.row.tail
val nfailrow = new ListBuffer[Row]
@@ -123,37 +131,52 @@ trait ParallelMatching {
fcol = fcol.tail
frow = frow.tail
}
- Rep(scrutinee::rest.temp, nfailrow.toList)
+ rep.make(scrutinee::rest.temp, nfailrow.toList)
}
/** translate outcome of the rule application into code (possible involving recursive application of rewriting) */
- def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree): Tree
+ def tree(implicit handleOuter: HandleOuter, localTyper: LocalTyper, theOwner: Symbol, failTree: Tree): Tree
}
- case class ErrorRule extends RuleApplication {
+ case class ErrorRule(implicit rep:RepFactory) extends RuleApplication(rep) {
def scrutinee:Symbol = throw new RuntimeException("this never happens")
- final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) = failTree
+ final def tree(implicit handleOuter: HandleOuter, localTyper: LocalTyper, theOwner: Symbol, failTree: Tree) = failTree
}
- case class VariableRule(subst:Binding, guard: Tree, guardedRest:Rep, bx: Int) extends RuleApplication {
+ /** {case ... if guard => bx} else {guardedRest} */
+ case class VariableRule(subst:Binding, guard: Tree, guardedRest:Rep, bx: Int)(implicit rep:RepFactory) extends RuleApplication(rep) {
def scrutinee:Symbol = throw new RuntimeException("this never happens")
- final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree): Tree = {
- val body = typed { Rep.requestBody(bx, subst) }
+ final def tree(implicit handleOuter: HandleOuter, localTyper: LocalTyper, theOwner: Symbol, failTree: Tree): Tree = {
+ val body = typed { rep.requestBody(bx, subst) }
if(guard eq EmptyTree)
return body
-
+ //Console.println("guard in variable rule"+guard)
val vdefs = targetParams(subst)
- val typedElse = repToTree(guardedRest, handleOuter)
- //Console.println("typedElse:"+typedElse)
- val untypedIf = If(guard, body, typedElse)
- val r = atPhase(phase.prev) { typed { squeezedBlock(vdefs, untypedIf) }}
- //Console.println("genBody-guard:"+r)
+ val typedElse = repToTree(guardedRest, handleOuter,localTyper)
+
+ // crucial: use local typer, it has the the context needed to enter new class symbols
+ val otyper = localTyper//typer.atOwner(theOwner)
+ val resetGuard = resetAttrs(guard.duplicate)
+ val typedGuard0 = atPhase(phase.prev) {otyper.typed{ resetGuard }}
+ val typedGuard = handleOuter(typedGuard0)
+ val typedIf = typed{If(typedGuard, body, typedElse)}
+
+ val r = try {
+ typer.typed { squeezedBlock(vdefs, typedIf) }/*} */
+ } catch {
+ case e => e.printStackTrace();
+ throw new FatalError(e.getMessage());
+ null
+ }
+ //Console.println("genBody-guard PRE:"+r)
+ //val r2 = handleOuter(r)
+ //Console.println("genBody-guard POST:"+r2)
r
- } /* def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) */
+ } /* def tree(implicit handleOuter: HandleOuter, theOwner: Symbol, failTree: Tree) */
}
- abstract class CaseRuleApplication extends RuleApplication {
+ abstract class CaseRuleApplication(rep:RepFactory) extends RuleApplication(rep) {
def column: List[Tree]
def rest:Rep
@@ -194,7 +217,7 @@ trait ParallelMatching {
}
/** inserts row indices using in to list of tagindexpairs*/
- protected def tagIndicesToReps = {
+ protected def tagIndicesToReps(implicit theOwner: Symbol) = {
val defaultRows = getDefaultRows
var trs:List[(Int,Rep)] = Nil
var old = tagIndexPairs
@@ -206,13 +229,13 @@ trait ParallelMatching {
tagRows = this.grabRow(tagIndexPairs.index)::tagRows
tagIndexPairs = tagIndexPairs.next
}
- trs = (tag, Rep(this.grabTemps, tagRows ::: defaultRows)) :: trs
+ trs = (tag, rep.make(this.grabTemps, tagRows ::: defaultRows)) :: trs
}
tagIndexPairs = old
trs
}
- protected def defaultsToRep = Rep(rest.temp, getDefaultRows)
+ protected def defaultsToRep(implicit theOwner: Symbol) = rep.make(rest.temp, getDefaultRows)
protected def insertTagIndexPair(tag: Int, index: Int) { tagIndexPairs = TagIndexPair.insert(tagIndexPairs, tag, index) }
@@ -230,7 +253,7 @@ trait ParallelMatching {
*
* this rule gets translated to a switch of _.$tag()
**/
- class MixCases(val scrutinee:Symbol, val column:List[Tree], val rest:Rep) extends CaseRuleApplication {
+ class MixCases(val scrutinee:Symbol, val column:List[Tree], val rest:Rep)(implicit rep:RepFactory) extends CaseRuleApplication(rep) {
/** insert row indices using in to list of tagindexpairs */
{
@@ -252,13 +275,13 @@ trait ParallelMatching {
Row(column(tagIndexPairs.index)::pats, nbindings, g, bx)
}
- final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree): Tree = {
+ final def tree(implicit handleOuter: HandleOuter, localTyper: LocalTyper, theOwner: Symbol, failTree: Tree): Tree = {
val (branches, defaultV, default) = getTransition // tag body pairs
DBG("[[mix cases transition: branches \n"+(branches.mkString("","\n","")+"\ndefaults:"+defaultV+" "+default+"]]"))
- var ndefault = if(default.isEmpty) failTree else repToTree(default.get, handleOuter)
+ var ndefault = if(default.isEmpty) failTree else repToTree(default.get, handleOuter,localTyper)
var cases = branches map {
- case (tag, rep) =>
+ case (tag, r) =>
CaseDef(Literal(tag),
EmptyTree,
{
@@ -268,10 +291,10 @@ trait ParallelMatching {
//cast
val vtmp = newVar(pat.pos, ptpe)
squeezedBlock(
- List(typedValDef(vtmp, gen.mkAsInstanceOf(Ident(this.scrutinee),ptpe))),
- repToTree(Rep(vtmp::rep.temp.tail, rep.row),handleOuter)
+ List(typedValDef(vtmp, gen.mkAsInstanceOf(Ident(this.scrutinee), ptpe))),
+ repToTree(rep.make(vtmp :: r.temp.tail, r.row),handleOuter,localTyper)
)
- } else repToTree(rep, handleOuter)
+ } else repToTree(r, handleOuter,localTyper)
}
)}
@@ -290,7 +313,7 @@ trait ParallelMatching {
case _ => val defCase = CaseDef(mk_(definitions.IntClass.tpe), EmptyTree, ndefault)
Match(Select(Ident(this.scrutinee),nme.tag), cases ::: defCase :: Nil)
}
- } /* def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) */
+ } /* def tree(implicit handleOuter: HandleOuter, theOwner: Symbol, failTree: Tree) */
} /* MixCases */
/**
@@ -308,7 +331,7 @@ trait ParallelMatching {
*
* this rule gets translated to a switch. all defaults/same literals are collected
**/
- class MixLiterals(val scrutinee:Symbol, val column:List[Tree], val rest:Rep) extends CaseRuleApplication {
+ class MixLiterals(val scrutinee:Symbol, val column:List[Tree], val rest:Rep)(implicit rep:RepFactory) extends CaseRuleApplication(rep) {
private var defaultIndexSet: Set64 = if(column.length < 64) new Set64 else null
@@ -346,7 +369,7 @@ trait ParallelMatching {
if(!pvars.isEmpty) cunit.error(pos, "nonsensical variable binding")
}
- {
+ /*block*/{
var xs = column
var i = 0;
while(xs ne Nil) { // forall
@@ -358,13 +381,13 @@ trait ParallelMatching {
i += 1
xs = xs.tail
}
- }
+ }/*end block*/
- final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree): Tree = {
+ final def tree(implicit handleOuter: HandleOuter, localTyper: LocalTyper, 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]]")
- val cases = branches map { case (tag, rep) => CaseDef(Literal(tag), EmptyTree, repToTree(rep, handleOuter)) }
- var ndefault = if(defaultRepOpt.isEmpty) failTree else repToTree(defaultRepOpt.get, handleOuter)
+ val cases = branches map { case (tag, rep) => CaseDef(Literal(tag), EmptyTree, repToTree(rep, handleOuter,localTyper)) }
+ var ndefault = if(defaultRepOpt.isEmpty) failTree else repToTree(defaultRepOpt.get, handleOuter,localTyper)
renamingBind(defaultV, this.scrutinee, ndefault) // each v in defaultV gets bound to scrutinee
if(cases.length == 1) {
@@ -386,18 +409,18 @@ trait ParallelMatching {
}
return Match(Ident(this.scrutinee), cases ::: defCase :: Nil)
}
- } /* def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) */
+ } /* def tree(implicit handleOuter: HandleOuter, theOwner: Symbol, failTree: Tree) */
} /* MixLiterals */
/**
* mixture rule for unapply pattern
*/
- class MixUnapply(val scrutinee:Symbol, val column:List[Tree], val rest:Rep) extends RuleApplication {
+ class MixUnapply(val scrutinee:Symbol, val column:List[Tree], val rest:Rep)(implicit rep:RepFactory) extends RuleApplication(rep) {
def newVarCapture(pos:Position,tpe:Type)(implicit theOwner:Symbol) = {
val v = newVar(pos,tpe)
- if(scrutinee.hasFlag(symtab.Flags.CAPTURED))
- v.setFlag(symtab.Flags.CAPTURED) // propagate "unchecked"
+ if(scrutinee.hasFlag(symtab.Flags.TRANS_FLAG))
+ v.setFlag(symtab.Flags.TRANS_FLAG) // propagate "unchecked"
v
}
@@ -419,7 +442,7 @@ trait ParallelMatching {
case UnApply(app @ Apply(fn1,_),args) if fn.symbol==fn1.symbol => Nil
case p => List(Row(pat::ps, subst, g, bx))
}}
- val nrepFail = if(nrowsOther.isEmpty) None else Some(Rep(scrutinee::rest.temp, nrowsOther))
+ val nrepFail = if(nrowsOther.isEmpty) None else Some(rep.make(scrutinee::rest.temp, nrowsOther))
//Console.println("active = "+column.head+" / nrepFail = "+nrepFail)
n match {
case 0 => //special case for unapply(), app.tpe is boolean
@@ -431,7 +454,7 @@ trait ParallelMatching {
case _ =>
Row( pat ::ps, subst, g, bx)
}}
- (uacall, rootvdefs, Rep(ntemps, nrows), nrepFail)
+ (uacall, rootvdefs, rep.make(ntemps, nrows), nrepFail)
case 1 => //special case for unapply(p), app.tpe is Option[T]
val vtpe = app.tpe.typeArgs(0)
@@ -444,7 +467,7 @@ trait ParallelMatching {
case _ =>
Row(EmptyTree :: pat :: ps, subst, g, bx)
}}
- (uacall, rootvdefs:::List( typedValDef(vsym, Select(Ident(ures), nme.get))), Rep(ntemps, nrows), nrepFail)
+ (uacall, rootvdefs:::List( typedValDef(vsym, Select(Ident(ures), nme.get))), rep.make(ntemps, nrows), nrepFail)
case _ => // app.tpe is Option[? <: ProductN[T1,...,Tn]]
val uresGet = newVarCapture(ua.pos, app.tpe.typeArgs(0))
@@ -474,22 +497,22 @@ trait ParallelMatching {
case _ =>
Row(dummies::: pat ::ps, subst, g, bx)
}}
- (uacall, rootvdefs:::vdefs.reverse, Rep(ntemps, nrows), nrepFail)
+ (uacall, rootvdefs:::vdefs.reverse, rep.make(ntemps, nrows), nrepFail)
}}
} /* def getTransition(...) */
- final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) = {
+ final def tree(implicit handleOuter: HandleOuter, localTyper: LocalTyper, theOwner: Symbol, failTree: Tree) = {
val (uacall/*:ValDef*/ , vdefs,srep,frep) = this.getTransition // uacall is a Valdef
//Console.println("getTransition"+(uacall,vdefs,srep,frep))
- val succ = repToTree(srep, handleOuter)
- val fail = if(frep.isEmpty) failTree else repToTree(frep.get, handleOuter)
+ val succ = repToTree(srep, handleOuter,localTyper)
+ val fail = if(frep.isEmpty) failTree else repToTree(frep.get, handleOuter,localTyper)
val cond =
if(uacall.symbol.tpe.typeSymbol eq definitions.BooleanClass)
typed{ Ident(uacall.symbol) }
else
emptynessCheck(uacall.symbol)
typed { squeezedBlock(List(handleOuter(uacall)), If(cond,squeezedBlock(vdefs,succ),fail)) }
- } /* def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) */
+ } /* def tree(implicit handleOuter: HandleOuter, theOwner: Symbol, failTree: Tree) */
} /* MixUnapply */
/** handle sequence pattern and ArrayValue
@@ -532,7 +555,7 @@ trait ParallelMatching {
val nrows = rest.row.map {
case Row(pats,subst,g,b) => Row(childpatList ::: pats,subst,g,b)
}
- val succRep = Rep( vs.toList ::: rest.temp, nrows)
+ val succRep = rep.make( vs.toList ::: rest.temp, nrows)
if(isRightIgnoring(av)) { // contains a _* at the end
val minlen = xs.length-1;
@@ -555,7 +578,7 @@ trait ParallelMatching {
}
}
- final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) = {
+ final def tree(implicit handleOuter: HandleOuter, theOwner: Symbol, failTree: Tree) = {
val (cx,srep,frep) = this.getTransition
val succ = repToTree(srep, handleOuter)
val fail = repToTree(frep, handleOuter)
@@ -564,23 +587,25 @@ trait ParallelMatching {
}
*/
- class MixEquals(val scrutinee:Symbol, val column:List[Tree], val rest:Rep) extends RuleApplication {
+ // @todo: equals test for same constant
+ class MixEquals(val scrutinee:Symbol, val column:List[Tree], val rest:Rep)(implicit rep:RepFactory) extends RuleApplication(rep) {
/** condition (to be used in IF), success and failure Rep */
final def getTransition(implicit theOwner: Symbol): (Tree, Rep, Rep) = {
val nmatrix = rest
- val vlue = column.head.tpe match {
+ val vlue = (column.head.tpe: @unchecked) match {
case TypeRef(_,_,List(SingleType(pre,sym))) =>
gen.mkAttributedRef(pre,sym)
}
val nsuccFst = rest.row.head match { case Row(pats,bnd,g,b) => Row(EmptyTree::pats,bnd,g,b) }
val nsuccRow = nsuccFst :: (column.tail.zip(rest.row.tail) map { case (p, Row(pats,bnd,g,b)) => Row(p::pats,bnd,g,b) })
- val nsucc = Rep(scrutinee :: rest.temp, nsuccRow)
+ val nsucc = rep.make(scrutinee :: rest.temp, nsuccRow)
val nfail = repWithoutHead(column,rest)
return (typed{ Equals(Ident(scrutinee) setType scrutinee.tpe, vlue) }, nsucc, nfail)
}
- final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) = {
+ final def tree(implicit handleOuter: HandleOuter, localTyper: LocalTyper, theOwner: Symbol, failTree: Tree) = {
val (cond,srep,frep) = this.getTransition
+ //Console.println("MixEquals::tree -- cond "+cond)
val cond2 = try{
typed { handleOuter(cond) }
} catch {
@@ -591,8 +616,8 @@ trait ParallelMatching {
throw e
}
- val succ = repToTree(srep, handleOuter)
- val fail = repToTree(frep, handleOuter)
+ val succ = repToTree(srep, handleOuter,localTyper)
+ val fail = repToTree(frep, handleOuter,localTyper)
try {
typed{ If(cond2, succ, fail) }
} catch {
@@ -601,13 +626,13 @@ trait ParallelMatching {
Console.println("cond2: "+cond2)
throw e
}
- } /* def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) */
+ } /* def tree(implicit handleOuter: HandleOuter, theOwner: Symbol, failTree: Tree) */
} /* MixEquals */
/**
* mixture rule for type tests
**/
- class MixTypes(val scrutinee:Symbol, val column:List[Tree], val rest:Rep) extends RuleApplication {
+ class MixTypes(val scrutinee:Symbol, val column:List[Tree], val rest:Rep)(implicit rep:RepFactory) extends RuleApplication(rep) {
var casted: Symbol = null
var moreSpecific: List[Tree] = Nil
@@ -622,13 +647,14 @@ trait ParallelMatching {
private val headPatternType = column.head match {
case p @ (_:Ident | _:Select) =>
- singleType(p.symbol.tpe.prefix, p.symbol) //ConstantType(p.tpe.singleton)
+ singleType(p.symbol.tpe.prefix, p.symbol) //should be singleton object
//case p@Apply(_,_) if !p.tpe./*?type?*/symbol.hasFlag(symtab.Flags.CASE) => ConstantType(new NamedConstant(p))
case _ => column.head.tpe
}
private val isCaseHead = isCaseClass(headPatternType)
- private val dummies = if(!isCaseHead) Nil else headPatternType.typeSymbol.caseFieldAccessors.map { x => EmptyTree }
+ private val dummies = if(!isCaseHead) Nil else getDummies(headPatternType.typeSymbol.caseFieldAccessors.length)
+ //Console.println("headPatternType "+headPatternType)
//Console.println("isCaseHead = "+isCaseHead)
//Console.println("dummies = "+dummies)
@@ -666,7 +692,7 @@ trait ParallelMatching {
}
//Console.println("scrutinee == "+scrutinee+":"+scrutinee.tpe)
//Console.println("column.head == "+column.head);
- {
+ /*init block*/ {
var sr = (moreSpecific,subsumed,remaining)
var j = 0; var pats = column; while(pats ne Nil) {
val (ms,ss,rs) = sr // more specific, more general(subsuming current), remaining patterns
@@ -718,7 +744,7 @@ trait ParallelMatching {
this.subsumed = sr._2.reverse
this.remaining = sr._3.reverse
sr = null
- }
+ } /* init block */
override def toString = {
"MixTypes("+scrutinee+":"+scrutinee.tpe+") {\n moreSpecific:"+moreSpecific+"\n subsumed:"+subsumed+"\n remaining"+remaining+"\n}"
@@ -730,15 +756,15 @@ trait ParallelMatching {
// the following works for type tests... what fudge is necessary for value comparisons?
// type test
casted = if(scrutinee.tpe =:= headPatternType) scrutinee else newVar(scrutinee.pos, headPatternType)
- if(scrutinee.hasFlag(symtab.Flags.CAPTURED))
- casted.setFlag(symtab.Flags.CAPTURED)
+ if(scrutinee.hasFlag(symtab.Flags.TRANS_FLAG))
+ casted.setFlag(symtab.Flags.TRANS_FLAG)
// succeeding => transition to translate(subsumed) (taking into account more specific)
val nmatrix = {
var ntemps = if(isCaseClass(casted.tpe)) casted.caseFieldAccessors map {
meth =>
val ctemp = newVar(scrutinee.pos, casted.tpe.memberType(meth).resultType)
- if(scrutinee.hasFlag(symtab.Flags.CAPTURED))
- ctemp.setFlag(symtab.Flags.CAPTURED)
+ if(scrutinee.hasFlag(symtab.Flags.TRANS_FLAG))
+ ctemp.setFlag(symtab.Flags.TRANS_FLAG)
ctemp
} else Nil // (***)
var subtests = subsumed
@@ -759,7 +785,7 @@ trait ParallelMatching {
}
//DBG("ntemps = "+ntemps.mkString("[["," , ","]]"))
//DBG("ntriples = "+ntriples.mkString("[[\n","\n, ","\n]]"))
- Rep(ntemps, ntriples) /*setParent this*/
+ rep.make(ntemps, ntriples) /*setParent this*/
}
// fails => transition to translate(remaining)
@@ -768,46 +794,58 @@ trait ParallelMatching {
val ntriples = remaining map {
case (j, pat) => val r = rest.row(j); Row(pat :: r.pat, r.subst, r.guard, r.bx)
}
- if(ntriples.isEmpty) None else Some(Rep(ntemps, ntriples))
+ if(ntriples.isEmpty) None else Some(rep.make(ntemps, ntriples))
}
//DBG("nmatrixFail = \n\n"+nmatrixFail)
(casted, nmatrix, nmatrixFail)
} /* getTransition(implicit theOwner: Symbol): (Symbol, Rep, Option[Rep]) */
- final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) = {
+ final def tree(implicit handleOuter: HandleOuter, localTyper: LocalTyper, theOwner: Symbol, failTree: Tree) = {
val (casted,srep,frep) = this.getTransition
val condUntyped = condition(casted.tpe, this.scrutinee)
var cond = handleOuter(typed { condUntyped }) // <- throws exceptions in some situations?
if(needsOuterTest(casted.tpe, this.scrutinee.tpe)) // @todo merge into def condition
cond = addOuterCondition(cond, casted.tpe, typed{Ident(this.scrutinee)}, handleOuter)
+ val succ = repToTree(srep, handleOuter, localTyper)
- val succ = repToTree(srep, handleOuter)
-
- val fail = if(frep.isEmpty) failTree else repToTree(frep.get, handleOuter)
+ val fail = if(frep.isEmpty) failTree else repToTree(frep.get, handleOuter,localTyper)
// dig out case field accessors that were buried in (***)
- val cfa = casted.caseFieldAccessors
+ //Console.println("casted:"+casted+": "+casted.tpe)
+ val cfa = if(isCaseHead) casted.caseFieldAccessors else Nil
+ //Console.println("cfa's:"+cfa.toString)
+
val caseTemps = (if(!srep.temp.isEmpty && srep.temp.head == casted) srep.temp.tail else srep.temp).zip(cfa)
- //DEBUG("case temps"+caseTemps.toString)
+ //Console.println("case temps"+caseTemps.toString)
+ try{
var vdefs = caseTemps map {
- case (tmp,meth) =>
- val typedAccess = typed { Apply(Select(typed{Ident(casted)}, meth),List()) }
- typedValDef(tmp, typedAccess)
+ case (tmp,accessorMethod) =>
+ //Console.println("tmp: "+tmp+":"+tmp.tpe)
+ //Console.println("accessorMethod: "+accessorMethod+":"+accessorMethod.tpe)
+ val untypedAccess = Apply(Select(typed{Ident(casted)}, accessorMethod),List())
+ val typedAccess = typed { untypedAccess }
+ //Console.println("ParallelMatching-- MixTypes "+typedAccess)
+ typedValDef(tmp, typedAccess)
}
if(casted ne this.scrutinee) {
vdefs = ValDef(casted, gen.mkAsInstanceOf(typed{Ident(this.scrutinee)}, casted.tpe)) :: vdefs
}
typed { If(cond, squeezedBlock(vdefs,succ), fail) }
- } /* def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) */
+ } catch {
+ case e =>
+ throw new FatalError("EXCEPTION:"+e.getMessage())
+ }
+ } /* def tree(implicit handleOuter: HandleOuter, theOwner: Symbol, failTree: Tree) */
} /* class MixTypes */
/** converts given rep to a tree - performs recursive call to translation in the process to get sub reps
*/
- final def repToTree(rep:Rep, handleOuter: Tree => Tree)(implicit theOwner: Symbol, failTree: Tree): Tree = {
+ final def repToTree(r: Rep, handleOuter: HandleOuter, localTyper: LocalTyper)(implicit theOwner: Symbol, failTree: Tree, rep: RepFactory): Tree = {
implicit val HandleOuter = handleOuter
- rep.applyRule.tree
+ implicit val LocalTyper = localTyper
+ r.applyRule.tree
/*
rep.applyRule match {
case r : ErrorRule => r.tree
@@ -831,12 +869,13 @@ trait ParallelMatching {
/** subst: the bindings so far */
case class Row(pat:List[Tree], subst:Binding, guard:Tree, bx:Int)
-object Rep {
- type RepType = Product2[List[Symbol], List[Row]]
- final def unapply(x:Rep):Option[RepType] =
- if(x.isInstanceOf[RepImpl]) Some(x.asInstanceOf[RepImpl]) else None
-
- private case class RepImpl(val temp:List[Symbol], val row:List[Row]) extends Rep with RepType {
+ object Rep {
+ type RepType = Product2[List[Symbol], List[Row]]
+ final def unapply(x:Rep)(implicit rep:RepFactory):Option[RepType] =
+ if(x.isInstanceOf[rep.RepImpl]) Some(x.asInstanceOf[RepType]) else None
+ }
+ class RepFactory {
+ case class RepImpl(val temp:List[Symbol], val row:List[Row]) extends Rep with Rep.RepType {
(row.find { case Row(pats, _, _, _) => temp.length != pats.length }) match {
case Some(row) => assert(false, "temp == "+temp+" row.pats == "+row.pat);
case _ =>
@@ -850,8 +889,9 @@ object Rep {
var targets: List[Tree] = _
var reached64: Set64 = _
var reached: List[Int] = Nil
+ var shortCuts: List[Symbol] = Nil;
- final def apply(temp:List[Symbol], row:List[Row], targets: List[Tree], vss:List[SymList]): Rep = {
+ final def make(temp:List[Symbol], row:List[Row], targets: List[Tree], vss:List[SymList])(implicit theOwner: Symbol): Rep = {
// ensured that labels(i) eq null for all i, cleanup() has to be called after translation
this.targets = targets
if(targets.length > labels.length)
@@ -860,7 +900,13 @@ object Rep {
this.reached64 = if(targets.length < 64) new Set64 else null
//Console.println("targets: "+targets)
//Console.print("labels: "); {for(s<-labels) Console.print({if(s ne null) {s} else "_"}+",")}
- return apply(temp, row)
+ return make(temp, row)
+ }
+
+ final def shortCut(theLabel:Symbol): Int = {
+ //Console.println("adds shortcut:"+theLabel)
+ this.shortCuts = shortCuts:::theLabel::Nil;
+ return -shortCuts.length
}
final def cleanup(tree: Tree)(implicit theOwner: Symbol): Tree = {
@@ -903,11 +949,12 @@ object Rep {
var i = targets.length;
while (i>0) { i-=1; labels(i) = null; };
reached = Nil
+ shortCuts = Nil
}
final def isReached(bx:Int) = { /*Console.println("isReached("+bx+")"); */labels(bx) ne null }
final def markReachedTwice(bx:Int) = if(reached64 ne null) { reached64 |= bx } else { reached = insertSorted(bx, reached) }
- /** @pre labelIndex(bx) != -1 */
- final def isReachedTwice(bx:Int) = if(reached64 ne null) { reached64 contains bx } else { findSorted(bx,reached) }
+ /** @pre bx < 0 || labelIndex(bx) != -1 */
+ final def isReachedTwice(bx:Int) = (bx < 0) || (if(reached64 ne null) { reached64 contains bx } else { findSorted(bx,reached) })
/* @returns bx such that labels(bx) eq label, -1 if no such bx exists */
final def labelIndex(label:Symbol): Int = {
@@ -919,6 +966,16 @@ object Rep {
* the function takes care of binding
*/
final def requestBody(bx:Int, subst:Binding)(implicit theOwner: Symbol): Tree = {
+ if(bx < 0) {// is shortcut
+ //Console.println("requestBody ("+bx+") gets shortcut "+(shortCuts.length-bx)+ " all:"+shortCuts);
+ val jlabel = shortCuts(-bx-1)
+ //Console.println("is "+jlabel);
+ val jump = Apply(Ident(jlabel) setType jlabel.tpe, Nil)
+ //Console.println(jump)
+ //val jumpT = typed{ jump }
+ //Console.println(jumpT)
+ return jump
+ }
//Console.print("requestbody("+bx+", "+subst+") isReached(bx)?"+isReached(bx)+" labels:"); {for(s<-labels) Console.print({if(s ne null) {s} else "_"}+",")}
if(!isReached(bx)) { // first time this bx is requested
val argts = new ListBuffer[Type] // types of
@@ -937,8 +994,6 @@ object Rep {
// bug: typer is not able to digest a body of type Nothing being assigned result type Unit
val tpe = if(body.tpe.typeSymbol eq definitions.AllClass) body.tpe else resultType
val label = theOwner.newLabel(body.pos, "body%"+bx).setInfo(new MethodType(argts.toList, tpe))
- //Console.println("label.tpe"+label.tpe)
-
labels(bx) = label
if(body.isInstanceOf[Throw] || body.isInstanceOf[Literal]) {
@@ -962,7 +1017,7 @@ object Rep {
label.tpe match {
case MethodType(fmls,_) =>
if (fmls.length != args.length) { // sanity check
- cunit.error(targets(bx).pos, "consistency problem ! "+fmls)
+ cunit.error(targets(bx).pos, "consistency problem in target generation ! I have args "+args+" and need to jump to a label with fmls "+fmls)
//System.exit(-1)
throw FatalError("consistency problem")
}
@@ -992,7 +1047,7 @@ object Rep {
}
/** the injection here handles alternatives and unapply type tests */
- final def apply(temp:List[Symbol], row1:List[Row]): Rep = {
+ final def make(temp:List[Symbol], row1:List[Row])(implicit theOwner: Symbol): Rep = {
//if(temp.isEmpty && row1.length > 1) return apply(Nil, row1.head::Nil) // small standalone optimization, we won't need other rows (check guard?)
var unchanged: Boolean = true
val row = row1 flatMap {
@@ -1035,40 +1090,47 @@ object Rep {
Console.println("/'''''''''''' 6"+(o.symbol.tpe.typeSymbol hasFlag (Flags.CASE)))
Console.println("/'''''''''''' 7"+(o.symbol.tpe.termSymbol.hasFlag (Flags.CASE)))
*/
- val stpe =
+ val tpe =
if (!o.symbol.isValue) {
- singleType(o.tpe.prefix, o.symbol)
+ singleType(o.tpe.prefix, o.symbol)
} else {
+ DBG("o.tpe "+o.symbol.tpe)
+ DBG("o.tpe "+o.symbol.tpe.isStable)
+ DBG("p.prefix "+o.symbol.tpe.prefix)
singleType(NoPrefix, o.symbol) // equals-check
+ // call the above `stpe'. Then we could also return
+ // `typeRef(definitions.ScalaPackageClass.tpe, definitions.EqualsPatternClass, List(stpe))'
+ // and force an equality check. However, exhaustivity checking would not work anymore.
+ // so first, extend exhaustivity check to equalspattern
}
- val p = Ident(nme.WILDCARD) setType stpe
- val q = Typed(p, TypeTree(stpe)) setType stpe
+ val p = Ident(nme.WILDCARD) setType tpe
+ val q = Typed(p, TypeTree(tpe)) setType tpe
pats = q::pats
case o @ Ident(nme.WILDCARD) =>
pats = o::pats
- case o @ Select(_,_) =>
- /*
- Console.println("!/'''''''''''' 1"+o.tpe)
- Console.println("!/'''''''''''' 2"+o.symbol)
- Console.println("!/'''''''''''' 3"+o.symbol.tpe)
- Console.println("!'''''''''''' 4"+o.symbol.tpe.prefix)
- Console.println("!/'''''''''''' 5"+o.symbol.tpe.prefix.isStable)
-
- Console.println("!/'''''''''''' 6"+(o.symbol.tpe.typeSymbol hasFlag (Flags.CASE)))
- Console.println("!/'''''''''''' 7"+(o.symbol.tpe.termSymbol.hasFlag (Flags.CASE)))
- */
+ case o @ Select(stor,_) =>
val stpe =
if (!o.symbol.isValue) {
- singleType(o.tpe.prefix, o.symbol)
+ singleType(o.tpe.prefix, o.symbol)
} else {
+ DBG("stor.tpe "+stor.tpe)
+ DBG("stor.symbol "+stor.symbol)
+ DBG("stor.symbol.tpe "+stor.symbol.tpe)
singleType(NoPrefix, o.symbol) // equals-check
}
val p = Ident(nme.WILDCARD) setType stpe
val q = Typed(p, TypeTree(stpe)) setType stpe
pats = q::pats
+ case UnApply(Apply(TypeApply(sel @ Select(stor, nme.unapplySeq),List(tptArg)),_),ArrayValue(_,xs)::Nil) if(stor.symbol eq definitions.ListModule) =>
+ //@pre: is not right-ignoring (no star pattern)
+ // no exhaustivity check, please
+ temp(j).setFlag(symtab.Flags.TRANS_FLAG)
+ val listType = typeRef(mkThisType(definitions.ScalaPackage), definitions.ListClass, List(tptArg.tpe))
+ val nmlzdPat = normalizedListPattern(xs, tptArg.tpe)
+ pats = nmlzdPat :: pats
case ua @ UnApply(Apply(fn, _), arg) =>
fn.tpe match {
case MethodType(List(argtpe,_*),_) =>
@@ -1078,17 +1140,39 @@ object Rep {
/** something too tricky is going on if the outer types don't match
*/
case o @ Apply(fn, List()) if !isCaseClass(o.tpe) =>
- val stpe = fn match {
+ DBG("o.tpe "+o.tpe)
+ DBG("fn is ")
+ //Console.println("o.symbol is a module? "+o.symbol+" "+o.symbol.isModule)
+ //Console.println("o.tpe.termSymbol is a module? "+o.tpe.termSymbol+" "+o.tpe.termSymbol.isModule)
+ val stpe: Type = fn match {
+ case _ if (o.symbol.isModule) =>
+ DBG("o.symbol is module! "+o.symbol)
+ DBG(nodeToString(fn))
+ singleType(o.tpe.prefix, o.symbol)
+ case _ if (o.tpe.termSymbol.isModule) =>
+ //Console.println("o.tpe.termSymbol is a module! "+sym)
+ singleType(o.tpe.prefix, o.symbol)
case Select(path,sym) =>
- if (o.tpe.termSymbol.isModule) singleType(o.tpe.prefix, o.symbol)
- else path.tpe match {
+ DBG("path "+path);
+ DBG("sym "+sym);
+ path.tpe match {
case ThisType(sym) =>
singleType(path.tpe, o.symbol)
- case _ =>
- singleType(singleType(path.tpe.prefix, path.symbol), o.symbol)
+
+ case _ => // e.g. `case Some(p._2)' in scala.collection.jcl.Map
+ singleType(singleType(path.tpe.prefix, path.symbol) , o.symbol) // old
+
}
- case Ident(_) => // lazy val
- singleType(NoPrefix, o.symbol)
+ case o @ Ident(_) => // lazy val
+ DBG("sym "+o.symbol)
+ DBG("sym.isValue "+o.symbol.isValue)
+ //singleType(NoPrefix, o.symbol) // before
+ if (!o.symbol.isValue) {
+ singleType(o.tpe.prefix, o.symbol)
+ } else {
+ singleType(NoPrefix, o.symbol) // equals-check
+ }
+
}
//Console.println("encoding in singleType:"+stpe)
@@ -1106,7 +1190,7 @@ object Rep {
pats = q :: pats
case p @ ArrayValue(_,xs) =>
- Console.println("hello from array val!")
+ assert(false) // inactive, @see PatternMatchers::isImplemented
pats = p :: pats
case p =>
@@ -1132,7 +1216,7 @@ object Rep {
ri
} else {
//Console.println("Rep.apply / recursive ")
- Rep(temp,row) // recursive call
+ this.make(temp,row) // recursive call
}
}
}
@@ -1150,7 +1234,7 @@ object Rep {
case (sym,i) =>
//Console.println("sym! "+sym+" mutable? "+sym.hasFlag(symtab.Flags.MUTABLE)+" captured? "+sym.hasFlag(symtab.Flags.CAPTURED))
if (sym.hasFlag(symtab.Flags.MUTABLE) && // indicates that have not yet checked exhaustivity
- !sym.hasFlag(symtab.Flags.CAPTURED) && // indicates @unchecked
+ !sym.hasFlag(symtab.Flags.TRANS_FLAG) && // indicates @unchecked
sym.tpe.typeSymbol.hasFlag(symtab.Flags.SEALED)) {
sym.resetFlag(symtab.Flags.MUTABLE)
@@ -1189,8 +1273,9 @@ object Rep {
comb forall {
case (i,sym) =>
val p = strip2(pats(i));
+ //Console.println("covers? "+p+" "+sym);
val res =
- isDefaultPattern(p) || {
+ isDefaultPattern(p) || p.isInstanceOf[UnApply] || p.isInstanceOf[ArrayValue] || {
val symtpe = if(sym.hasFlag(symtab.Flags.MODULE)) {
singleType(sym.tpe.prefix, sym.linkedModuleOfClass) // e.g. None, Nil
} else sym.tpe
@@ -1227,7 +1312,13 @@ object Rep {
return this
} /* def init */
- final def applyRule: RuleApplication = row match {
+
+ /* internal representation is (temp:List[Symbol], row:List[Row])
+ *
+ * tmp1 tmp_m
+ */
+
+ final def applyRule(implicit theOwner: Symbol, rep: RepFactory): RuleApplication = row match {
case Nil =>
ErrorRule
case Row(pats, subst, g, bx)::xs =>
@@ -1240,18 +1331,23 @@ object Rep {
px += 1 // pattern index
}
}
+ /* Row( _ ... _ g_1 b_1 ) :: rows it's all default patterns
+ */
if(bnd ne null) { // all default patterns
- val rest = if(g eq EmptyTree) null else Rep(temp, xs)
+ val rest = if(g eq EmptyTree) null else rep.make(temp, xs)
return VariableRule (bnd, g, rest, bx)
}
+ /* Row( _ ... _ p_1i ... p_1n g_m b_m ) :: rows
+ */
+
// cut out column px that contains the non-default pattern
// assert(px == pats findIndexOf {x => !isDefaultPattern(x)})
val column = rpats.head :: (row.tail map { case Row(pats,_,_,_) => pats(px) })
// assert(column == row map { case Row(pats,_,_,_) => pats(px) })
val restTemp = temp.take(px) ::: temp.drop(px+1)
val restRows = row map { case Row(pats, subst, g, bx) => Row(pats.take(px) ::: pats.drop(px+1), subst, g, bx) }
- return MixtureRule(temps.head, column, Rep(restTemp,restRows))
+ return MixtureRule(temps.head, column, rep.make(restTemp,restRows))
} /* applyRule */
// a fancy toString method for debugging
@@ -1273,11 +1369,11 @@ object Rep {
/** creates initial clause matrix
*/
- final def initRep(selector: Tree, cases: List[Tree], checkExhaustive: Boolean)(implicit theOwner: Symbol) = {
+ final def initRep(selector: Tree, cases: List[Tree], checkExhaustive: Boolean, rep:RepFactory)(implicit theOwner: Symbol) = {
val root = newVar(selector.pos, selector.tpe)
// communicate whether exhaustiveness-checking is enabled via some flag
if (!checkExhaustive)
- root.setFlag(symtab.Flags.CAPTURED)
+ root.setFlag(symtab.Flags.TRANS_FLAG)
var bx = 0;
val targets = new ListBuffer[Tree]
val vss = new ListBuffer[SymList]
@@ -1292,7 +1388,7 @@ object Rep {
cs = cs.tail
}
//Console.println("leaving initRep")
- /*val res = */Rep(List(root), row.toList, targets.toList, vss.toList)
+ /*val res = */rep.make(List(root), row.toList, targets.toList, vss.toList)
//Console.println("left initRep")
//res
}
@@ -1303,7 +1399,6 @@ object Rep {
final def newVar(pos: Position, name: Name, tpe: Type)(implicit theOwner: Symbol): Symbol = {
if(tpe eq null) assert(tpe ne null, "newVar("+name+", null)")
val sym = theOwner.newVariable(pos, name) // careful: pos has special meaning
- sym setFlag symtab.Flags.TRANS_FLAG // should eventually be used for avoiding non-null checks?
sym setInfo tpe
sym
}
@@ -1315,8 +1410,8 @@ object Rep {
*/
final def condition(tpe: Type, scrut: Symbol): Tree = {
val res = condition1(tpe, scrut)
- if (settings_debug)
- Console.println("condition, tpe = "+tpe+", scrut.tpe = "+scrut.tpe+", res = "+res)
+ //if (settings_debug)
+ // Console.println("condition, tpe = "+tpe+", scrut.tpe = "+scrut.tpe+", res = "+res)
res
}
final def condition1(tpe: Type, scrut: Symbol): Tree = {
@@ -1395,8 +1490,10 @@ object Rep {
}
/** adds a test comparing the dynamic outer to the static outer */
- final def addOuterCondition(cond:Tree, tpe2test: Type, scrutinee: Tree, handleOuter: Tree=>Tree) = {
+ final def addOuterCondition(cond:Tree, tpe2test: Type, scrutinee: Tree, handleOuter: HandleOuter) = {
val TypeRef(prefix,_,_) = tpe2test
+ //Console.println("addOuterCondition: "+prefix)
+ assert(prefix ne NoPrefix)
var theRef = gen.mkAttributedRef(prefix.prefix, prefix.termSymbol)
// needs explicitouter treatment
diff --git a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala
index dc0ce77db7..a4795fcdb1 100644
--- a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala
+++ b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala
@@ -53,13 +53,16 @@ trait PatternMatchers { self: transform.ExplicitOuter with PatternNodes with Par
import global.{ definitions => defs }
- var handleOuter: Tree=>Tree = _
+ var handleOuter: HandleOuter = _
- def initialize(selector: Tree, doCheckExhaustive: Boolean, owner: Symbol, handleOuter:Tree=>Tree): Unit = {
+ var localTyper: LocalTyper = _
+
+ def initialize(selector: Tree, doCheckExhaustive: Boolean, owner: Symbol, _handleOuter:Tree=>Tree, _localTyper:Tree=>Tree): Unit = {
this.owner = owner
this.doCheckExhaustive = doCheckExhaustive
this.selector = selector
- this.handleOuter = handleOuter
+ this.handleOuter = new HandleOuter( _handleOuter )
+ this.localTyper = new LocalTyper( _localTyper )
if (settings_debug) {
Console.println("****")
Console.println("**** initalize, selector = "+selector+" selector.tpe = "+selector.tpe)
@@ -177,32 +180,30 @@ trait PatternMatchers { self: transform.ExplicitOuter with PatternNodes with Par
val c = cases1.head.asInstanceOf[CaseDef]
//if(c.guard != EmptyTree) return CantHandleGuard // TEST
//hasUnapply.traverse(c.pat)
- val e = isImplemented(c.pat); if(e ne null) return e
+ val e = isImplemented(c.pat, c.guard); if(e ne null) return e
cases1 = cases1.tail
}
- val irep = initRep(selector, cases, doCheckExhaustive)
- val root = irep.temp.head
-
- implicit val fail: Tree = ThrowMatchError(selector.pos, Ident(root))
- val vdef = typed{ValDef(root, selector)}
+ implicit val rep = new RepFactory()
+ try {
+ val irep = initRep(selector, cases, doCheckExhaustive, rep)
+ val root = irep.temp.head
- //implicit val memo = new collection.mutable.HashMap[(Symbol,Symbol),Symbol]
- //implicit val theCastMap = new collection.mutable.HashMap[(Symbol,Type),Symbol]
+ implicit val fail: Tree = ThrowMatchError(selector.pos, Ident(root))
+ val vdef = typed{ValDef(root, selector)}
- try {
- val mch = typed{repToTree(irep, handleOuter)}
+ val mch = typed{repToTree(irep, handleOuter, localTyper)}
dfatree = typed{squeezedBlock(List(vdef), mch)}
//DEBUG("**** finished\n"+dfatree.toString)
var bx = 0; var cs = cases; while(cs ne Nil) {
- if(!Rep.isReached(bx)) {
+ if(!rep.isReached(bx)) {
cunit.error(cs.head.asInstanceOf[CaseDef].body.pos, "unreachable code")
}
cs = cs.tail
bx += 1
}
- dfatree = Rep.cleanup(dfatree)
+ dfatree = rep.cleanup(dfatree)
resetTrav.traverse(dfatree)
//constructParallel(cases) // ZZZ
@@ -220,7 +221,7 @@ trait PatternMatchers { self: transform.ExplicitOuter with PatternNodes with Par
// return e // fallback
//non-fallback:
- case e: CantHandle => Rep.cleanup(); return e
+ case e: CantHandle => rep.cleanup(); return e
case e => throw e
}
}
@@ -234,27 +235,26 @@ trait PatternMatchers { self: transform.ExplicitOuter with PatternNodes with Par
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)
+ //vd.symbol.resetFlag(symtab.Flags.MUTABLE)
}
case _ =>
super.traverse(x)
}
}
- def isImplemented(xs:List[Tree]): CantHandle =
+ def isImplemented(xs:List[Tree], guard:Tree): CantHandle =
if(xs eq Nil) null else {
- val e = isImplemented(xs.head)
- if(e ne null) e else isImplemented(xs.tail)
+ val e = isImplemented(xs.head, guard)
+ if(e ne null) e else isImplemented(xs.tail, guard)
}
- def isImplemented(x:Tree): CantHandle = {
+ def isImplemented(x:Tree,guard:Tree): CantHandle = {
//Console.println("isImplemented? "+x)
x match {
case app @ Apply(fn,xs) =>
- if(!isCaseClass(app.tpe)) { /*|| (fn.symbol ne null)*/
+ if(!isCaseClass(app.tpe)) { //|| (fn.symbol ne null)
//Console.println(app)
//Console.println(app.tpe)
//Console.println(app.symbol)
@@ -265,65 +265,45 @@ trait PatternMatchers { self: transform.ExplicitOuter with PatternNodes with Par
}
null
} else {
- /*if(!app.tpe.symbol.hasFlag(symtab.Flags.CASE)) {
- Console.print("what is this?"+x)
- if(fn.symbol eq null) {
- Console.println("it's fn doesn't even have a symbol?!")
- } else {
- Console.println("it's fn symbol is "+fn.symbol)
- }
- }*/
- isImplemented(xs)
+ isImplemented(xs, guard)
}
case p @ Ident(n) => null // if(n!= nme.WILDCARD && p.symbol.) CantHandleIdent else null
- case UnApply(fn,xs) => isImplemented(xs)
- case Bind(n, p) => isImplemented(p)
- case Alternative(xs) => isImplemented(xs)
+
+ //case UnApply(fn,xs) => isImplemented(xs, guard)
+ case UnApply(fn,xs) =>
+ fn match {
+ // List.unapply<...>(xs)
+ case Apply(TypeApply(sel @ Select(stor, nme.unapplySeq),_),_) if(stor.symbol eq definitions.ListModule) =>
+ (xs: @unchecked) match {
+ case ArrayValue(_,ys)::Nil => return {if(guard eq EmptyTree) isImplemented(ys, guard) else CantHandleSeq }
+ }
+
+ // ignore other unapplySeq occurrences, since will run into ArrayValue
+ case _ =>
+ return isImplemented(xs, guard)
+ }
+
+ case Bind(n, p) => isImplemented(p , guard)
+ case Alternative(xs) => isImplemented(xs, guard)
case p:Literal => null
case p:Select => null
case p:Typed => null
-
+ // ArrayValue nodes can also appear in repeated parameter positions of case classes (e.g. xml.Elem)
case ArrayValue(_,xs) => CantHandleSeq
//@todo
- //case av @ ArrayValue(_,xs) => if(isRightIgnoring(av)) CantHandleSeq else null // DEBUG
- //case Star(t) => isImplemented(t) //can't happen/ excluded by Transmatcher:isregular
+ //case av @ ArrayValue(_,xs) =>
+ //Console.println("is Impl(av), typesym = "+av.tpe.typeSymbol+" of List?"+av.tpe.typeSymbol eq definitions.ListClass);
+
+ //if(guard.isEmpty) isImplemented(xs, guard) else CantHandleSeq ; // null;
+ //Console.println("PM:"+av+" isRI?"+isRightIgnoring(av))
+ //if(isRightIgnoring(av)) CantHandleSeq else null // DEBUG
+ case Star(t) => CantHandleSeq //isImplemented(t) //can't happen/ excluded by Transmatcher:isregular
//case Sequence(trees) =>can't happen/ only appear below ArrayValue
}
}
- /*
- object hasUnapply extends Traverser {
- override def traverse(x:Tree) = {
- //Console.println("pat:'"+x+"' / "+x.getClass)
- x match {
- case _:ArrayValue => throw CantHandleSeq
- case UnApply(fn,args) => //throw CantHandleUnapply // EXPR
- traverseTrees(args)
- 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(fn,args) if !p.tpe.symbol.hasFlag(symtab.Flags.CASE) =>
- //Console.println("I can't handle APPLY pattern:"+p)
- //Console.println("fn:"+fn)
- //Console.println("args:"+args)
- //Console.println("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) =>
@@ -1033,7 +1013,7 @@ print()
); // forward jump
if (guard(i) != EmptyTree)
- res0 = And(guard(i), res0);
+ res0 = And(handleOuter(guard(i)), res0);
res = Or(squeezedBlock(ts.toList, res0), res)
i = i - 1
}
diff --git a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
index d3d567225a..64a5da7708 100644
--- a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
+++ b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
@@ -17,6 +17,54 @@ trait PatternNodes { self: transform.ExplicitOuter =>
// --- misc methods
+ private val dummy1 = EmptyTree :: Nil
+ private val dummy2 = EmptyTree :: dummy1
+ private val dummy3 = EmptyTree :: dummy2
+ private val dummy4 = EmptyTree :: dummy3
+ private val dummy5 = EmptyTree :: dummy4
+ private val dummy6 = EmptyTree :: dummy5
+ private val dummy7 = EmptyTree :: dummy6
+
+ final def getDummies(i:Int): List[Tree] = i match {
+ case 0 => Nil
+ case 1 => dummy1
+ case 2 => dummy2
+ case 3 => dummy3
+ case 4 => dummy4
+ case 5 => dummy5
+ case 6 => dummy6
+ case 7 => dummy7
+ case n => EmptyTree::getDummies(i-1)
+ }
+
+ def normalizedListPattern(pats:List[Tree], tptArg:Type): Tree = pats match {
+ case Nil => gen.mkAttributedRef(definitions.NilModule)
+ case x::xs =>
+ var resType: Type = null;
+ val consType: Type = definitions.ConsClass.primaryConstructor.tpe match {
+ case mt @ MethodType(args, res @ TypeRef(pre,sym,origArgs)) =>
+ val listType = TypeRef(pre, definitions.ListClass, List(tptArg))
+ resType = TypeRef(pre, sym , List(tptArg))
+
+ MethodType(List(tptArg, listType), resType)
+ }
+ Apply(TypeTree(consType),List(x,normalizedListPattern(xs,tptArg))).setType(resType)
+ }
+/*
+ object ArrayValueFixed {
+ def unapply(x:Tree):Option[List[Tree]] = x match {
+ case ArrayValue(_,xs) => if(isDefaultPattern(xs.last)) Some(xs) else None
+ }
+ }
+ object ArrayValueStar {
+ def unapply(x:Tree): Option[(List[Tree],Tree)] = x match {
+ case ArrayValue(_,xs) =>
+ val ys = xs.drop(xs.length-1)
+ val p = xs.last
+ if(!isDefaultPattern(p)) Some(ys,p) else None
+ }
+ }*/
+
/* equality checks for named constant patterns like "Foo()" are encoded as "_:<equals>[Foo().type]"
* and later compiled to "if(Foo() == scrutinee) ...". This method extracts type information from
* such an encoded type, which is used in optimization. If the argument is not an encoded equals
@@ -113,6 +161,9 @@ trait PatternNodes { self: transform.ExplicitOuter =>
case _ => false
}
+ final case class HandleOuter(transform:Tree=>Tree) { def apply(x:Tree) = transform(x) }
+ final case class LocalTyper(typed:Tree=>Tree) { def apply(x:Tree) = typed(x) }
+
/** pvar: the symbol of the pattern variable
* temp: the temp variable that holds the actual value
* next: next binding
@@ -124,6 +175,13 @@ trait PatternNodes { self: transform.ExplicitOuter =>
}
return b
}
+ /** this is just to produce debug output, ListBuffer needs an equals method?! */
+ override def equals(x:Any) = {
+ x match {
+ case NoBinding => false
+ case Binding(pv2,tmp2,next2) => (pvar eq pv2) && (temp eq tmp2) && (next==next2)
+ }
+ }
def apply(v:Symbol): Ident = {
//Console.println(this.toString()+" apply ("+v+"), eq?"+(v eq pvar))
if(v eq pvar) {Ident(temp).setType(v.tpe)} else next(v)
@@ -132,6 +190,7 @@ trait PatternNodes { self: transform.ExplicitOuter =>
object NoBinding extends Binding(null,null,null) {
override def apply(v:Symbol) = null // not found, means bound elsewhere (x @ unapply-call)
override def toString = "."
+ override def equals(x:Any) = x.isInstanceOf[Binding] && (x.asInstanceOf[Binding] eq this)
}
// misc methods END ---
diff --git a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
index b302154ea1..e2e57ccbc2 100644
--- a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
+++ b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
@@ -27,7 +27,7 @@ trait TransMatcher { self: transform.ExplicitOuter with PatternNodes with CodeFa
// cache these
final val settings_debug = settings.debug.value
- final val settings_squeeze = settings.Xmatchalgo.value != "incr"
+ 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"
@@ -223,7 +223,7 @@ trait TransMatcher { self: transform.ExplicitOuter with PatternNodes with CodeFa
/** handles all translation of pattern matching
*/
def handlePattern(sel: Tree, ocases: List[CaseDef], doCheckExhaustive: Boolean,
- owner: Symbol, handleOuter: Tree => Tree): Tree = {
+ owner: Symbol, handleOuter: Tree => Tree, localTyper: Tree => Tree): Tree = {
// TEMPORARY
//new NewMatcher().toIR(sel, ocases)
//
@@ -239,7 +239,7 @@ trait TransMatcher { self: transform.ExplicitOuter with PatternNodes with CodeFa
EmptyTree
} else {
val pm = new PatternMatcher()
- pm.initialize(sel, doCheckExhaustive, owner,handleOuter)
+ pm.initialize(sel, doCheckExhaustive, owner,handleOuter, localTyper)
pm.construct(cases)
//if (global.log()) {
// global.log("internal pattern matching structure");
diff --git a/src/compiler/scala/tools/nsc/symtab/Scopes.scala b/src/compiler/scala/tools/nsc/symtab/Scopes.scala
index 581bf102a5..c0817a65e8 100644
--- a/src/compiler/scala/tools/nsc/symtab/Scopes.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Scopes.scala
@@ -46,7 +46,8 @@ trait Scopes {
*/
def newScope(initElems: ScopeEntry): Scope = new NormalScope(initElems)
final def newScope: Scope = newScope(null: ScopeEntry)
- final def newScope(base: Scope) : Scope = newScope(base.elems)
+ //final def newScope(base: Scope) : Scope = newScope(base.elems)
+ final def newScope(base: Scope) : Scope = if(base eq null) newScope else newScope(base.elems)
final def newScope(decls: List[Symbol]) : Scope = {
val ret = newScope
decls.foreach(d => ret.enter(d))
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 90a5fa805a..857c178057 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -1334,7 +1334,7 @@ trait Symbols {
override def name: Name =
if (phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass) {
if (flatname == nme.EMPTY) {
- assert(rawowner.isClass)
+ //assert(rawowner.isClass) //bqe: this assert prevents duplication of classdefs (e.g Interpreter.scala)
flatname = newTypeName(rawowner.name.toString() + "$" + rawname)
}
flatname
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index 9b8ec5525c..6c828b81a5 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -410,8 +410,11 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter
*/
var nselector = transform(selector)
- assert(nselector.tpe =:= selector.tpe)
- val ncases = transformCaseDefs(cases)
+ //assert(nselector.tpe =:= selector.tpe)
+ //val ncases = transformCaseDefs(cases)
+ val ncases = cases map {
+ case CaseDef(p,g,b) => CaseDef(transform(p),g,transform(b))
+ }
var checkExhaustive = true
def isUncheckedAnnotation(tpe: Type) = tpe match {
@@ -432,7 +435,7 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter
//Console.println("TransMatcher selector.tpe ="+selector.tpe+")")
//Console.println("TransMatcher resultType ="+resultType+")")
- val t_untyped = handlePattern(nselector, ncases, checkExhaustive, currentOwner, transform)
+ val t_untyped = handlePattern(nselector, ncases, checkExhaustive, currentOwner, transform, {x:Tree => localTyper.typed(x)})
try {
//Console.println("t_untyped "+t_untyped.toString())
val t = atPos(tree.pos) { localTyper.typed(t_untyped, resultType) }
diff --git a/test/files/run/patmatnew.scala b/test/files/run/patmatnew.scala
index ee0d620d21..f183fc11ec 100644
--- a/test/files/run/patmatnew.scala
+++ b/test/files/run/patmatnew.scala
@@ -385,5 +385,14 @@ object Test extends TestConsoleMain {
}
}
+ trait Outer { // bug #1282 compile-only
+ object No
+ trait File {
+ (null:AnyRef) match {
+ case No => false
+ }
+ }
+ }
+
}