diff options
author | Paul Phillips <paulp@improving.org> | 2009-10-10 00:31:27 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2009-10-10 00:31:27 +0000 |
commit | 422ad71e10f559839ffa0fbd9a4c8dc721210986 (patch) | |
tree | f25365ce9d5e5984db4ab995dddac20d800c1e67 | |
parent | 1c67c5b849d57a3fae89c4156f4a15defceccbf4 (diff) | |
download | scala-422ad71e10f559839ffa0fbd9a4c8dc721210986.tar.gz scala-422ad71e10f559839ffa0fbd9a4c8dc721210986.tar.bz2 scala-422ad71e10f559839ffa0fbd9a4c8dc721210986.zip |
Starting the process of properly encapsulating ...
Starting the process of properly encapsulating the temporary variables
created during pattern match translation.
3 files changed, 82 insertions, 49 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/Matrix.scala b/src/compiler/scala/tools/nsc/matching/Matrix.scala index 07923059c1..c5373f0924 100644 --- a/src/compiler/scala/tools/nsc/matching/Matrix.scala +++ b/src/compiler/scala/tools/nsc/matching/Matrix.scala @@ -17,6 +17,7 @@ trait Matrix extends MatrixAdditions { import analyzer.Typer import CODE._ import Debug._ + import Flags.{ TRANS_FLAG } /** Translation of match expressions. * @@ -89,6 +90,41 @@ trait Matrix extends MatrixAdditions { matchResultType: Type) // the expected result type of the whole match extends Squeezer { + private def ifNull[T](x: T, alt: T) = if (x == null) alt else x + + // TRANS_FLAG communicates there should be no exhaustiveness checking + private def flags(checked: Boolean) = if (checked) Nil else List(TRANS_FLAG) + + /** Given a tree, creates a new synthetic variable of the same type + * and assigns the tree to it. + */ + def copyVar( + root: Tree, + _tpe: Type = null, + checked: Boolean = false, + label: String = "temp"): PatternVar = + { + val tpe = ifNull(_tpe, root.tpe) + val name = newName(root.pos, label) + val sym = newVar(root.pos, tpe, flags(checked), name) + + new PatternVar(sym, root) + } + + /** The rhs is expressed as a function of the lhs. */ + def createVar(tpe: Type, f: Symbol => Tree, checked: Boolean = false) = { + val lhs = newVar(owner.pos, tpe, flags(checked)) + val rhs = f(lhs) + + new PatternVar(lhs, rhs) + } + + class PatternVar(val lhs: Symbol, val rhs: Tree) { + lazy val ident = ID(lhs) + lazy val valDef = typedValDef(lhs, rhs) + // lazy val valDef = typedValDef(lhs, rhs setType lhs.tpe) + } + def newVar( pos: Position, tpe: Type, diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 46f8c8bfbe..8c15f7ae08 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -31,6 +31,7 @@ trait ParallelMatching extends ast.TreeDSL import CODE._ import Types._ import Debug._ + import Flags.{ TRANS_FLAG } /** Transition **/ def isRightIgnoring(t: Tree) = cond(unbind(t)) { case ArrayValue(_, xs) if !xs.isEmpty => isStar(xs.last) } @@ -92,7 +93,7 @@ trait ParallelMatching extends ast.TreeDSL * Note that we only ever match on Symbols, not Trees: a temporary variable * is created for any expressions being matched on. */ - case class Scrutinee(val sym: Symbol) { + class Scrutinee(val sym: Symbol) { import definitions._ // presenting a face of our symbol @@ -117,7 +118,11 @@ trait ParallelMatching extends ast.TreeDSL def newVarOfElemType = newVar(pos, elemType) // for propagating "unchecked" to synthetic vars - def flags: List[Long] = List(Flags.TRANS_FLAG) filter (sym hasFlag _) + def isChecked = !(sym hasFlag TRANS_FLAG) + def flags: List[Long] = List(TRANS_FLAG) filter (sym hasFlag _) + + // this is probably where this actually belongs + def createVar(tpe: Type, f: Symbol => Tree) = context.createVar(tpe, f, isChecked) def castedTo(headType: Type) = if (tpe =:= headType) this @@ -332,18 +337,17 @@ trait ParallelMatching extends ast.TreeDSL val uapattern = head match { case x: UnapplyPattern => x ; case _ => abort("XXX") } val ua @ UnApply(app, args) = head.tree - private lazy val zipped = pmatch pzip rest.rows - // Note: trailingArgs is not necessarily Nil, because unapply can take implicit parameters. val Apply(fxn, _ :: trailingArgs) = app - def unapplyReturnType = if (args.isEmpty) BooleanClass.tpe else app.tpe typeArgs 0 + private def reapply = Apply(fxn, scrut.id :: trailingArgs) - lazy val unapplyVar = newVar(ua.pos, app.tpe, scrut.flags) - lazy val unapplyValDef = - typedValDef(unapplyVar, Apply(fxn, scrut.id :: trailingArgs) setType unapplyVar.tpe) + private lazy val zipped = pmatch pzip rest.rows - def mkGet(s: Symbol) = typedValDef(s, fn(ID(unapplyVar), nme.get)) - def mkVar(tpe: Type) = newVar(ua.pos, tpe, scrut.flags) + lazy val unapplyResult = + createVar(app.tpe, + lhs => reapply setType lhs.tpe, + scrut.isChecked + ) // XXX in transition. object sameUnapplyCall { @@ -369,7 +373,7 @@ trait ParallelMatching extends ast.TreeDSL } lazy val cond: Tree = { - val s = unapplyValDef.symbol + val s = unapplyResult.valDef.symbol if (s.tpe.isBoolean) ID(s) else s IS_DEFINED } @@ -377,41 +381,40 @@ trait ParallelMatching extends ast.TreeDSL lazy val failure = mkFail(zipped.tail filterNot (x => isSameUnapply(x._1)) map { case (pat, r) => r insert pat }) - lazy val success = { - val (vdefs, ntemps, nrows) = - args.length match { - case 0 => - (Nil, Nil, mkNewRows((xs) => Nil, 0)) + private def doSuccess: (List[Tree], List[Symbol], List[Row]) = { + def mkVar(tpe: Type) = newVar(ua.pos, tpe, scrut.flags) - case 1 => - val lhs = mkVar(app.tpe typeArgs 0) - val vdef = mkGet(lhs) - (List(vdef), List(lhs), mkNewRows(xs => List(xs.head), 1)) + lazy val lhs = mkVar(app.tpe typeArgs 0) + lazy val vdef = typedValDef(lhs, fn(ID(unapplyResult.lhs), nme.get)) - case _ => - val uresGet = mkVar(app.tpe typeArgs 0) - val vdefHead = mkGet(uresGet) - val ts = getProductArgs(uresGet.tpe).get - val nrows = mkNewRows(identity, ts.size) + // at this point it's Some[T1,T2...] + lazy val tpes = getProductArgs(lhs.tpe).get - val (vdefs: List[Tree], vsyms: List[Symbol]) = List.unzip( - for ((vtpe, i) <- ts.zipWithIndex) yield { - val vchild = mkVar(vtpe) - val accSym = productProj(uresGet, i+1) - val rhs = fn(ID(uresGet), accSym) + // one allocation per tuple element + lazy val allocations = + for ((tpe, i) <- tpes.zipWithIndex) yield + scrut.createVar(tpe, _ => fn(ID(lhs), productProj(lhs, i + 1))) - (typedValDef(vchild, rhs), vchild) - }) + def vdefs = allocations map (_.valDef) + def vsyms = allocations map (_.lhs) - (vdefHead :: vdefs, vsyms, nrows) - } + // 0 is Boolean, 1 is Option[T], 2+ is Option[(T1,T2,...)] + args.length match { + case 0 => (Nil, Nil, mkNewRows((xs) => Nil, 0)) + case 1 => (List(vdef), List(lhs), mkNewRows(xs => List(xs.head), 1)) + case _ => (vdef :: vdefs, vsyms, mkNewRows(identity, tpes.size)) + } + } + + lazy val success = { + val (vdefs, ntemps, rows) = doSuccess + val srep = make(ntemps ::: scrut.sym :: rest.tvars, rows).toTree - val srep = make(ntemps ::: scrut.sym :: rest.tvars, nrows).toTree squeezedBlock(vdefs, srep) } final def tree() = - squeezedBlock(List(handleOuter(unapplyValDef)), codegen) + squeezedBlock(List(handleOuter(unapplyResult.valDef)), codegen) } /** handle sequence pattern and ArrayValue (but not star patterns) diff --git a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala index 6a31a68989..4d8315530f 100644 --- a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala +++ b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala @@ -24,7 +24,6 @@ trait TransMatcher extends ast.TreeDSL with CompactTreePrinter { import global.{ typer => _, _ } import analyzer.Typer import definitions._ - import symtab.Flags import CODE._ // cunit is set to the current unit in ExplicitOuter's transformUnit, @@ -45,10 +44,9 @@ trait TransMatcher extends ast.TreeDSL with CompactTreePrinter { { import context._ - // TRANS_FLAG communicates that there should be no exhaustiveness checking - val flags = List(Flags.TRANS_FLAG) filterNot (_ => isChecked) def matchError(obj: Tree) = atPos(selector.pos)(THROW(MatchErrorClass, obj)) def caseIsOk(c: CaseDef) = cond(c.pat) { case _: Apply | Ident(nme.WILDCARD) => true } + def rootTypes = selector.tpe.typeArgs // this appears to be an attempt at optimizing when all case defs are constructor // patterns, but I don't think it's correct. @@ -58,22 +56,18 @@ trait TransMatcher extends ast.TreeDSL with CompactTreePrinter { // For x match { ... we start with a single root def singleMatch(): (List[Tree], MatrixInit) = { - val root: Symbol = newVar(selector.pos, selector.tpe, flags) - val varDef: Tree = typedValDef(root, selector) + val v = copyVar(selector, checked = isChecked) - (List(varDef), MatrixInit(List(root), cases, matchError(ID(root)))) + (List(v.valDef), MatrixInit(List(v.lhs), cases, matchError(v.ident))) } // For (x, y, z) match { ... we start with multiple roots, called tpXX. def tupleMatch(app: Apply): (List[Tree], MatrixInit) = { val Apply(fn, args) = app - val (roots, vars) = List.unzip( - for ((arg, typeArg) <- args zip selector.tpe.typeArgs) yield { - val v = newVar(arg.pos, typeArg, flags, newName(arg.pos, "tp")) - (v, typedValDef(v, arg)) - } - ) - (vars, MatrixInit(roots, cases, matchError(treeCopy.Apply(app, fn, roots map ID)))) + val vs = args zip rootTypes map { case (arg, tpe) => copyVar(arg, tpe, isChecked, "tp") } + + def merror = matchError(treeCopy.Apply(app, fn, vs map (_.ident))) + (vs map (_.valDef), MatrixInit(vs map (_.lhs), cases, merror)) } // sets up top level variables and algorithm input |