From dc8e90809cd61f9418eedaf1b7fec499b3e470ed Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Mon, 21 Nov 2016 17:47:43 +0300 Subject: [PATCH] JS: coroutines: fix handling of throw statement inside try/catch block when controller has handleSuspend function --- .../controlFlow/throwInTryWithHandleResult.kt | 37 +++++++++++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 6 +++ ...CoroutineBlackBoxCodegenTestGenerated.java | 6 +++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 +++ .../js/coroutine/CoroutineBodyTransformer.kt | 5 +-- .../semantics/JsCodegenBoxTestGenerated.java | 6 +++ 6 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/codegen/box/coroutines/controlFlow/throwInTryWithHandleResult.kt diff --git a/compiler/testData/codegen/box/coroutines/controlFlow/throwInTryWithHandleResult.kt b/compiler/testData/codegen/box/coroutines/controlFlow/throwInTryWithHandleResult.kt new file mode 100644 index 00000000000..0f55c45aa53 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/controlFlow/throwInTryWithHandleResult.kt @@ -0,0 +1,37 @@ +// WITH_RUNTIME + +class Controller { + var result = "" + + suspend fun suspendAndLog(value: T, c: Continuation) { + result += "suspend($value);" + c.resume(value) + } + + operator fun handleException(exception: Throwable, c: Continuation) { + result += "ignoreCaught(${exception.message});" + } +} + +fun builder(coroutine c: Controller.() -> Continuation): String { + val controller = Controller() + c(controller).resume(Unit) + return controller.result +} + +fun box(): String { + val value = builder { + try { + suspendAndLog("before") + throw RuntimeException("foo") + } catch (e: RuntimeException) { + result += "caught(${e.message});" + } + suspendAndLog("after") + } + if (value != "suspend(before);caught(foo);suspend(after);") { + return "fail: $value" + } + + return "OK" +} \ 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 0a618920822..bb58cd28ef5 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 @@ -4774,6 +4774,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("throwInTryWithHandleResult.kt") + public void testThrowInTryWithHandleResult() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/throwInTryWithHandleResult.kt"); + doTest(fileName); + } + @TestMetadata("whileStatement.kt") public void testWhileStatement() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/whileStatement.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/AdditionalCoroutineBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/AdditionalCoroutineBlackBoxCodegenTestGenerated.java index 56242791130..01c41234eea 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/AdditionalCoroutineBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/AdditionalCoroutineBlackBoxCodegenTestGenerated.java @@ -332,6 +332,12 @@ public class AdditionalCoroutineBlackBoxCodegenTestGenerated extends AbstractAdd KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/controlFlow"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("throwInTryWithHandleResult.kt") + public void testThrowInTryWithHandleResult() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/throwInTryWithHandleResult.kt"); + doTest(fileName); + } + } @TestMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 55c36831d01..233881acc7c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4774,6 +4774,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("throwInTryWithHandleResult.kt") + public void testThrowInTryWithHandleResult() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/throwInTryWithHandleResult.kt"); + doTest(fileName); + } + @TestMetadata("whileStatement.kt") public void testWhileStatement() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/whileStatement.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 13d65f08786..b57bb46835d 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 @@ -73,7 +73,7 @@ class CoroutineBodyTransformer( val thenEntryBlock = CoroutineBlock() currentBlock = thenEntryBlock - x.thenStatement?.accept(this) + x.thenStatement.accept(this) val thenExitBlock = currentBlock val elseEntryBlock = CoroutineBlock() @@ -322,8 +322,7 @@ class CoroutineBodyTransformer( } override fun visitThrow(x: JsThrow) { - if (throwFunctionName != null) { - // TODO: what if we catch exception in coroutine? + if (throwFunctionName != null && tryStack.isEmpty()) { val methodRef = JsNameRef(throwFunctionName, JsNameRef(context.controllerFieldName, JsLiteral.THIS)) val invocation = JsInvocation(methodRef, x.expression).apply { source = x.source 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 cd354d7af7a..f70b0fe17ac 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 @@ -5591,6 +5591,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("throwInTryWithHandleResult.kt") + public void testThrowInTryWithHandleResult() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/throwInTryWithHandleResult.kt"); + doTest(fileName); + } + @TestMetadata("whileStatement.kt") public void testWhileStatement() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/whileStatement.kt");