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.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<StackValue, StackValue> 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<StackValue, StackValue> impleme
}
private StackValue generateBlock(
List<KtExpression> statements,
@NotNull KtBlockExpression block,
@NotNull List<KtExpression> statements,
boolean isStatement,
Label labelBeforeLastExpression,
@Nullable Label labelBeforeLastExpression,
@Nullable final Label labelBlockEnd
) {
final Label blockEnd = labelBlockEnd != null ? labelBlockEnd : new Label();
final List<Function<StackValue, Void>> leaveTasks = Lists.newArrayList();
StackValue answer = StackValue.none();
@Nullable
StackValue answer = null;
for (Iterator<KtExpression> iterator = statements.iterator(); iterator.hasNext(); ) {
KtExpression possiblyLabeledStatement = iterator.next();
@@ -1731,9 +1733,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> 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<StackValue, StackValue> impleme
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>() {
@Override
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
private StackValue genControllerHandleResultCallIfNeeded(@NotNull KtExpression callOwner, @Nullable KtExpression valueToReturn) {
ResolvedCall<FunctionDescriptor> resolvedCall = bindingContext.get(RETURN_HANDLE_RESULT_RESOLVED_CALL, callOwner);
@@ -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)
}
}
@@ -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);
}
@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");