summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2012-02-01 17:26:11 +0100
committerGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2012-02-01 17:26:11 +0100
commit39457f6c85fc9764d714d52317edcd4300fd82b8 (patch)
tree4813f1ee5585e0d8c1c3e9984cad0a7798e54d71
parentaa7759651d25ab8c315a2d36e3f28cf3caaa041f (diff)
downloadscala-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.scala62
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
}
}