diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/TemporaryVariableElimination.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/TemporaryVariableElimination.kt index 3eee00f4c5b..ffe8a425175 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/TemporaryVariableElimination.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/TemporaryVariableElimination.kt @@ -22,6 +22,7 @@ import com.google.dart.compiler.backend.js.ast.metadata.synthetic import org.jetbrains.kotlin.js.inline.util.collectFreeVariables import org.jetbrains.kotlin.js.inline.util.collectLocalVariables import org.jetbrains.kotlin.js.translate.utils.JsAstUtils +import org.jetbrains.kotlin.js.translate.utils.splitToRanges internal class TemporaryVariableElimination(function: JsFunction) { private val root = function.body @@ -440,38 +441,28 @@ internal class TemporaryVariableElimination(function: JsFunction) { private fun cleanUp() { object : JsVisitorWithContextImpl() { override fun visit(x: JsVars, ctx: JsContext): Boolean { - x.vars.removeAll(statementsToRemove) + if (x.vars.removeAll(statementsToRemove)) { + hasChanges = true + } - var lastDroppedIndex = 0 - for ((index, v) in x.vars.toList().withIndex()) { - val name = v.name - if (name in variablesToRemove) { - hasChanges = true - if (index > lastDroppedIndex) { - val droppedVars = JsVars(*x.vars.subList(lastDroppedIndex, index).toTypedArray()) - droppedVars.synthetic = x.synthetic - ctx.addPrevious(droppedVars) + val ranges = x.vars.splitToRanges { it.name in variablesToRemove } + if (ranges.size == 1 && !ranges[0].second) return super.visit(x, ctx) + + hasChanges = true + for ((subList, isRemoved) in ranges) { + val initializers = subList.mapNotNull { it.initExpression } + initializers.forEach { accept(it) } + if (isRemoved) { + for (initializer in initializers) { + ctx.addPrevious(JsExpressionStatement(initializer).apply { synthetic = x.synthetic }) } - val initExpression = v.initExpression - if (initExpression != null) { - ctx.addPrevious(JsExpressionStatement(initExpression).run { - synthetic = true - accept(this) - }) - } - lastDroppedIndex = index + 1 + } + else { + ctx.addPrevious(JsVars(*subList.toTypedArray()).apply { synthetic = x.synthetic }) } } - if (lastDroppedIndex > 0) { - x.vars.subList(0, lastDroppedIndex).clear() - } - - if (x.vars.isEmpty()) { - ctx.removeMe() - hasChanges = true - return false - } - return super.visit(x, ctx) + ctx.removeMe() + return false } override fun visit(x: JsExpressionStatement, ctx: JsContext): Boolean { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt index e42ddf1ac45..c3c642c7eb1 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.js.translate.utils import com.google.dart.compiler.backend.js.ast.* +import com.google.dart.compiler.backend.js.ast.metadata.synthetic import com.intellij.util.SmartList import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.js.translate.context.Namer @@ -55,3 +56,23 @@ fun generateDelegateCall( functionObject.parameters.addAll(parameters) return JsPropertyInitializer(delegateMemberFunctionName.makeRef(), functionObject) } + +fun List.splitToRanges(classifier: (T) -> S): List, S>> { + if (isEmpty()) return emptyList() + + var lastIndex = 0 + var lastClass: S = classifier(this[0]) + val result = mutableListOf, S>>() + + for ((index, e) in asSequence().withIndex().drop(1)) { + val cls = classifier(e) + if (cls != lastClass) { + result += Pair(subList(lastIndex, index), lastClass) + lastClass = cls + lastIndex = index + } + } + + result += Pair(subList(lastIndex, size), lastClass) + return result +}