diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt index 9bcb61face0..96b5ac3c756 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt @@ -341,12 +341,6 @@ private val rangeContainsLoweringPhase = makeBodyLoweringPhase( description = "[Optimization] Optimizes calls to contains() for ClosedRanges" ) -private val loopWithBreakingSwitchLowering = makeBodyLoweringPhase( - { LoopWithBreakingSwitchLowering() }, - name = "LoopWithBreakingSwitchLowering", - description = "Transform statement-like-expression nodes into pure-statement to make it easily transform into JS", -) - private val forLoopsLoweringPhase = makeBodyLoweringPhase( ::ForLoopsLowering, name = "ForLoopsLowering", @@ -718,7 +712,6 @@ val loweringList = listOf( interopCallableReferenceLoweringPhase, returnableBlockLoweringPhase, rangeContainsLoweringPhase, - loopWithBreakingSwitchLowering, forLoopsLoweringPhase, primitiveCompanionLoweringPhase, propertyAccessorInlinerLoweringPhase, diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/LoopWithBreakingSwitchLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/LoopWithBreakingSwitchLowering.kt deleted file mode 100644 index c8755efb51a..00000000000 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/LoopWithBreakingSwitchLowering.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.ir.backend.js.lower - -import org.jetbrains.kotlin.backend.common.BodyLoweringPass -import org.jetbrains.kotlin.ir.declarations.IrDeclaration -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.expressions.IrBody -import org.jetbrains.kotlin.ir.expressions.IrBreak -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.IrLoop -import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid -import java.util.* - -class LoopWithBreakingSwitchLowering : BodyLoweringPass { - - private val switchInLoopTransformer = LoopWithBreakingSwitchTransformer() - - override fun lower(irBody: IrBody, container: IrDeclaration) { - when (container) { - is IrFunction -> { - container.accept(switchInLoopTransformer, null) - } - } - } -} - -class LoopWithBreakingSwitchTransformer : IrElementTransformerVoid() { - private var counter: Int = 0 - - private val loopDeque: Deque = LinkedList() - - override fun visitBreak(jump: IrBreak): IrExpression { - val loop = loopDeque.firstOrNull() - loop?.label = loop?.label ?: makeLoopLabel() - - return super.visitBreak(jump) - } - - override fun visitLoop(loop: IrLoop): IrExpression { - loopDeque.push(loop) - return super.visitLoop(loop).apply { - loopDeque.pop() - } - } - - private fun makeLoopLabel() = "\$l\$switch\$${counter++}" -} diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt index ce602f659b9..f738f74e656 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt @@ -11,7 +11,10 @@ import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrBreak +import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrLoop +import org.jetbrains.kotlin.ir.expressions.IrWhen import org.jetbrains.kotlin.ir.types.isUnit import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid @@ -21,6 +24,7 @@ import org.jetbrains.kotlin.js.naming.isES5IdentifierPart import org.jetbrains.kotlin.js.naming.isES5IdentifierStart import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty +import java.util.* fun mapToKey(declaration: T): String { return with(JsManglerIr) { @@ -357,6 +361,8 @@ class NameTables( inner class LocalNameGenerator(parentDeclaration: IrDeclaration) : IrElementVisitorVoid { val table = NameTable(globalNames) + private val breakableDeque: Deque = LinkedList() + init { localNames[parentDeclaration] = table } @@ -373,21 +379,45 @@ class NameTables( super.visitDeclaration(declaration) } - override fun visitLoop(loop: IrLoop) { - val label = loop.label - if (label != null) { - localLoopNames.declareFreshName(loop, label) - loopNames[loop] = localLoopNames.names[loop]!! + override fun visitBreak(jump: IrBreak) { + val loop = jump.loop + if (loop != breakableDeque.firstOrNull()) { + persistLoopName(SYNTHETIC_LOOP_LABEL, loop) } + + super.visitBreak(jump) + } + + override fun visitWhen(expression: IrWhen) { + breakableDeque.push(expression) + + super.visitWhen(expression) + + breakableDeque.pop() + } + + override fun visitLoop(loop: IrLoop) { + breakableDeque.push(loop) + super.visitLoop(loop) + + breakableDeque.pop() + + val label = loop.label + + if (label != null) { + persistLoopName(label, loop) + } + } + + private fun persistLoopName(label: String, loop: IrLoop) { + localLoopNames.declareFreshName(loop, label) + loopNames[loop] = localLoopNames.names[loop]!! } } fun getNameForLoop(loop: IrLoop): String? = - if (loop.label == null) - null - else - loopNames[loop]!! + loopNames[loop] } @@ -397,3 +427,5 @@ fun sanitizeName(name: String): String { val first = name.first().let { if (it.isES5IdentifierStart()) it else '_' } return first.toString() + name.drop(1).map { if (it.isES5IdentifierPart()) it else '_' }.joinToString("") } + +private const val SYNTHETIC_LOOP_LABEL = "\$l\$break"