Fix coroutine generation in case of empty lambda
'handleResult' should be called in such case too
This commit is contained in:
@@ -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");
|
||||||
|
|||||||
Reference in New Issue
Block a user