diff options
author | Grzegorz Kossakowski <grzegorz.kossakowski@gmail.com> | 2012-02-01 17:26:11 +0100 |
---|---|---|
committer | Grzegorz Kossakowski <grzegorz.kossakowski@gmail.com> | 2012-02-01 17:26:11 +0100 |
commit | 39457f6c85fc9764d714d52317edcd4300fd82b8 (patch) | |
tree | 4813f1ee5585e0d8c1c3e9984cad0a7798e54d71 | |
parent | aa7759651d25ab8c315a2d36e3f28cf3caaa041f (diff) | |
download | scala-39457f6c85fc9764d714d52317edcd4300fd82b8.tar.gz scala-39457f6c85fc9764d714d52317edcd4300fd82b8.tar.bz2 scala-39457f6c85fc9764d714d52317edcd4300fd82b8.zip |
Convert values to Int in switchable patterns.
Further improvements to how -Yvirtpatmat
handles switch-like patterns that can be
translated to switch tables.
First of all, we added a check whether
a type of an expression we pattern match
on is in the set of allowed types for
switch patterns.
If yes, we translate a pattern to switch
one by converting both an expression we
pattern match on and literals in a pattern
to an Int.
I borrowed an idea of converting to Ints
from both old pattern matcher implementation
and from how javac handles it.
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala | 62 |
1 files changed, 41 insertions, 21 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index cf5985eeee..b1e02cb062 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -1128,10 +1128,22 @@ defined class Foo */ // } // } + private val switchableTpes = Set(ByteClass.tpe, ShortClass.tpe, IntClass.tpe, CharClass.tpe) + 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) + def isSwitchableTpe(tpe: Type): Boolean = + switchableTpes contains tpe + def switchableConstToInt(x: Tree): Tree = { + val Literal(const) = x + const.tag match { + case IntTag => x + case ByteTag | ShortTag | CharTag => Literal(Constant(const.intValue)) + } + } + 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) @@ -1139,12 +1151,12 @@ defined class Foo */ Some(CaseDef(Ident(nme.WILDCARD), EmptyTree, btm.substitution(body))) // constant case (EqualityTestTreeMaker(_, const@SwitchablePattern(), _)) :: (btm@BodyTreeMaker(body, _)) :: Nil => - Some(CaseDef(const, EmptyTree, btm.substitution(body))) + Some(CaseDef(switchableConstToInt(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) + Some(switchableConstToInt(const)) case _ => None } @@ -1158,27 +1170,35 @@ defined class Foo */ } } - sequence(caseDefs) map { caseDefs => - import CODE._ - val caseDefsWithDefault = { - def isDefault(x: CaseDef): Boolean = x match { - case CaseDef(Ident(nme.WILDCARD), EmptyTree, _) => true - case _ => false - } - val hasDefault = caseDefs exists isDefault - if (hasDefault) caseDefs else { - val default = atPos(scrut.pos) { DEFAULT ==> MATCHERROR(REF(scrutSym)) } - caseDefs :+ default + if (!isSwitchableTpe(scrut.tpe)) + None + else { + sequence(caseDefs) map { caseDefs => + import CODE._ + val caseDefsWithDefault = { + def isDefault(x: CaseDef): Boolean = x match { + case CaseDef(Ident(nme.WILDCARD), EmptyTree, _) => true + case _ => false + } + val hasDefault = caseDefs exists isDefault + if (hasDefault) caseDefs else { + val default = atPos(scrut.pos) { DEFAULT ==> MATCHERROR(REF(scrutSym)) } + caseDefs :+ default + } } + val matcher = BLOCK( + if (scrut.tpe != IntClass.tpe) { + scrutSym setInfo IntClass.tpe + VAL(scrutSym) === (scrut DOT nme.toInt) + } else { + VAL(scrutSym) === scrut + }, + Match(REF(scrutSym), caseDefsWithDefault) // match on scrutSym, not scrut to avoid duplicating scrut + ) + // matcher filter (tree => tree.tpe == null) foreach println + // treeBrowser browse matcher + matcher // set type to avoid recursion in typedMatch } - val matcher = BLOCK( - VAL(scrutSym) === scrut, // TODO: type test for switchable type if patterns allow switch but the scrutinee doesn't - Match(REF(scrutSym), caseDefsWithDefault) // match on scrutSym, not scrut to avoid duplicating scrut - ) - - // matcher filter (tree => tree.tpe == null) foreach println - // treeBrowser browse matcher - matcher // set type to avoid recursion in typedMatch } } |