Skip to content

Commit 6db9976

Browse files
committed
For switch-Matches in PatMap, convert scrutinee and alternatives to Int.
In JVM bytecode as well in Scala.js IR, switches only work with primitive ints. Therefore, it makes more sense to convert the scrutinee and alternatives of switch-Matches to Ints early. This is also what scalac does. See `RegularSwitchMaker` in `patmat/MatchOptimization.scala`. The JVM back-end tolerates non-ints due its aggressive and blind adaptations everywhere (not because of a deliberate action to support non-Ints). However, the Scala.js back-end does not like receiving non-Ints in `Match`es, because it is much more conservative in where it inserts adaptations (i.e., almost nowhere).
1 parent d6d374a commit 6db9976

File tree

1 file changed

+23
-9
lines changed

1 file changed

+23
-9
lines changed

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -821,17 +821,31 @@ object PatternMatcher {
821821
}
822822
}
823823

824-
/** Emit cases of a switch */
825-
private def emitSwitchCases(cases: List[(List[Tree], Plan)]): List[CaseDef] = (cases: @unchecked) match {
826-
case (alts, ons) :: cases1 =>
824+
/** Emit a switch-match */
825+
private def emitSwitchMatch(scrutinee: Tree, cases: List[(List[Tree], Plan)]): Match = {
826+
/* Make sure to adapt the scrutinee to Int, as well as all the alternatives
827+
* of all cases, so that only Matches on pritimive Ints survive this phase.
828+
*/
829+
830+
val intScrutinee =
831+
if (scrutinee.tpe.widen.isRef(defn.IntClass)) scrutinee
832+
else scrutinee.select(nme.toInt)
833+
834+
def intLiteral(lit: Tree): Tree =
835+
val Literal(constant) = lit
836+
if (constant.tag == Constants.IntTag) lit
837+
else cpy.Literal(lit)(Constant(constant.intValue))
838+
839+
val caseDefs = cases.map { (alts, ons) =>
827840
val pat = alts match {
828-
case alt :: Nil => alt
841+
case alt :: Nil => intLiteral(alt)
829842
case Nil => Underscore(defn.IntType) // default case
830-
case _ => Alternative(alts)
843+
case _ => Alternative(alts.map(intLiteral))
831844
}
832-
CaseDef(pat, EmptyTree, emit(ons)) :: emitSwitchCases(cases1)
833-
case nil =>
834-
Nil
845+
CaseDef(pat, EmptyTree, emit(ons))
846+
}
847+
848+
Match(intScrutinee, caseDefs)
835849
}
836850

837851
/** If selfCheck is `true`, used to check whether a tree gets generated twice */
@@ -892,7 +906,7 @@ object PatternMatcher {
892906
def maybeEmitSwitch(scrutinee: Tree): Tree = {
893907
val switchCases = collectSwitchCases(scrutinee, plan)
894908
if (hasEnoughSwitchCases(switchCases, MinSwitchCases)) // at least 3 cases + default
895-
Match(scrutinee, emitSwitchCases(switchCases))
909+
emitSwitchMatch(scrutinee, switchCases)
896910
else
897911
default
898912
}

0 commit comments

Comments
 (0)