summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala
diff options
context:
space:
mode:
authorGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2012-01-23 21:32:19 +0100
committerGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2012-01-24 02:16:42 +0100
commit963ab412ce2e404a92d89a3f1f61d5f669426eb9 (patch)
treea8ea190ffdda9409a2bb624df849012350edc23b /src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala
parent5cbd7d06eb8fe81bc3812ee99de05b1f4bd820fe (diff)
downloadscala-963ab412ce2e404a92d89a3f1f61d5f669426eb9.tar.gz
scala-963ab412ce2e404a92d89a3f1f61d5f669426eb9.tar.bz2
scala-963ab412ce2e404a92d89a3f1f61d5f669426eb9.zip
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.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala68
1 files changed, 27 insertions, 41 deletions
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)