From 5da8a164cdd276e191ab6429e5a64e02529bbe45 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Thu, 27 May 2010 02:53:02 +0000 Subject: Reversion of r21940, which caused a big bump in... Reversion of r21940, which caused a big bump in quick.comp compilation time. Another glorious day in the land of the pattern matcher. No review. --- .../tools/nsc/matching/ParallelMatching.scala | 107 +++++++++++++-------- 1 file changed, 67 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index f33f637a46..3438c77e44 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -170,7 +170,10 @@ trait ParallelMatching extends ast.TreeDSL def tail = ps.tail def size = ps.length - def dummies = head.dummies + def headType = head.tpe + def isCaseHead = head.isCaseClass + private val dummyCount = if (isCaseHead) headType.typeSymbol.caseFieldAccessors.length else 0 + def dummies = emptyPatterns(dummyCount) def apply(i: Int): Pattern = ps(i) def pzip() = ps.zipWithIndex @@ -198,7 +201,7 @@ trait ParallelMatching extends ast.TreeDSL tracing("Rule", head match { case x if isEquals(x.tree.tpe) => new MixEquals(this, rest) case x: SequencePattern => new MixSequence(this, rest, x) - case AnyUnapply(false) => new MixUnapply(this, rest) + case AnyUnapply(false) => new MixUnapply(this, rest, false) case _ => isPatternSwitch(scrut, ps) match { case Some(x) => new MixLiteralInts(x, rest) @@ -354,7 +357,7 @@ trait ParallelMatching extends ast.TreeDSL /** mixture rule for unapply pattern */ - class MixUnapply(val pmatch: PatternMatch, val rest: Rep) extends RuleApplication { + class MixUnapply(val pmatch: PatternMatch, val rest: Rep, typeTest: Boolean) extends RuleApplication { val uapattern = head match { case x: UnapplyPattern => x ; case _ => abort("XXX") } val ua @ UnApply(app, args) = head.tree @@ -563,38 +566,53 @@ trait ParallelMatching extends ast.TreeDSL * remaining: remaining, rows index and pattern */ class MixTypes(val pmatch: PatternMatch, val rest: Rep) extends RuleApplication { - val succRows = new ListBuffer[(Int, List[Pattern])] - val failRows = new ListBuffer[(Int, Pattern)] - - for ((pattern, j) <- pmatch.pzip()) { - def isMoreSpecific = matches(pattern.tpe, head.tpe) - def isLessSpecific = matches(head.tpe, pattern.tpe) - def isEquivalent = head.tpe =:= pattern.tpe - def isObjectTest = pattern.isObject && (head.tpe =:= pattern.tpe) - - def whichSubs = if (head.isCaseClass) (pattern expandToArity head.arity) else Nil - - def ifElsePattern(yes: Pattern) = if (isEquivalent) yes else pattern - - def succDummy = succRows += ((j, NoPattern :: pmatch.dummies)) - def succTyped(pp: Pattern) = succRows += ((j, ifElsePattern(pp) :: pmatch.dummies)) - def succSubs = succRows += ((j, ifElsePattern(NoPattern) :: whichSubs)) - def failOnly = failRows += ((j, pattern)) - - pattern match { - case Pattern(LIT(null), _) if !isEquivalent => failOnly - case x if isObjectTest => succDummy - // Note: bugs 1697/2337/etc have their origins right here because they - // have a type test which when passed doesn't guarantee a match: the - // unapply can still fail. - case Pattern(Typed(pp, _), _) if isMoreSpecific => succTyped(Pattern(pp)) - case Pattern(UnApply(_, _), _) => failOnly - case x if !x.isDefault && isMoreSpecific => succSubs - case x if x.isDefault || isLessSpecific => succDummy ; failOnly - case _ => failOnly + case class Yes(bx: Int, moreSpecific: Pattern, subsumed: List[Pattern]) + case class No(bx: Int, remaining: Pattern) + + val (yeses, noes) = { + val _ys = new ListBuffer[Yes] + val _ns = new ListBuffer[No] + + for ((pattern, j) <- pmatch.pzip()) { + // scrutinee, head of pattern group + val (s, p) = (pattern.tpe, head.tpe) + + def isEquivalent = head.tpe =:= pattern.tpe + def isObjectTest = pattern.isObject && (p =:= pattern.tpe) + + def sMatchesP = matches(s, p) + def pMatchesS = matches(p, s) + + def ifEquiv(yes: Pattern): Pattern = if (isEquivalent) yes else pattern + + def passl(p: Pattern = NoPattern, ps: List[Pattern] = pmatch.dummies) = Some(Yes(j, p, ps)) + def passr() = Some( No(j, pattern)) + + def typed(pp: Tree) = passl(ifEquiv(Pattern(pp))) + def subs() = passl(ifEquiv(NoPattern), pattern expandToArity head.arity) + + val (oneY, oneN) = pattern match { + case Pattern(LIT(null), _) if !(p =:= s) => (None, passr) // (1) + case x if isObjectTest => (passl(), None) // (2) + case Pattern(Typed(pp, _), _) if sMatchesP => (typed(pp), None) // (4) + // The next line used to be this which "fixed" 1697 but introduced + // numerous regressions including #3136. + // case Pattern(_: UnApply, _) => (passl(), passr) + case Pattern(_: UnApply, _) => (None, passr) + case x if !x.isDefault && sMatchesP => (subs(), None) + case x if x.isDefault || pMatchesS => (passl(), passr) + case _ => (None, passr) + } + oneY map (_ys +=) + oneN map (_ns +=) } + (_ys.toList, _ns.toList) } + val moreSpecific = yeses map (_.moreSpecific) + val subsumed = yeses map (x => (x.bx, x.subsumed)) + val remaining = noes map (x => (x.bx, x.remaining)) + // temporary checks so we're less crashy while we determine what to implement. def checkErroneous(scrut: Scrutinee): Type = { scrut.tpe match { @@ -605,20 +623,29 @@ trait ParallelMatching extends ast.TreeDSL } } - lazy val casted = scrut castedTo head.tpe + private def mkZipped = + for (Yes(j, moreSpecific, subsumed) <- yeses) yield + j -> (moreSpecific :: subsumed) + + lazy val casted = scrut castedTo pmatch.headType lazy val cond = condition(checkErroneous(casted), scrut, head.boundVariables.nonEmpty) - lazy val success = { - val newRows = - for ((j, ps) <- succRows.toList) yield - (rest rows j).insert2(ps, pmatch(j).boundVariables, casted.sym) + private def isAnyMoreSpecific = yeses exists (x => !x.moreSpecific.isEmpty) + lazy val (subtests, subtestVars) = + if (isAnyMoreSpecific) (mkZipped, List(casted.pv)) + else (subsumed, Nil) - val newRoots = casted.pv :: casted.accessorPatternVars - val srep = remake(newRows, newRoots, false) + lazy val newRows = + for ((j, ps) <- subtests) yield + (rest rows j).insert2(ps, pmatch(j).boundVariables, casted.sym) + + lazy val success = { + val srep = remake(newRows, subtestVars ::: casted.accessorPatternVars, includeScrut = false) squeezedBlock(casted.allValDefs, srep.toTree) } - lazy val failure = mkFail(failRows.toList map { case (p1, p2) => rest rows p1 insert p2 }) + lazy val failure = + mkFail(remaining map { case (p1, p2) => rest rows p1 insert p2 }) final def tree(): Tree = codegen } -- cgit v1.2.3