From 400a15e3d6c23d78e023c087e32929580290dd98 Mon Sep 17 00:00:00 2001 From: Ilya Goncharov Date: Mon, 19 Oct 2020 21:34:34 +0300 Subject: [PATCH] Add lowering on switch in loop ^KT-42262 fixed --- .../kotlin/ir/backend/js/JsLoweringPhases.kt | 7 +++ .../lower/LoopWithBreakingSwitchLowering.kt | 51 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/LoopWithBreakingSwitchLowering.kt 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 96b5ac3c756..9bcb61face0 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,6 +341,12 @@ 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", @@ -712,6 +718,7 @@ 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 new file mode 100644 index 00000000000..c8755efb51a --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/LoopWithBreakingSwitchLowering.kt @@ -0,0 +1,51 @@ +/* + * 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++}" +}