Fix coroutine generation in case of empty lambda

'handleResult' should be called in such case too
This commit is contained in:
Denis Zharkov
2016-06-20 15:41:33 +03:00
parent b6ccd03ef4
commit 453ee55615
4 changed files with 55 additions and 11 deletions
@@ -570,7 +570,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
statements.addAll(doWhileStatements); statements.addAll(doWhileStatements);
statements.add(condition); statements.add(condition);
conditionValue = generateBlock(statements, false, continueLabel, null); conditionValue = generateBlock((KtBlockExpression) body, statements, false, continueLabel, null);
} }
else { else {
if (body != null) { if (body != null) {
@@ -1678,9 +1678,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
/* package */ StackValue generateBlock(@NotNull KtBlockExpression expression, boolean isStatement) { /* package */ StackValue generateBlock(@NotNull KtBlockExpression expression, boolean isStatement) {
if (expression.getParent() instanceof KtNamedFunction) { if (expression.getParent() instanceof KtNamedFunction) {
// For functions end of block should be end of function label // 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 @NotNull
@@ -1695,16 +1695,18 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
} }
private StackValue generateBlock( private StackValue generateBlock(
List<KtExpression> statements, @NotNull KtBlockExpression block,
@NotNull List<KtExpression> statements,
boolean isStatement, boolean isStatement,
Label labelBeforeLastExpression, @Nullable Label labelBeforeLastExpression,
@Nullable final Label labelBlockEnd @Nullable final Label labelBlockEnd
) { ) {
final Label blockEnd = labelBlockEnd != null ? labelBlockEnd : new Label(); final Label blockEnd = labelBlockEnd != null ? labelBlockEnd : new Label();
final List<Function<StackValue, Void>> leaveTasks = Lists.newArrayList(); final List<Function<StackValue, Void>> leaveTasks = Lists.newArrayList();
StackValue answer = StackValue.none(); @Nullable
StackValue answer = null;
for (Iterator<KtExpression> iterator = statements.iterator(); iterator.hasNext(); ) { for (Iterator<KtExpression> iterator = statements.iterator(); iterator.hasNext(); ) {
KtExpression possiblyLabeledStatement = iterator.next(); KtExpression possiblyLabeledStatement = iterator.next();
@@ -1731,9 +1733,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
if (!iterator.hasNext()) { if (!iterator.hasNext()) {
answer = result; answer = result;
StackValue handleResultValue = !(possiblyLabeledStatement instanceof KtReturnExpression) StackValue handleResultValue = genControllerHandleResultForLastStatementInCoroutine(block, possiblyLabeledStatement);
? genControllerHandleResultCallIfNeeded(possiblyLabeledStatement, possiblyLabeledStatement)
: null;
if (handleResultValue != null) { if (handleResultValue != null) {
answer = handleResultValue; answer = handleResultValue;
} }
@@ -1745,6 +1745,13 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
addLeaveTaskToRemoveDescriptorFromFrameMap(statement, blockEnd, leaveTasks); addLeaveTaskToRemoveDescriptorFromFrameMap(statement, blockEnd, leaveTasks);
} }
if (answer == null) {
answer = genControllerHandleResultForLastStatementInCoroutine(block, null);
if (answer == null) {
answer = StackValue.none();
}
}
return new StackValueWithLeaveTask(answer, new Function1<StackValue, Unit>() { return new StackValueWithLeaveTask(answer, new Function1<StackValue, Unit>() {
@Override @Override
public Unit invoke(StackValue value) { public Unit invoke(StackValue value) {
@@ -1759,6 +1766,17 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> 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 @Nullable
private StackValue genControllerHandleResultCallIfNeeded(@NotNull KtExpression callOwner, @Nullable KtExpression valueToReturn) { private StackValue genControllerHandleResultCallIfNeeded(@NotNull KtExpression callOwner, @Nullable KtExpression valueToReturn) {
ResolvedCall<FunctionDescriptor> resolvedCall = bindingContext.get(RETURN_HANDLE_RESULT_RESOLVED_CALL, callOwner); ResolvedCall<FunctionDescriptor> resolvedCall = bindingContext.get(RETURN_HANDLE_RESULT_RESOLVED_CALL, callOwner);
@@ -114,12 +114,12 @@ class CallCompleter(
function.controllerTypeIfCoroutine ?: return@forEach function.controllerTypeIfCoroutine ?: return@forEach
val lastBlockStatement = it.functionLiteral.bodyExpression?.statements?.lastOrNull() ?: return@forEach val lastBlockStatement = it.functionLiteral.bodyExpression?.statements?.lastOrNull()
// Already resolved // Already resolved
if (lastBlockStatement is KtReturnExpression) return@forEach if (lastBlockStatement is KtReturnExpression) return@forEach
fakeCallResolver.resolveCoroutineHandleResultCallIfNeeded(lastBlockStatement, lastBlockStatement, function, context) fakeCallResolver.resolveCoroutineHandleResultCallIfNeeded(it.functionLiteral, lastBlockStatement, function, context)
} }
} }
@@ -0,0 +1,20 @@
class Controller {
var ok = false
operator fun handleResult(u: Unit, v: Continuation<Nothing>) {
ok = true
}
}
fun builder(coroutine c: Controller.() -> Continuation<Unit>): 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 {}
}
@@ -4153,6 +4153,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName); 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") @TestMetadata("illegalState.kt")
public void testIllegalState() throws Exception { public void testIllegalState() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/illegalState.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/illegalState.kt");