Skip to content

Commit 1ef2fff

Browse files
committed
Scala.js: Emit Match nodes for string switches.
Forward port of scala-js/scala-js@808b054
1 parent c15c01a commit 1ef2fff

File tree

1 file changed

+17
-35
lines changed

1 file changed

+17
-35
lines changed

compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala

Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3192,7 +3192,7 @@ class JSCodeGen()(using genCtx: Context) {
31923192
case resType => resType
31933193
}
31943194

3195-
var clauses: List[(List[js.Tree], js.Tree)] = Nil
3195+
var clauses: List[(List[js.MatchableLiteral], js.Tree)] = Nil
31963196
var optDefaultClause: Option[js.Tree] = None
31973197

31983198
for (caze @ CaseDef(pat, guard, body) <- cases) {
@@ -3201,19 +3201,29 @@ class JSCodeGen()(using genCtx: Context) {
32013201

32023202
val genBody = genStatOrExpr(body, isStat)
32033203

3204+
def invalidCase(): Nothing =
3205+
abortMatch("Invalid case")
3206+
3207+
def genMatchableLiteral(tree: Literal): js.MatchableLiteral = {
3208+
genExpr(tree) match {
3209+
case matchableLiteral: js.MatchableLiteral => matchableLiteral
3210+
case otherExpr => invalidCase()
3211+
}
3212+
}
3213+
32043214
pat match {
32053215
case lit: Literal =>
3206-
clauses = (List(genExpr(lit)), genBody) :: clauses
3216+
clauses = (List(genMatchableLiteral(lit)), genBody) :: clauses
32073217
case Ident(nme.WILDCARD) =>
32083218
optDefaultClause = Some(genBody)
32093219
case Alternative(alts) =>
32103220
val genAlts = alts.map {
3211-
case lit: Literal => genExpr(lit)
3212-
case _ => abortMatch("Invalid case in alternative")
3221+
case lit: Literal => genMatchableLiteral(lit)
3222+
case _ => invalidCase()
32133223
}
32143224
clauses = (genAlts, genBody) :: clauses
32153225
case _ =>
3216-
abortMatch("Invalid case pattern")
3226+
invalidCase()
32173227
}
32183228
}
32193229

@@ -3228,10 +3238,6 @@ class JSCodeGen()(using genCtx: Context) {
32283238
* case is a typical product of `match`es that are full of
32293239
* `case n if ... =>`, which are used instead of `if` chains for
32303240
* convenience and/or readability.
3231-
*
3232-
* When no optimization applies, and any of the case values is not a
3233-
* literal int, we emit a series of `if..else` instead of a `js.Match`.
3234-
* This became necessary in 2.13.2 with strings and nulls.
32353241
*/
32363242
def isInt(tree: js.Tree): Boolean = tree.tpe == jstpe.IntType
32373243

@@ -3251,32 +3257,8 @@ class JSCodeGen()(using genCtx: Context) {
32513257
js.If(js.BinaryOp(op, genSelector, uniqueAlt), caseRhs, defaultClause)(resultType)
32523258

32533259
case _ =>
3254-
if (isInt(genSelector) &&
3255-
clauses.forall(_._1.forall(_.isInstanceOf[js.IntLiteral]))) {
3256-
// We have int literals only: use a js.Match
3257-
val intClauses = clauses.asInstanceOf[List[(List[js.IntLiteral], js.Tree)]]
3258-
js.Match(genSelector, intClauses, defaultClause)(resultType)
3259-
} else {
3260-
// We have other stuff: generate an if..else chain
3261-
val (tempSelectorDef, tempSelectorRef) = genSelector match {
3262-
case varRef: js.VarRef =>
3263-
(js.Skip(), varRef)
3264-
case _ =>
3265-
val varDef = js.VarDef(freshLocalIdent(), NoOriginalName,
3266-
genSelector.tpe, mutable = false, genSelector)
3267-
(varDef, varDef.ref)
3268-
}
3269-
val ifElseChain = clauses.foldRight(defaultClause) { (caze, elsep) =>
3270-
val conds = caze._1.map { caseValue =>
3271-
js.BinaryOp(js.BinaryOp.===, tempSelectorRef, caseValue)
3272-
}
3273-
val cond = conds.reduceRight[js.Tree] { (left, right) =>
3274-
js.If(left, js.BooleanLiteral(true), right)(jstpe.BooleanType)
3275-
}
3276-
js.If(cond, caze._2, elsep)(resultType)
3277-
}
3278-
js.Block(tempSelectorDef, ifElseChain)
3279-
}
3260+
// We have more than one case: use a js.Match
3261+
js.Match(genSelector, clauses, defaultClause)(resultType)
32803262
}
32813263
}
32823264

0 commit comments

Comments
 (0)