diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsStatementTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsStatementTransformer.kt index df48a857f6e..e3db9df5509 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsStatementTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsStatementTransformer.kt @@ -5,7 +5,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs -import org.jetbrains.kotlin.backend.common.compilationException +import org.jetbrains.kotlin.ir.backend.js.utils.isTheLastReturnStatementIn import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope @@ -94,7 +94,11 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer JsStatement = if (targetSymbol is IrReturnableBlockSymbol) { // TODO assert that value is Unit? - { JsBreak(context.getNameForReturnableBlock(targetSymbol.owner)!!.makeRef()) } + { + context.getNameForReturnableBlock(targetSymbol.owner) + .takeIf { !expression.isTheLastReturnStatementIn(targetSymbol) } + ?.run { JsBreak(makeRef()) } ?: JsEmpty + } } else { { JsReturn(it) } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrJsUtils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrJsUtils.kt index c428efec871..4c063541c22 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrJsUtils.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrJsUtils.kt @@ -9,6 +9,8 @@ import org.jetbrains.kotlin.descriptors.isInterface import org.jetbrains.kotlin.descriptors.isClass import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.expressions.IrReturn +import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol import org.jetbrains.kotlin.ir.util.parentClassOrNull fun IrDeclaration.isExportedMember() = @@ -21,4 +23,8 @@ fun IrDeclaration?.isExportedInterface() = this is IrClass && kind.isInterface && isJsExport() fun IrDeclaration.isExportedInterfaceMember() = - parentClassOrNull.isExportedInterface() \ No newline at end of file + parentClassOrNull.isExportedInterface() + +fun IrReturn.isTheLastReturnStatementIn(target: IrReturnableBlockSymbol): Boolean { + return target.owner.statements.lastOrNull() === this +} \ No newline at end of file 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 f5630d7d68b..64f3baa8e7f 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 @@ -339,7 +339,7 @@ class LocalNameGenerator(val variableNames: NameTable) : IrElemen override fun visitReturn(expression: IrReturn) { val targetSymbol = expression.returnTargetSymbol - if (targetSymbol is IrReturnableBlockSymbol) { + if (targetSymbol is IrReturnableBlockSymbol && !expression.isTheLastReturnStatementIn(targetSymbol)) { persistReturnableBlockName(SYNTHETIC_BLOCK_LABEL, targetSymbol.owner) } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/BoxJsTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/BoxJsTestGenerated.java index 2f53472939e..5245688a58e 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/BoxJsTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/BoxJsTestGenerated.java @@ -4844,6 +4844,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { runTest("js/js.translator/testData/box/inline/lambdaReassignmentWithCapture.kt"); } + @Test + @TestMetadata("lastLabeledReturn.kt") + public void testLastLabeledReturn() throws Exception { + runTest("js/js.translator/testData/box/inline/lastLabeledReturn.kt"); + } + @Test @TestMetadata("localDeclarationsClash.kt") public void testLocalDeclarationsClash() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java index 4876ac4af24..8daa9c6da97 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java @@ -5222,6 +5222,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { runTest("js/js.translator/testData/box/inline/lambdaReassignmentWithCapture.kt"); } + @Test + @TestMetadata("lastLabeledReturn.kt") + public void testLastLabeledReturn() throws Exception { + runTest("js/js.translator/testData/box/inline/lastLabeledReturn.kt"); + } + @Test @TestMetadata("localDeclarationsClash.kt") public void testLocalDeclarationsClash() throws Exception { diff --git a/js/js.translator/testData/box/inline/lastLabeledReturn.kt b/js/js.translator/testData/box/inline/lastLabeledReturn.kt new file mode 100644 index 00000000000..62fe96f9cc4 --- /dev/null +++ b/js/js.translator/testData/box/inline/lastLabeledReturn.kt @@ -0,0 +1,12 @@ +inline fun foo(l: () -> Unit) { l() } +inline fun bar(l: () -> Unit) { l() } + +fun box(): String { + foo { + bar { + return@foo; + } + return "Failed: labeled return was not added" + } + return "OK" +} \ No newline at end of file