From 112a1dbef04bdeb8255ab4af709b2e16a79bc827 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sun, 11 Oct 2009 20:17:32 +0000 Subject: Further iteration related to patterns and bindi... Further iteration related to patterns and bindings. --- src/compiler/scala/tools/nsc/matching/Matrix.scala | 1 + .../tools/nsc/matching/ParallelMatching.scala | 67 ++++++++++++++-------- .../scala/tools/nsc/matching/Patterns.scala | 46 ++++++++------- 3 files changed, 68 insertions(+), 46 deletions(-) diff --git a/src/compiler/scala/tools/nsc/matching/Matrix.scala b/src/compiler/scala/tools/nsc/matching/Matrix.scala index 96b665f2ea..c489955e5e 100644 --- a/src/compiler/scala/tools/nsc/matching/Matrix.scala +++ b/src/compiler/scala/tools/nsc/matching/Matrix.scala @@ -158,6 +158,7 @@ trait Matrix extends MatrixAdditions { override def toString() = "%s: %s = %s".format(lhs, lhs.info, rhs) } + // val NoPatternVar = PatternVar(NoSymbol, EmptyTree, false) /** Sets the rhs to EmptyTree, which makes the valDef ignored in Scrutinee. */ diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 0e08c0eaf5..5c27a7373c 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -53,12 +53,15 @@ trait ParallelMatching extends ast.TreeDSL -shortCuts.length } + // XXX transitional. + final def requestBody(bx: Int, subst: Bindings): Tree = + requestBody(bx, PatternVarGroup.fromBindings(subst.get(), targets(bx).freeVars)) + /** first time bx is requested, a LabelDef is returned. next time, a jump. * the function takes care of binding */ - final def requestBody(bx: Int, subst: Bindings): Tree = { - val target @ FinalState(tbx, body, freeVars) = targets(bx) - val pvgroup = PatternVarGroup.fromBindings(subst.get(), freeVars) + final def requestBody(bx: Int, pvgroup: PatternVarGroup): Tree = { + val target = targets(bx) // shortcut if (bx < 0) Apply(ID(shortCuts(-bx-1)), Nil) @@ -70,7 +73,7 @@ trait ParallelMatching extends ast.TreeDSL /** the injection here handles alternatives and unapply type tests */ final def make(tvars: PatternVarGroup, row1: List[Row]): Rep = { - def classifyPat(opat: Pattern, j: Int): Pattern = opat simplify tvars(j).sym + def classifyPat(opat: Pattern, j: Int): Pattern = opat simplify tvars(j) val rows = row1 flatMap (_ expandAlternatives classifyPat) if (rows.length != row1.length) make(tvars, rows) // recursive call if any change @@ -114,10 +117,13 @@ trait ParallelMatching extends ast.TreeDSL // sequences def seqType = tpe.widen baseType SeqClass def elemType = tpe typeArgs 0 - def elemAt(i: Int) = (id DOT (tpe member nme.apply))(LIT(i)) - def createElemVar(i: Int) = createVar(elemType, _ => elemAt(i)) - def createSeqVar(drop: Int) = createVar(seqType, _ => id DROP drop) + private def elemAt(i: Int) = (id DOT (tpe member nme.apply))(LIT(i)) + private def createElemVar(i: Int) = createVar(elemType, _ => elemAt(i)) + private def createSeqVar(drop: Int) = createVar(seqType, _ => id DROP drop) + + def createSequenceVars(count: Int): List[PatternVar] = + (0 to count).toList map (i => if (i < count) createElemVar(i) else createSeqVar(i)) // for propagating "unchecked" to synthetic vars def isChecked = !(sym hasFlag TRANS_FLAG) @@ -171,6 +177,7 @@ trait ParallelMatching extends ast.TreeDSL def isCaseHead = head.isCaseClass private val dummyCount = if (isCaseHead) headType.typeSymbol.caseFieldAccessors.length else 0 def dummies = emptyPatterns(dummyCount) + // def dummies = head.dummies def apply(i: Int): Pattern = ps(i) def pzip() = ps.zipWithIndex @@ -362,7 +369,8 @@ trait ParallelMatching extends ast.TreeDSL private def sameFunction(fn1: Tree) = fxn.symbol == fn1.symbol && (fxn equalsStructure fn1) def unapply(p: Pattern) = condOpt(p) { - case Pattern(UnApply(Apply(fn1, _), args), _) if sameFunction(fn1) => args + case Pattern(UnApply(Apply(fn1, _), args), _) if sameFunction(fn1) => + tracing("sameUnapply", args) } } object SameUnapply { @@ -373,13 +381,6 @@ trait ParallelMatching extends ast.TreeDSL } def isSameUnapply(p: Pattern) = SameUnapply.unapply(p).isDefined - // Second argument is number of dummies to prepend in the default case - def mkNewRows(sameFilter: (List[Tree]) => List[Tree], dum: Int) = - for ((pat, r) <- zipped) yield pat match { - case sameUnapplyCall(args) => r.insert2(toPats(sameFilter(args)) ::: List(NoPattern), pat.boundVariables, scrut.sym) - case _ => r insert (emptyPatterns(dum) ::: List(pat)) - } - lazy val cond: Tree = if (unapplyResult.tpe.isBoolean) ID(unapplyResult.valsym) else unapplyResult.valsym IS_DEFINED @@ -403,11 +404,20 @@ trait ParallelMatching extends ast.TreeDSL for ((tpe, i) <- tpes.zipWithIndex) yield scrut.createVar(tpe, _ => fn(ID(tuple), productProj(tuple, i + 1))) + // the filter prevents infinite unapply recursion + def mkNewRows(sameFilter: (List[Tree]) => List[Tree]) = { + val dum = if (args.length <= 1) args.length else tpes.size + for ((pat, r) <- zipped) yield pat match { + case sameUnapplyCall(xs) => r.insert2(toPats(sameFilter(xs)) ::: List(NoPattern), pat.boundVariables, scrut.sym) + case _ => r insert (emptyPatterns(dum) ::: List(pat)) + } + } + // 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(pv), List(pv), mkNewRows(xs => List(xs.head), 1)) - case _ => (pv :: tuplePVs, tuplePVs, mkNewRows(identity, tpes.size)) + case 0 => (Nil, Nil, mkNewRows((xs) => Nil)) + case 1 => (List(pv), List(pv), mkNewRows(xs => List(xs.head))) + case _ => (pv :: tuplePVs, tuplePVs, mkNewRows(identity)) } } @@ -437,7 +447,8 @@ trait ParallelMatching extends ast.TreeDSL } def getSubPatterns(x: Pattern): Option[List[Pattern]] = { - def defaults = Some(emptyPatterns(pivot.elemPatterns.length + 1)) + // def defaults = Some(emptyPatterns(pivot.elemPatterns.length + 1)) + def defaults = Some(pivot.dummies) val av @ ArrayValue(_, xs) = x.tree match { case x: ArrayValue => x case EmptyTree | WILD() => return defaults @@ -467,8 +478,7 @@ trait ParallelMatching extends ast.TreeDSL assert(scrut.tpe <:< head.tpe, "fatal: %s is not <:< %s".format(scrut, head.tpe)) // one pattern var per sequence element up to elemCount, and one more for the rest of the sequence - val elemCount = pivot.nonStarPatterns.size - val pvs = ((0 until elemCount).toList map (scrut createElemVar _)) ::: List(scrut createSeqVar elemCount) + val pvs = scrut createSequenceVars pivot.nonStarPatterns.size val (nrows, frows): (List[Option[Row]], List[Option[Row]]) = List.unzip( for ((c, rows) <- pmatch pzip rest.rows) yield getSubPatterns(c) match { @@ -663,11 +673,12 @@ trait ParallelMatching extends ast.TreeDSL // returns this rows with alternatives expanded def expandAlternatives(classifyPat: (Pattern, Int) => Pattern): List[Row] = { + def isNotAlternative(p: Pattern) = !cond(p.tree) { case _: Alternative => true } + // classify all the top level patterns - alternatives come back unaltered val newPats: List[Pattern] = pats.zipWithIndex map tupled(classifyPat) // see if any alternatives were in there - val (ps, others) = newPats span (x => !x.isAlternative) - + val (ps, others) = newPats span isNotAlternative // make a new row for each alternative, with it spliced into the original position if (others.isEmpty) List(copy(pats = ps)) else extractBindings(others.head) map (x => replaceAt(ps.size, x)) @@ -684,8 +695,14 @@ trait ParallelMatching extends ast.TreeDSL class ExpandedMatrix(val rows: List[Row], val targets: List[FinalState]) { require(rows.size == targets.size) - override def toString() = - "ExpandedMatrix(%d)".format(rows.size) + pp(rows zip targets, true) + override def toString() = { + def rprint(r: Row) = "Row %d: %d pats, %d bound".format(r.bx, r.pats.size, r.subst.get().size) + def tprint(t: FinalState) = "%s (free = %s)".format(t.body, pp(t.freeVars)) + val xs = rows zip targets map { case (r,t) => rprint(r) -> tprint(t) } + val ppstr = pp(xs, newlines = true) + + "ExpandedMatrix(%d rows)".format(rows.size) + ppstr + } } abstract class State { diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala index 75b13c2d32..895bb7a4f3 100644 --- a/src/compiler/scala/tools/nsc/matching/Patterns.scala +++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala @@ -23,7 +23,8 @@ trait Patterns extends ast.TreeDSL { import Debug._ import treeInfo.{ unbind, isVarPattern } - type PatternMatch = MatchMatrix#PatternMatch + type PatternMatch = MatchMatrix#PatternMatch + private type PatternVar = MatrixContext#PatternVar // Fresh patterns def emptyPatterns(i: Int): List[Pattern] = List.fill(i)(NoPattern) @@ -58,8 +59,8 @@ trait Patterns extends ast.TreeDSL { override def subpatternsForVars: List[Pattern] = List(Pattern(expr)) override def irrefutableFor(tpe: Type) = tpe <:< tree.tpe - override def simplify(testVar: Symbol) = Pattern(expr) match { - case ExtractorPattern(ua) if testVar.tpe <:< tpt.tpe => this rebindTo expr + override def simplify(pv: PatternVar) = Pattern(expr) match { + case ExtractorPattern(ua) if pv.sym.tpe <:< tpt.tpe => this rebindTo expr case _ => this } override def toString() = "%s: %s".format(Pattern(expr), tpt) @@ -80,7 +81,7 @@ trait Patterns extends ast.TreeDSL { val ident @ Ident(name) = fn override def typeToMatch = Pattern(ident).equalsCheck - override def simplify(testVar: Symbol) = this.rebindToObjectCheck() + override def simplify(pv: PatternVar) = this.rebindToObjectCheck() override def toString() = "Id(%s)".format(name) } // 8.1.4 (b) @@ -88,7 +89,7 @@ trait Patterns extends ast.TreeDSL { val Apply(select: Select, _) = tree override def typeToMatch = mkSingletonFromQualifier - override def simplify(testVar: Symbol) = this.rebindToObjectCheck() + override def simplify(pv: PatternVar) = this.rebindToObjectCheck() override def toString() = "SelectApply(%s)".format(name) } // 8.1.4 (c) @@ -101,7 +102,7 @@ trait Patterns extends ast.TreeDSL { require(!fn.isType && isModule) override def typeToMatch = tpe.narrow - override def simplify(testVar: Symbol) = this.rebindToObjectCheck() + override def simplify(pv: PatternVar) = this.rebindToObjectCheck() override def toString() = "Object(%s)".format(fn) } // 8.1.4 (e) @@ -114,10 +115,10 @@ trait Patterns extends ast.TreeDSL { require(fn.isType && this.isCaseClass) override def subpatterns(pm: MatchMatrix#PatternMatch) = - if (pm.isCaseHead) args map Pattern.apply + if (pm.head.isCaseClass) args map Pattern.apply else super.subpatterns(pm) - override def simplify(testVar: Symbol) = + override def simplify(pv: PatternVar) = if (args.isEmpty) this rebindToEmpty tree.tpe else this @@ -141,8 +142,8 @@ trait Patterns extends ast.TreeDSL { override def typeToMatch = arg.tpe // can fix #1697 here? - override def simplify(testVar: Symbol) = - if (testVar.tpe <:< arg.tpe) this + override def simplify(pv: PatternVar) = + if (pv.sym.tpe <:< arg.tpe) this else this rebindTo uaTyped override def toString() = "Unapply(f: %s => %s)".format(typeToMatch, fn.tpe.resultType) @@ -175,8 +176,8 @@ trait Patterns extends ast.TreeDSL { } // @pre: is not right-ignoring (no star pattern) ; no exhaustivity check - override def simplify(testVar: Symbol) = { - testVar setFlag Flags.TRANS_FLAG + override def simplify(pv: PatternVar) = { + pv.sym setFlag Flags.TRANS_FLAG this rebindTo elems.foldRight(gen.mkNil)(listFolder) } override def toString() = "UnapplySeq(%s)".format(elems) @@ -195,6 +196,8 @@ trait Patterns extends ast.TreeDSL { def nonStarLength = nonStarPatterns.length def isAllDefaults = nonStarPatterns forall (_.isDefault) + override def dummies = emptyPatterns(elemPatterns.length + 1) + def rebindStar(seqType: Type): List[Pattern] = { require(hasStar) nonStarPatterns ::: List(lastPattern rebindTo WILD(seqType)) @@ -399,13 +402,9 @@ trait Patterns extends ast.TreeDSL { sealed trait NamePattern extends Pattern { def name: Name override def typeToMatch = tpe.narrow - override def simplify(testVar: Symbol) = this.rebindToEqualsCheck() + override def simplify(pv: PatternVar) = this.rebindToEqualsCheck() } - // trait SimplePattern extends Pattern { - // def simplify(testVar: Symbol): Pattern = this - // } - sealed trait UnapplyPattern extends Pattern { lazy val UnApply(unfn, args) = tree override def subpatternsForVars: List[Pattern] = toPats(args) @@ -422,6 +421,10 @@ trait Patterns extends ast.TreeDSL { protected lazy val Apply(fn, args) = tree override def subpatternsForVars: List[Pattern] = toPats(args) + override def dummies = + if (!this.isCaseClass) Nil + else emptyPatterns(typeToMatch.typeSymbol.caseFieldAccessors.size) + def isConstructorPattern = fn.isType } @@ -429,8 +432,11 @@ trait Patterns extends ast.TreeDSL { val tree: Tree // returns either a simplification of this pattern or identity. - def simplify(testVar: Symbol): Pattern = this - def simplify(): Pattern = this simplify NoSymbol + def simplify(pv: PatternVar): Pattern = this + def simplify(): Pattern = this simplify null + + // the right number of dummies for this pattern + def dummies: List[Pattern] = Nil // given this scrutinee, what if any condition must be satisfied before // we even try to match? @@ -478,8 +484,6 @@ trait Patterns extends ast.TreeDSL { else tpe.narrow ) - final def isAlternative = cond(tree) { case Alternative(_) => true } - /** Standard methods **/ def copy(tree: Tree = this.tree): Pattern = if (boundTree eq tree) Pattern(tree) -- cgit v1.2.3