From 963ab412ce2e404a92d89a3f1f61d5f669426eb9 Mon Sep 17 00:00:00 2001 From: Grzegorz Kossakowski Date: Mon, 23 Jan 2012 21:32:19 +0100 Subject: Simplified emitSwitch in PatMatVirtualiser. Simplified emitSwitch method that does not emit forward jumps for switch tables. Instead, it emits Match trees that are of a shape that can be directly translated to switch. The backend takes care of the actual translation from Match trees into switch tables. As a bonus, we emit more compact trees compared to the old implementation of emitSwitch. Review by @adriaanm. --- .../tools/nsc/typechecker/PatMatVirtualiser.scala | 68 +++++++++------------- 1 file changed, 27 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index 4104803194..ed185c27d6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -1128,62 +1128,48 @@ defined class Foo */ // } // } - def emitSwitch(scrut: Tree, scrutSym: Symbol, cases: List[List[TreeMaker]], pt: Type): Option[Tree] = if (optimizingCodeGen) { - def unfold(tms: List[TreeMaker], currLabel: Option[Symbol] = None, nextLabel: Option[Symbol] = None): List[CaseDef] = tms match { - // constant - case (EqualityTestTreeMaker(_, const@SwitchablePattern(), _)) :: (btm@BodyTreeMaker(body, _)) :: Nil => import CODE._ - @inline - def substedBody = btm.substitution(body) - val labelledBody = currLabel match { - case None => substedBody // currLabel.isEmpty implies nextLabel.isEmpty - case Some(myLabel) => - LabelDef(myLabel, Nil, - nextLabel match { - case None => substedBody - case Some(next) => ID(next) APPLY () - } - ) - } - List(CaseDef(const, EmptyTree, labelledBody)) - - // alternatives - case AlternativesTreeMaker(_, altss, _) :: bodyTm :: Nil => // assert(currLabel.isEmpty && nextLabel.isEmpty) - val labels = altss map { alts => - Some(freshSym(NoPosition, MethodType(Nil, pt), "$alt$") setFlag (METHOD | LABEL)) - } - - val caseDefs = (altss, labels, labels.tail :+ None).zipped.map { case (alts, currLabel, nextLabel) => - unfold(alts :+ bodyTm, currLabel, nextLabel) - } - - if (caseDefs exists (_.isEmpty)) Nil - else caseDefs.flatten - - case _ => Nil // failure - } + def emitSwitch(scrut: Tree, scrutSym: Symbol, cases: List[List[TreeMaker]], pt: Type): Option[Tree] = if (!optimizingCodeGen) None else { + def sequence[T](xs: List[Option[T]]): Option[List[T]] = + if (xs exists (_.isEmpty)) None else Some(xs.flatten) val caseDefs = cases map { makers => removeSubstOnly(makers) match { // default case (don't move this to unfold, as it may only occur on the top level, not as an alternative -- well, except in degenerate matches) case (btm@BodyTreeMaker(body, _)) :: Nil => - List(CaseDef(Ident(nme.WILDCARD), EmptyTree, btm.substitution(body))) - case nonTrivialMakers => - unfold(nonTrivialMakers) + Some(CaseDef(Ident(nme.WILDCARD), EmptyTree, btm.substitution(body))) + // constant + case (EqualityTestTreeMaker(_, const@SwitchablePattern(), _)) :: (btm@BodyTreeMaker(body, _)) :: Nil => import CODE._ + Some(CaseDef(const, EmptyTree, btm.substitution(body))) + // alternatives + case AlternativesTreeMaker(_, altss, _) :: (btm@BodyTreeMaker(body, _)) :: Nil => // assert(currLabel.isEmpty && nextLabel.isEmpty) + val caseConstants = altss map { + case EqualityTestTreeMaker(_, const@SwitchablePattern(), _) :: Nil => + Some(const) + case _ => + None + } + + sequence(caseConstants) map { contants => + val substedBody = btm.substitution(body) + CaseDef(Alternative(contants), EmptyTree, substedBody) + } + case _ => + None //failure (can't translate pattern to a switch) } } - if (caseDefs exists (_.isEmpty)) None - else { import CODE._ + sequence(caseDefs) map { caseDefs => + import CODE._ val matcher = BLOCK( VAL(scrutSym) === scrut, // TODO: type test for switchable type if patterns allow switch but the scrutinee doesn't - Match(REF(scrutSym), caseDefs.flatten) // match on scrutSym, not scrut to avoid duplicating scrut + Match(REF(scrutSym), caseDefs) // match on scrutSym, not scrut to avoid duplicating scrut ) // matcher filter (tree => tree.tpe == null) foreach println // treeBrowser browse matcher - Some(matcher) // set type to avoid recursion in typedMatch + matcher // set type to avoid recursion in typedMatch } - } else None + } def optimizeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type): List[List[TreeMaker]] = doCSE(prevBinder, doDCE(prevBinder, cases, pt), pt) -- cgit v1.2.3