From c8c3d24b451971ead24522b9f487168c5b88f6d5 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 27 Apr 2017 17:37:17 +0300 Subject: [PATCH] Fix non-suspending labeled loop in suspend function Fix bug when labeled loop, which does not contain suspend calls in its body, was losing its label --- .../coroutines/controlFlow/labeledWhile.kt | 50 +++++++++++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 6 +++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 +++ .../LightAnalysisModeTestGenerated.java | 6 +++ .../js/coroutine/CoroutineBodyTransformer.kt | 9 +++- .../semantics/JsCodegenBoxTestGenerated.java | 6 +++ 6 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/codegen/box/coroutines/controlFlow/labeledWhile.kt diff --git a/compiler/testData/codegen/box/coroutines/controlFlow/labeledWhile.kt b/compiler/testData/codegen/box/coroutines/controlFlow/labeledWhile.kt new file mode 100644 index 00000000000..fda94456574 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/controlFlow/labeledWhile.kt @@ -0,0 +1,50 @@ +// IGNORE_BACKEND: NATIVE +// WITH_RUNTIME +// WITH_COROUTINES +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +fun builder(c: suspend () -> Unit): Unit { + c.startCoroutine(handleResultContinuation { + finished = true + }) +} + +fun box(): String { + builder { + var i = 0 + var j = 0 + outer@while (i < 10) { + while (j < 10) { + if (i + j > 3) break@outer + log += "$i,$j;" + suspendAndContinue() + j++ + } + log += "i++;" + i++ + } + log += "done;" + suspendAndContinue() + } + + while (!finished) { + log += "@;" + postponed() + } + + if (log != "0,0;@;0,1;@;0,2;@;0,3;@;done;@;") return "fail: $log" + + return "OK" +} + +suspend fun suspendAndContinue(): Unit = suspendCoroutineOrReturn { c -> + postponed = { + c.resume(Unit) + } + COROUTINE_SUSPENDED +} + +var postponed: () -> Unit = {} +var finished = false +var log = "" \ No newline at end of file diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index c2de24c76f4..6925c12e001 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -5362,6 +5362,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("labeledWhile.kt") + public void testLabeledWhile() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/labeledWhile.kt"); + doTest(fileName); + } + @TestMetadata("returnFromFinally.kt") public void testReturnFromFinally() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/returnFromFinally.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 1f54d4909cf..19bd61d284f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -5362,6 +5362,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("labeledWhile.kt") + public void testLabeledWhile() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/labeledWhile.kt"); + doTest(fileName); + } + @TestMetadata("returnFromFinally.kt") public void testReturnFromFinally() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/returnFromFinally.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 71453afbb0e..67483f1170c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -5362,6 +5362,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("labeledWhile.kt") + public void testLabeledWhile() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/labeledWhile.kt"); + doTest(fileName); + } + @TestMetadata("returnFromFinally.kt") public void testReturnFromFinally() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/returnFromFinally.kt"); diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineBodyTransformer.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineBodyTransformer.kt index f22de1134f0..6b1411812cb 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineBodyTransformer.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineBodyTransformer.kt @@ -93,7 +93,14 @@ class CoroutineBodyTransformer(private val program: JsProgram, private val conte when (inner) { is JsWhile, is JsDoWhile, - is JsFor -> inner.accept(this) + is JsFor -> { + if (x in nodesToSplit) { + inner.accept(this) + } + else { + currentStatements += x + } + } else -> splitIfNecessary(x) { val successor = CoroutineBlock() diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index f4917bb88d7..60174543315 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -6077,6 +6077,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("labeledWhile.kt") + public void testLabeledWhile() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/labeledWhile.kt"); + doTest(fileName); + } + @TestMetadata("returnFromFinally.kt") public void testReturnFromFinally() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/returnFromFinally.kt");