[JS IR] Fix switch transformer in case of if as an expr

- Fix KT-43374
This commit is contained in:
Roman Artemev
2021-09-24 13:53:46 +07:00
parent 9123d426c3
commit 4073f177b4
2 changed files with 25 additions and 13 deletions
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
import org.jetbrains.kotlin.ir.types.isAny import org.jetbrains.kotlin.ir.types.isAny
import org.jetbrains.kotlin.ir.util.constructedClassType import org.jetbrains.kotlin.ir.util.constructedClassType
import org.jetbrains.kotlin.ir.util.file import org.jetbrains.kotlin.ir.util.file
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.*
@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
@@ -64,8 +65,11 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
private fun IrExpression.maybeOptimizeIntoSwitch(context: JsGenerationContext, transformer: (JsExpression) -> JsStatement): JsStatement { private fun IrExpression.maybeOptimizeIntoSwitch(context: JsGenerationContext, transformer: (JsExpression) -> JsStatement): JsStatement {
if (this is IrWhen) { if (this is IrWhen) {
val stmtTransformer = { stmt: JsStatement -> transformer((stmt as JsExpressionStatement).expression) } val stmtTransformer = { stmt: JsStatement ->
SwitchOptimizer(context, stmtTransformer).tryOptimize(this)?.let { return it } assert(stmt is JsExpressionStatement) { "${render()} is not a statement $stmt" }
transformer((stmt as JsExpressionStatement).expression)
}
SwitchOptimizer(context, isExpression = true, stmtTransformer).tryOptimize(this)?.let { return it }
} }
return transformer(accept(IrElementToJsExpressionTransformer(), context)) return transformer(accept(IrElementToJsExpressionTransformer(), context))
@@ -112,7 +116,7 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
JsBinaryOperation(JsBinaryOperator.ASG, varRef, expr).makeStmt() JsBinaryOperation(JsBinaryOperator.ASG, varRef, expr).makeStmt()
} }
SwitchOptimizer(context, transformer).tryOptimize(value)?.let { SwitchOptimizer(context, isExpression = true, transformer).tryOptimize(value)?.let {
return JsBlock(JsVars(JsVars.JsVar(varName)), it).withSource(declaration, context) return JsBlock(JsVars(JsVars.JsVar(varName)), it).withSource(declaration, context)
} }
} }
@@ -11,10 +11,10 @@ import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.*
class SwitchOptimizer(private val context: JsGenerationContext, private val lastStatementTransformer: (JsStatement) -> JsStatement) { class SwitchOptimizer(private val context: JsGenerationContext, private val isExpression: Boolean, private val lastStatementTransformer: (JsStatement) -> JsStatement) {
// TODO: reimplement optimization on top of IR // TODO: reimplement optimization on top of IR
constructor(context: JsGenerationContext) : this(context, { it }) constructor(context: JsGenerationContext) : this(context, isExpression = false, { it })
private val jsEqeqeq = context.staticContext.backendContext.intrinsics.jsEqeqeq private val jsEqeqeq = context.staticContext.backendContext.intrinsics.jsEqeqeq
private val jsEqeq = context.staticContext.backendContext.intrinsics.jsEqeq private val jsEqeq = context.staticContext.backendContext.intrinsics.jsEqeq
@@ -144,19 +144,27 @@ class SwitchOptimizer(private val context: JsGenerationContext, private val last
JsDefault().also { jsCases += it } JsDefault().also { jsCases += it }
} }
val jsBody = case.body.accept(stmtTransformer, context).asBlock() val lastStatement = if (isExpression) {
var lastStatement = jsBody.statements.lastOrNull() val expression = case.body.accept(exprTransformer, context).makeStmt()
val lastStatement = lastStatementTransformer(expression)
jsCase.statements += lastStatement
lastStatement
} else {
val jsBody = case.body.accept(stmtTransformer, context).asBlock()
var lastStatement = jsBody.statements.lastOrNull()
if (lastStatement != null) { if (lastStatement != null) {
lastStatement = lastStatementTransformer(lastStatement) lastStatement = lastStatementTransformer(lastStatement)
jsBody.statements[jsBody.statements.lastIndex] = lastStatement jsBody.statements[jsBody.statements.lastIndex] = lastStatement
}
jsCase.statements += jsBody.statements
lastStatement
} }
if (lastStatement !is JsBreak && lastStatement !is JsContinue && lastStatement !is JsReturn && lastStatement !is JsThrow) { if (lastStatement !is JsBreak && lastStatement !is JsContinue && lastStatement !is JsReturn && lastStatement !is JsThrow) {
jsBody.statements += JsBreak() jsCase.statements += JsBreak()
} }
jsCase.statements += jsBody.statements
} }
return JsSwitch(jsExpr, jsCases) return JsSwitch(jsExpr, jsCases)