summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBurak Emir <emir@epfl.ch>2007-03-22 08:48:27 +0000
committerBurak Emir <emir@epfl.ch>2007-03-22 08:48:27 +0000
commit0c96403c277c5b937392affa701f69f4d16cf82d (patch)
tree87ddb931d013bb9e155bdef79d26b0a26c07e988
parentc61121a813abaace6e739a6f02e4c85b186f95a1 (diff)
downloadscala-0c96403c277c5b937392affa701f69f4d16cf82d.tar.gz
scala-0c96403c277c5b937392affa701f69f4d16cf82d.tar.bz2
scala-0c96403c277c5b937392affa701f69f4d16cf82d.zip
oops, forgot to add ParallelMatching
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala589
1 files changed, 589 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
new file mode 100644
index 0000000000..a49984a4de
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -0,0 +1,589 @@
+package scala.tools.nsc.matching
+
+import compat.StringBuilder
+import scala.tools.nsc.util.Position
+
+/** utility methods (not just for ParallelMatching) */
+trait ParallelMatching requires (transform.ExplicitOuter with PatternMatchers with CodeFactory) {
+
+ import global._
+
+ def DEBUG(x:String) = {if (settings.debug.value) Console.println(x)}
+ // ---------------------------------- data
+
+ trait RuleApplication
+ case class ErrorRule extends RuleApplication
+ case class VariableRule(subst:List[Pair[Symbol,Symbol]], guard: Tree, body: Tree) extends RuleApplication
+ case class MixtureRule(scrutinee:Symbol, column:List[Tree], rest:Rep) extends RuleApplication {
+
+ var parent: Rep = null
+ def setParent(rep:Rep) = { parent = rep; this }
+ var casted: Symbol = null
+ var moreSpecific: List[Tree] = Nil
+ var subsumed: List[(Int,List[Tree])] = Nil // row index and subpatterns
+ var remaining: List[(Int,Tree)] = Nil // row index and pattern
+
+ val isExhaustive = !scrutinee.tpe.symbol.hasFlag(symtab.Flags.SEALED) || {
+ //DEBUG("check exha for column "+column)
+ val tpes = column.map (.tpe.symbol)
+ scrutinee.tpe.symbol.children.forall { sym => tpes.contains(sym) }
+ }
+
+ //DEBUG("Mixture, is exhaustive? "+isExhaustive)
+ //if(!isExhaustive)
+ // cunit.warning(column.head.pos, "match is not exhaustive, I think (first approx)")
+ private val patternType = column.head match {
+ case p@(_:Ident | _:Select) => singleType(p.symbol.tpe.prefix, p.symbol) //ConstantType(p.tpe.singleton)
+ //case p@Apply(_,_) if !p.tpe.symbol.hasFlag(symtab.Flags.CASE) => ConstantType(new NamedConstant(p))
+ case _ => column.head.tpe
+ }
+ private val isCaseScrutinee = patternType.symbol.hasFlag(symtab.Flags.CASE)
+ private val dummies = if(!isCaseScrutinee) Nil else patternType.symbol.caseFieldAccessors.map { x => EmptyTree }
+ private def subpatterns(pat:Tree): List[Tree] = pat match {
+ case Bind(_,p) => subpatterns(p)
+ case app @ Apply(fn, pats) if app.tpe.symbol.hasFlag(symtab.Flags.CASE) => pats
+ case _: UnApply => throw CantHandleUnapply
+ case pat => /*DEBUG("dummy patterns for "+pat+" of class "+pat.getClass);*/dummies
+ }
+ // more specific patterns, subpatterns, remaining patterns
+ private var sr = column.zipWithIndex.foldLeft (moreSpecific,subsumed,remaining) {
+ (p,patAndIndex) =>
+ val (ms,ss,rs) = p
+ val (pat,j) = patAndIndex
+ //Console.println("pat.tpe = "+pat.tpe)
+ //Console.println("patternType = "+patternType)
+ pat match {
+ case Literal(Constant(null)) if !(patternType =:= pat.tpe) => //special case for constant null pattern
+ (ms,ss,(j,pat)::rs)
+ case _ if (pat.symbol ne null) && (patternType =:= singleType(pat.symbol.tpe.prefix, pat.symbol))=>
+ (EmptyTree::ms, (j,dummies)::ss, rs); // matching an object
+ case _ if pat.tpe <:< patternType =>
+ ({if(pat.tpe =:= patternType) EmptyTree else pat}::ms, (j,subpatterns(pat))::ss, rs); // subsumed (same or more specific) pattern;
+ case _ if patternType <:< pat.tpe =>
+ (EmptyTree::ms, (j,dummies)::ss, (j,pat)::rs); // subsuming (matched *and* remaining pattern)
+ case _ =>
+ (ms,ss,(j,pat)::rs)
+ }
+ }
+ this.moreSpecific = sr._1.reverse
+ this.subsumed = sr._2.reverse
+ this.remaining = sr._3.reverse
+ sr = null
+ override def toString = {
+ "MixtureRule("+scrutinee+":"+scrutinee.tpe+") {\n moreSpecific:"+moreSpecific+"\n subsumed:"+subsumed+"\n remaining"+remaining+"\n}"
+ }
+
+ def getTransition(implicit theOwner: Symbol): (Symbol, Rep, Option[Rep]) = {
+ // the following works for type tests... what fudge is necessary for value comparisons?
+ // type test
+ casted = if(scrutinee.tpe =:= patternType) scrutinee else newVar(scrutinee.pos, patternType)
+ if(scrutinee.hasFlag(symtab.Flags.CAPTURED))
+ casted.setFlag(symtab.Flags.CAPTURED)
+ // succeeding => transition to translate(subsumed) (taking into account more specific)
+ val nmatrix = {
+ var ntemps = 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)
+ ctemp
+ } // (***)
+ var subtests = subsumed
+
+ if(moreSpecific.exists { x => x != EmptyTree }) {
+ ntemps = casted::ntemps // (***)
+ subtests = moreSpecific.zip(subsumed) map { case (mspat, (j,pats)) => (j,mspat::pats) }
+ }
+ ntemps = ntemps ::: rest.temp
+ val ntriples = subtests map {
+ case (j,pats) =>
+ val (vs:List[Symbol],_) = strip(column(j));
+ val (opats,osubst:List[(Symbol,Symbol)],og,ob) = rest.row(j);
+ val subst1:List[(Symbol,Symbol)] = vs map { v => (v,casted) }
+
+ DEBUG("getTransition, vs = "+vs)
+ DEBUG("getTransition, subst1 = "+subst1)
+
+ // def doSubst(vs:List[Symbol], exp:Tree) = { new TreeSymSubstituter(vs,vs map {x=> casted}).traverse(exp); exp }
+
+ // don't substitute eagerly here, problems with bodies that can be reached with several routes
+ // problems would disappear if we didn't aim for sharing code and &^% duplicate would correctly duplicate definitions (alloc new symbols)
+
+ (pats ::: opats, osubst ::: subst1, og, ob) // don't duplicate body/guard, get "defined twice" error cause hashing breaks
+ }
+ Rep(ntemps, ntriples) setParent this
+ }
+ DEBUG("nmatrix for type "+patternType)
+ DEBUG(nmatrix.toString)
+
+ // and then more or this... Console.println(nmatrix.applyRule)
+ // CONTINUE HERE: epsilon transitions, which ensure that transitions are tested in the right order.
+
+ // fails => transition to translate(remaining)
+
+ val nmatrixFail: Option[Rep] = {
+ val ntemps = scrutinee::rest.temp
+ val ntriples = remaining map {
+ case (j, pat) => val r = rest.row(j); (pat :: r._1, r._2, r._3, r._4)
+ }
+ if(ntriples.isEmpty) None else Some(Rep(ntemps, ntriples) setParent this)
+ }
+ if(!nmatrixFail.isEmpty) {
+ DEBUG("nmatrix for failing type test "+patternType)
+ DEBUG(nmatrixFail.get.toString)
+ } else {
+ DEBUG("pattern type "+patternType+" cannot fail for "+scrutinee)
+ }
+ (casted, nmatrix, nmatrixFail)
+ } // end getTransitions
+ }
+
+ def repToTree(rep:Rep, typed:Tree => Tree, handleOuter: Tree => Tree)(implicit theOwner: Symbol, failTree: Tree, bodies: collection.mutable.Map[Tree,(Tree,Tree, Symbol)]): Tree = {
+ rep.applyRule match {
+ case VariableRule(subst, EmptyTree, b) => bodies.get(b) match {
+ case Some(EmptyTree, b, theLabel) =>
+ // (**) approach 2
+ val body = Apply(Ident(theLabel), subst.map { p => Ident(p._2) })
+ return body
+
+ // (*) approach 1
+ //DEBUG("--- variable \n JUMP ! subst = "+subst)
+ val vdefs = subst map {
+ case (v,t) => ValDef(v, {v.setFlag(symtab.Flags.TRANS_FLAG);
+ if(v.tpe <:< t.tpe) typed{gen.mkAsInstanceOf(Ident(t),v.tpe)} /*refinement*/ else typed{Ident(t)}})
+ }
+ // @todo! transfer variables/subst
+ Apply(Ident(theLabel), List())
+ case None =>
+ //DEBUG("--- variable \n new ! subst = "+subst)
+ val theLabel = theOwner.newLabel(b.pos, "body"+b.hashCode).setInfo(new MethodType(subst map { case (v,_) => v.tpe}, b.tpe))
+ // make new value parameter for each vsym in subst
+ // (**) approach 2
+ //val pdefsyms = subst map { case (v,tmp) => theLabel.newValueParameter(v.pos, v.name+"_!") . setInfo (v.tpe). setFlag(symtab.Flags.MUTABLE) }
+ DEBUG("subst of "+b.hashCode+"! in case VariableRule (new) "+subst)
+ val vdefs = subst map { case (v,t) => ValDef(v, {v.setFlag(symtab.Flags.TRANS_FLAG);
+ if(v.tpe =:= t.tpe) typed{Ident(t)} else typed{gen.mkAsInstanceOf(Ident(t),v.tpe)}}) }
+ // this weird thing should only be done for shared states.
+ val dom = subst.map(._1)
+ //val tss = new TreeSymSubstituter(dom,pdefsyms)
+ var nbody: Tree = b
+ //tss.traverse(nbody)
+ val vrefs = vdefs.map { p:ValDef => Ident(p.symbol) }
+ nbody = Block(vdefs:::List(Apply(Ident(theLabel), vrefs)), LabelDef(theLabel, subst.map(._1), nbody))
+ /*
+ val body = LabelDef(theLabel, List(), b.duplicate)
+ // (*) approach 1
+ val (dom,cod) = List.unzip(subst map {
+ case (v,t) => (v,{if(v.tpe =:= t.tpe) typed{Ident(t)} else typed{gen.mkAsInstanceOf(Ident(t),v.tpe)}})})
+ val tss = new TreeSubstituter(dom,cod)
+ val nbody = tss.transform(body)
+ //@todo
+ // instead of substitution, use valdefs
+ // val vdefs = subst map {
+ // case (v,t) => ValDef(v, {if(v.tpe <:< t.tpe) typed{gen.mkAsInstanceOf(Ident(t),v.tpe)} /*refinement*/ else typed{Ident(t)}})
+ //}
+
+ */
+ bodies(b) = (EmptyTree, nbody, theLabel)
+ nbody
+ }
+ case VariableRule(subst,g,b) =>
+ throw CantHandleGuard
+ case mm:MixtureRule =>
+ val (casted,srep,frep) = mm.getTransition
+ //DEBUG("--- mixture \n succ \n"+srep.toString+"\n fail\n"+frep.toString)
+ //val cond = typed{gen.mkIsInstanceOf(Ident(mm.scrutinee), casted.tpe)}
+ var cond = typed { condition(casted.tpe, mm.scrutinee) }
+ if(needsOuterTest(casted.tpe, mm.scrutinee.tpe)) // @todo merrge into def condition
+ cond = addOuterCondition(cond, casted.tpe, typed{Ident(mm.scrutinee)}, handleOuter)
+ val succ = repToTree(srep, typed, handleOuter)
+ val fail = if(frep.isEmpty) {
+ /*
+ if (true || casted.tpe.symbol.hasFlag(symtab.Flags.SEALED)) {
+ cunit.warning(casted.pos, "match not exhaustive! ");
+ var rep1 = rep
+ var mr,last : MixtureRule = null
+ while((rep1 ne null) && {mr = rep1.mixtureParent; mr ne null}) {
+ Console.println("casted "+casted+" !?:"+mr.scrutinee+" ? "+mr.column.head.tpe)
+ Console.println(mr.isExhaustive)
+ rep1 = mr.parent
+ last = mr
+ }
+ }
+ Console.println("BASTA")
+ */
+ failTree
+ } else repToTree(frep.get, typed, handleOuter)
+
+ // dig out case field accessors that were buried in (***)
+ val cfa = casted.caseFieldAccessors
+ //DEBUG(casted.toString)
+ //DEBUG(cfa.toString)
+ val caseTemps = (if(!srep.temp.isEmpty && srep.temp.head == casted) srep.temp.tail else srep.temp).zip(cfa)
+
+ //DEBUG(caseTemps.toString)
+ var vdefs = caseTemps map {
+ case (tmp,meth) =>
+ val typedAccess = typed { Apply(Select(typed{Ident(casted)}, meth),List()) }
+ typed { ValDef(tmp, typedAccess) }
+ }
+
+ vdefs = typed { ValDef(casted, gen.mkAsInstanceOf(typed{Ident(mm.scrutinee)}, casted.tpe))} :: vdefs
+ def makeIf(cond:Tree, thenp:Tree, elsep:Tree) = cond match {
+ case Literal(Constant(true)) => thenp
+ case Literal(Constant(false)) => elsep
+ case _ => If(cond, thenp, elsep)
+ }
+ typed { makeIf(cond, /*squeezed*/Block(vdefs,succ), fail) }
+ }
+ }
+
+ def makeRep(temp:List[Symbol], row1:List[(List[Tree], List[(Symbol,Symbol)], Tree, Tree)]/*, exCh:List[Boolean]*/): Rep = {
+ var i = -1
+ val row = row1 flatMap {
+ xx =>
+ def isAlternative(p: Tree): Boolean = p match {
+ case Bind(_,p) => isAlternative(p)
+ case Alternative(ps) => true
+ case _ => false
+ }
+ def getAlternativeBranches(p:Tree): List[Tree] = {
+ def get_BIND(pctx:Tree => Tree, p:Tree):List[Tree] = p match {
+ case b @ Bind(n,p) => get_BIND({ x:Tree => pctx(copy.Bind(b, n, x) setType x.tpe) }, p)
+ case Alternative(ps) => ps map pctx
+ }
+ get_BIND({x=>x}, p)
+ }
+ val (pats,subst,g,b) = xx
+ i = pats findIndexOf isAlternative
+ if(i == -1)
+ List((pats,subst,g,b))
+ else {
+ val prefix:List[Tree] = pats.take(i)
+ val alts = getAlternativeBranches(pats(i))
+ val suffix:List[Tree] = pats.drop(i+1)
+ alts map { p => (prefix ::: p :: suffix, subst, g, b) }
+ }
+ }
+ if(i == -1)
+ Rep(temp,row/*,ex*/)
+ else
+ makeRep(temp,row/*,ex*/)
+ }
+
+ case class Rep(val temp:List[Symbol], val row:List[(List[Tree], List[(Symbol,Symbol)], Tree, Tree)]/*, val exhaustivenessChecked:List[Boolean]*/) {
+ assert(row.forall { case (pats,subst,g,b) => temp.length == pats.length })
+
+ var sealedCols = List[Int]()
+ var sealedComb = List[Set[Symbol]]()
+ //Console.println(" the matrix "+this.toString)
+ temp.zipWithIndex.foreach {
+ 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 presence of catch-all at higher level
+ sym.tpe.symbol.hasFlag(symtab.Flags.SEALED)) {
+
+ sym.resetFlag(symtab.Flags.MUTABLE)
+ if(row.exists { case (pats,_,_,_) => isDefaultPattern(pats(i)) })
+ sym.setFlag(symtab.Flags.CAPTURED) // mark presence of catch-all
+ else {
+ sealedCols = i::sealedCols
+ // this should enumerate all cases... however, also the superclass is taken if it is not abstract
+ def checkExCoverage(tpesym:Symbol): SymSet =
+ if(!tpesym.hasFlag(symtab.Flags.SEALED)) emptySymbolSet else
+ tpesym.children.flatMap { x =>
+ val z = checkExCoverage(x)
+ if(x.hasFlag(symtab.Flags.ABSTRACT)) z else z + x
+ }
+
+ val cases = checkExCoverage(sym.tpe.symbol)
+ sealedComb = cases::sealedComb
+ }
+ }
+ }
+ // computes cartesian product, keeps indices available
+ def combine(colcom: List[(Int,Set[Symbol])]): List[List[(Int,Symbol)]] = colcom match {
+ case Nil => Nil
+ case (i,syms)::Nil => syms.toList.map { sym => List((i,sym)) }
+ case (i,syms)::cs => for(val s <- syms.toList; val rest <- combine(cs)) yield (i,s) :: rest
+ }
+
+ if(!sealedCols.isEmpty) {
+ DEBUG("cols"+sealedCols)
+ DEBUG("comb")
+ for(val com <- sealedComb)
+ DEBUG(com.toString)
+
+ val allcomb = combine(sealedCols zip sealedComb)
+ //Console.println("all comb!" + allcomb)
+ // returns true if pattern vector covers all type symbols
+ def covers(pats: List[Tree], comb:List[(Int,Symbol)]) = {
+ comb forall { case (i,sym) => pats(i).tpe.symbol == sym }
+ }
+ val coversAll = allcomb forall { combination => row exists { r => covers(r._1, combination)}}
+ //Console.println("all combinations covered? "+coversAll)
+ if(!coversAll) {
+ val sb = new compat.StringBuilder()
+ sb.append("match is not exhaustive!\n")
+ for(val open <- allcomb;
+ !(row exists { r => covers(r._1, open)})) {
+ sb.append("missing combination ")
+ val NPAD = 15
+ def pad(s:String) = { Iterator.range(1,NPAD - s.length).foreach { x => sb.append(" ") }; sb.append(s) }
+ List.range(0, temp.length) foreach {
+ i => open.find { case (j,sym) => j==i } match {
+ case None => pad("*")
+ case Some((_,sym)) => pad(sym.name.toString)
+ }
+ }
+ sb.append('\n')
+ }
+ cunit.warning(temp.head.pos, sb.toString)
+ }
+ }
+ // if this was the *fail* branch, the Rep preceding this Rep
+ var mixtureParent: MixtureRule = null
+
+ def setParent(mr:MixtureRule): this.type = { mixtureParent = mr; this }
+ //assert(temp.length == exhaustivenessChecked.length)
+ /*
+ def prepend(temp1:List[Symbol], row2:List[List[Tree]]) = {
+ assert(row.length == row2.length)
+ Rep(temp1 ::: temp, row.zip(row2) map { case ((pats,g,b),pats2) => (pats2:::pats,g,b) })
+ }
+ */
+ def applyRule: RuleApplication = row match {
+ case Nil => ErrorRule
+ case (pats,subst,g,b)::xs =>
+ if(pats forall isDefaultPattern) {
+ val subst1 = pats.zip(temp) flatMap { case (p,tmp) => val (vs,_) = strip(p); vs.zipAll(Nil,null,tmp)}
+ DEBUG("applyRule! subst1="+subst1)
+ VariableRule (subst:::subst1, g, b)
+ } else {
+ val i = pats findIndexOf {x => !isDefaultPattern(x)}
+
+ val column = row map { case (pats,subst,g,b) => pats(i) }
+ //val ex = exhaustivenessChecked(i)
+ val restTemp = temp.take(i) ::: temp.drop(i+1)
+ val restRows = row map { case (pats,subst,g,b) => (pats.take(i) ::: pats.drop(i+1),subst,g,b) }
+ //val restEx = exhaustivenessChecked.take(i) ::: exhaustivenessChecked.drop(i+1)
+ MixtureRule(temp(i), column, makeRep(restTemp,restRows/*,restEx*/)) setParent this
+ }
+ }
+ // a fancy toString method for debugging
+ override def toString = {
+ val sb = new StringBuilder
+ val NPAD = 15
+ def pad(s:String) = { Iterator.range(1,NPAD - s.length).foreach { x => sb.append(" ") }; sb.append(s) }
+ for(val tmp <- temp) pad(tmp.name.toString)
+ sb.append('\n')
+ for(val (r,i) <- row.zipWithIndex) {
+ for(val c <- r._1 ::: List(r._2, r._3)) {
+ pad(c.toString)
+ }
+ sb.append('\n')
+ }
+ sb.toString
+ }
+ }
+
+ def initRep(selector:Tree, cases:List[Tree], checkExhaustive: Boolean)(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)
+ val row = cases map { case CaseDef(pat,g,b) => (List(pat),List(),g,b) }
+ makeRep(List(root), row)
+ }
+ /** this tree node is used several times in the parallel algo and will never be needed for matching, so it is reused */
+ val Ident_WILDCARD = Ident(nme.WILDCARD) setType definitions.AnyClass.tpe
+
+ val NoSymbol_Ident_WILDCARD = (NoSymbol, EmptyTree);
+
+ // ---------------------------------- helper functions that extract information from patterns, symbols, types
+
+ /** returns if pattern can be considered a no-op test ??for expected type?? */
+ def isDefaultPattern(pattern:Tree): Boolean = pattern match {
+ case Bind(_, p) => isDefaultPattern(p)
+ case EmptyTree => true // dummy
+ case Ident(nme.WILDCARD) => true
+ case _ => false
+// -- what about the following? still have to test "ne null" :/
+// case Typed(nme.WILDCARD,_) => pattern.tpe <:< scrutinee.tpe
+ }
+
+ /** returns all variables that are binding the given pattern */
+ def strip(x:Tree): (List[Symbol], Tree) = x match {
+ case b @ Bind(_,pat) => val (vs,p) = strip(pat); (b.symbol :: vs,p)
+ case z => (Nil,z)
+ }
+
+ // ---------------------------------- functions used in internal data structure of the algorithm (matrix)
+
+ /** an entry ((x,m),y) hints at a case field access "val y = x.m" (@see tempValdef). we can recover the parent (@see getParent)
+ */
+// type TempMap = collection.mutable.Map[(Symbol,Symbol),Symbol]
+
+ /** returns the temp which is the "parent" of the given temp */
+/*
+ def getParent(sym:Symbol)(implicit memo: TempMap): Option[((Symbol, Symbol), Symbol)] = memo.elements.find { x => x._2 == sym }
+
+ def getChild(pos: PositionType, scrutineeSymbol:Symbol, theCaseFieldAccessor:Symbol)(implicit memo: TempMap, theOwner: Symbol) = {
+ val p = (scrutineeSymbol,theCaseFieldAccessor)
+ memo.get (p) match {
+ case Some(v) => v
+ case None => val v = newVar(pos, scrutineeSymbol.tpe.memberType(theCaseFieldAccessor).resultType); memo.update(p, v); v
+ }
+ }
+
+ def tempValDef1(tmpsym:Symbol)(implicit memo: TempMap): Option[Tree] =
+ getParent(tmpsym) match {
+ case Some((par,meth),_) => Some(ValDef(tmpsym, Select(Ident(par),meth)))
+ case None => None //assert(scrut == root.casted); Block(List(ValDef(scrut, selector)), theTest)
+ }
+*/
+ /** same as tempValDef, but with a default (typically root=selector)
+ def tempValDef(tmpsym:Symbol, default: Tree)(implicit memo: TempMap): Tree = // overloading+implicit+tuple == bug
+ getParent(tmpsym) match {
+ case Some((par,meth),_) => ValDef(tmpsym, Select(Ident(par),meth))
+ case None => ValDef(tmpsym, default)
+ }
+*/
+
+ /** an entry ((x,T),y) hints at a case field access "val y = x.asInstanceOf[T]" (@see caseValdef).
+ type CastMap = collection.mutable.Map[(Symbol,Type),Symbol]
+
+ def getCasted(oldScrutineeSymbol: Symbol, patternType: Type)(implicit castMap: CastMap, theOwner: Symbol) = {
+ val p = (oldScrutineeSymbol, patternType)
+ castMap.get (p) match {
+ case Some(v) => v
+ case None => val v = newVar(oldScrutineeSymbol.pos, patternType); castMap.update(p,v); v
+ }
+ }
+
+ def castValDef(oldScrutinee: Symbol, tpe:Type)(implicit castMap: CastMap): Tree = {
+ val newScrutinee = castMap.get((oldScrutinee, tpe)).get
+ ValDef(newScrutinee, gen.mkAsInstanceOf(Ident(oldScrutinee), tpe))
+ }
+*/
+ /** creates a new entry for casting, and replaces the scrutinee in give patterns
+ def doCast(scrutineeSymbol:Symbol, pattern:Tree)(implicit castMap: CastMap, theOwner: Symbol) = {
+ val patternType = pattern.tpe
+ val newScrutinee = getCasted(scrutineeSymbol, patternType)
+ (newScrutinee, pattern)
+ }
+*/
+ // access to children for matched constructor patterns
+
+ /** for a case pattern, returns subpatterns, otherwise a sequence of dummy wildcard patterns
+ * @param x tuple2 where _1 is the temp containing the scrutinee, _2 is the pattern
+ def childPats(x:(Symbol,Tree), len:Int)(implicit memo: TempMap, theOwner: Symbol) = {
+ def childPatsOfPattern(p:Tree): List[(Symbol,Tree)] = p match {
+ case Bind(_, p) => childPatsOfPattern(p)
+
+ // for case patterns, get children... condition necessary since e.g. pattern 'nme.CONSTRUCTOR' is also an Apply(fn,())
+ case app @ Apply(fn, patargs) if app.tpe.symbol.hasFlag(symtab.Flags.CASE) =>
+ val patternSymbol = app.tpe.symbol
+ val scrutineeSymbol = x._1
+ assert( patternSymbol.caseFieldAccessors.length == len)
+ assert(scrutineeSymbol.tpe.symbol.tpe =:= patternSymbol.tpe)
+ patternSymbol.caseFieldAccessors.map( { z => getChild(app.pos, scrutineeSymbol, z) }).zip(patargs)
+ case _ =>
+ List.range(0,len) map { x => NoSymbol_Ident_WILDCARD } //(NoSymbol, Ident_WILDCARD)
+ }
+ childPatsOfPattern(x._2)
+ }
+*/
+
+ // ---------------------------------- helper functions that generate symbols, trees for type tests, pattern tests
+
+ def newVar(pos: PositionType, 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)
+ sym.setInfo(tpe)
+ sym
+ }
+
+ def newVar(pos: PositionType, tpe: Type)(implicit theOwner: Symbol): Symbol =
+ newVar(pos, cunit.fresh.newName("temp"), tpe).setFlag(symtab.Flags.SYNTHETIC)
+
+ /** returns the condition in "if(cond) k1 else k2"
+ */
+ def condition(tpe: Type, scrut: Symbol) = {
+ val res = condition1(tpe, scrut)
+ DEBUG("condition, tpe = "+tpe+", scrut.tpe = "+scrut.tpe+", res = "+res)
+ res
+ }
+ def condition1(tpe: Type, scrut: Symbol) = {
+ assert( tpe ne NoType )
+ assert(scrut ne NoSymbol)
+ if(tpe.isInstanceOf[SingletonType] && !tpe.isInstanceOf[ConstantType]) {
+ if(scrut.tpe <:< definitions.AnyRefClass.tpe)
+ Eq(gen.mkAttributedRef(tpe.symbol), Ident(scrut)) // object
+ else
+ Equals(gen.mkAttributedRef(tpe.symbol), Ident(scrut)) // object
+ } else if(tpe.isInstanceOf[ConstantType]) {
+ val value = tpe.asInstanceOf[ConstantType].value
+ //if(false && value.isInstanceOf[NamedConstant])
+ // Equals(Ident(scrut), value.asInstanceOf[NamedConstant].tree) // constant
+ //assert(scrut.tpe <:< definitions.AnyRefClass.tpe, "stupid, should be caught by type checker "+value)
+ //else
+ if(value == Constant(null) && scrut.tpe <:< definitions.AnyRefClass.tpe)
+ Eq(Ident(scrut), Literal(value)) // constant
+ else
+ Equals(Ident(scrut), Literal(value)) // constant
+ } else if(scrut.tpe <:< tpe && tpe <:< definitions.AnyRefClass.tpe)
+ NotNull(Ident(scrut))
+ else if(tpe.prefix.symbol.isTerm && tpe.symbol.linkedModuleOfClass != NoSymbol) { // object
+ Console.println("iT"+tpe.prefix.symbol.isTerm)
+ Console.println("lmoc"+tpe.symbol.linkedModuleOfClass)
+ Eq(gen.mkAttributedRef(tpe.prefix, tpe.symbol.linkedModuleOfClass), Ident(scrut))
+ } else
+ //Console.println(tpe.prefix.symbol.isTerm)
+ //Console.println(tpe.symbol)
+ //Console.println(tpe.symbol.linkedModuleOfClass)
+ gen.mkIsInstanceOf(Ident(scrut), tpe)
+ }
+
+ def needsOuterTest(tpe2test:Type, scrutinee:Type) = tpe2test match {
+ case TypeRef(prefix,_,_) =>
+ prefix.symbol.isTerm &&
+ !prefix.symbol.isPackage &&
+ outerAlwaysEqual(tpe2test,scrutinee) == Some(false)
+ case _ => false
+ }
+
+ /** returns a result if both are TypeRefs, returns Some(true) if left and right are statically known to have
+ * the same outer, i.e. if their prefixes are the same
+ */
+ def outerAlwaysEqual(left: Type, right: Type): Option[Boolean] = (left,right) match {
+ case (TypeRef(lprefix, _,_), TypeRef(rprefix,_,_)) =>
+ if(!(lprefix =:= rprefix)) {
+ DEBUG("DEBUG(outerAlwaysEqual) Some(f) for"+(left,right))
+ }
+ Some(lprefix =:= rprefix)
+ case _ => None
+ }
+
+ /** adds a test comparing the dynamic outer to the static outer */
+ def addOuterCondition(cond:Tree, tpe2test: Type, scrutinee: Tree, handleOuter: Tree=>Tree) = {
+ val TypeRef(prefix,_,_) = tpe2test
+ var theRef = gen.mkAttributedRef(prefix.prefix, prefix.symbol)
+
+ // needs explicitouter treatment
+ theRef = handleOuter(theRef)
+
+ val outerAcc = outerAccessor(tpe2test.symbol)
+ if(outerAcc == NoSymbol) {
+ if(settings.debug.value) cunit.warning(scrutinee.pos, "no outer acc for "+tpe2test.symbol)
+ cond
+ } else
+ And(cond,
+ Eq(Apply(Select(
+ gen.mkAsInstanceOf(scrutinee, tpe2test, true), outerAcc),List()), theRef))
+
+ }
+
+}