From 453ee55615a26355d8d5e9dba65639eaf3c32000 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Mon, 20 Jun 2016 15:41:33 +0300 Subject: [PATCH] Fix coroutine generation in case of empty lambda 'handleResult' should be called in such case too --- .../kotlin/codegen/ExpressionCodegen.java | 36 ++++++++++++++----- .../kotlin/resolve/calls/CallCompleter.kt | 4 +-- .../coroutines/handleResultCallEmptyBody.kt | 20 +++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 ++++ 4 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/codegen/box/coroutines/handleResultCallEmptyBody.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index c649c59f3a9..5613afa1a76 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -570,7 +570,7 @@ public class ExpressionCodegen extends KtVisitor impleme statements.addAll(doWhileStatements); statements.add(condition); - conditionValue = generateBlock(statements, false, continueLabel, null); + conditionValue = generateBlock((KtBlockExpression) body, statements, false, continueLabel, null); } else { if (body != null) { @@ -1678,9 +1678,9 @@ public class ExpressionCodegen extends KtVisitor impleme /* package */ StackValue generateBlock(@NotNull KtBlockExpression expression, boolean isStatement) { if (expression.getParent() instanceof KtNamedFunction) { // For functions end of block should be end of function label - return generateBlock(expression.getStatements(), isStatement, null, context.getMethodEndLabel()); + return generateBlock(expression, expression.getStatements(), isStatement, null, context.getMethodEndLabel()); } - return generateBlock(expression.getStatements(), isStatement, null, null); + return generateBlock(expression, expression.getStatements(), isStatement, null, null); } @NotNull @@ -1695,16 +1695,18 @@ public class ExpressionCodegen extends KtVisitor impleme } private StackValue generateBlock( - List statements, + @NotNull KtBlockExpression block, + @NotNull List statements, boolean isStatement, - Label labelBeforeLastExpression, + @Nullable Label labelBeforeLastExpression, @Nullable final Label labelBlockEnd ) { final Label blockEnd = labelBlockEnd != null ? labelBlockEnd : new Label(); final List> leaveTasks = Lists.newArrayList(); - StackValue answer = StackValue.none(); + @Nullable + StackValue answer = null; for (Iterator iterator = statements.iterator(); iterator.hasNext(); ) { KtExpression possiblyLabeledStatement = iterator.next(); @@ -1731,9 +1733,7 @@ public class ExpressionCodegen extends KtVisitor impleme if (!iterator.hasNext()) { answer = result; - StackValue handleResultValue = !(possiblyLabeledStatement instanceof KtReturnExpression) - ? genControllerHandleResultCallIfNeeded(possiblyLabeledStatement, possiblyLabeledStatement) - : null; + StackValue handleResultValue = genControllerHandleResultForLastStatementInCoroutine(block, possiblyLabeledStatement); if (handleResultValue != null) { answer = handleResultValue; } @@ -1745,6 +1745,13 @@ public class ExpressionCodegen extends KtVisitor impleme addLeaveTaskToRemoveDescriptorFromFrameMap(statement, blockEnd, leaveTasks); } + if (answer == null) { + answer = genControllerHandleResultForLastStatementInCoroutine(block, null); + if (answer == null) { + answer = StackValue.none(); + } + } + return new StackValueWithLeaveTask(answer, new Function1() { @Override public Unit invoke(StackValue value) { @@ -1759,6 +1766,17 @@ public class ExpressionCodegen extends KtVisitor impleme }); } + @Nullable + private StackValue genControllerHandleResultForLastStatementInCoroutine( + @NotNull KtBlockExpression block, + @Nullable KtExpression lastStatement + ) { + if (!(block.getParent() instanceof KtFunctionLiteral)) return null; + KtFunctionLiteral functionLiteral = (KtFunctionLiteral) block.getParent(); + + return genControllerHandleResultCallIfNeeded(functionLiteral, lastStatement); + } + @Nullable private StackValue genControllerHandleResultCallIfNeeded(@NotNull KtExpression callOwner, @Nullable KtExpression valueToReturn) { ResolvedCall resolvedCall = bindingContext.get(RETURN_HANDLE_RESULT_RESOLVED_CALL, callOwner); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt index 6f7e38e31b3..ad688936905 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt @@ -114,12 +114,12 @@ class CallCompleter( function.controllerTypeIfCoroutine ?: return@forEach - val lastBlockStatement = it.functionLiteral.bodyExpression?.statements?.lastOrNull() ?: return@forEach + val lastBlockStatement = it.functionLiteral.bodyExpression?.statements?.lastOrNull() // Already resolved if (lastBlockStatement is KtReturnExpression) return@forEach - fakeCallResolver.resolveCoroutineHandleResultCallIfNeeded(lastBlockStatement, lastBlockStatement, function, context) + fakeCallResolver.resolveCoroutineHandleResultCallIfNeeded(it.functionLiteral, lastBlockStatement, function, context) } } diff --git a/compiler/testData/codegen/box/coroutines/handleResultCallEmptyBody.kt b/compiler/testData/codegen/box/coroutines/handleResultCallEmptyBody.kt new file mode 100644 index 00000000000..a8f72899d7d --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/handleResultCallEmptyBody.kt @@ -0,0 +1,20 @@ +class Controller { + var ok = false + + operator fun handleResult(u: Unit, v: Continuation) { + ok = true + } +} + +fun builder(coroutine c: Controller.() -> Continuation): String { + val controller = Controller() + c(controller).resume(Unit) + if (!controller.ok) throw java.lang.RuntimeException("Was not called") + return "OK" +} + +fun unitFun() {} + +fun box(): String { + return builder {} +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index e9ea4900d7f..db4a06930e1 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4153,6 +4153,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("handleResultCallEmptyBody.kt") + public void testHandleResultCallEmptyBody() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/handleResultCallEmptyBody.kt"); + doTest(fileName); + } + @TestMetadata("illegalState.kt") public void testIllegalState() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/illegalState.kt");