Use proper coroutine class descriptor for extension receiver generation

Before this commit context.getThisDescriptor() has been used, that was quite correct
until suspension happens inside inlined lambda (it has different this-descriptor)
This commit is contained in:
Denis Zharkov
2016-05-25 14:52:16 +03:00
parent 75e112e752
commit 94bd6dcc82
3 changed files with 43 additions and 4 deletions
@@ -2714,14 +2714,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
private StackValue generateExtensionReceiver(@NotNull CallableDescriptor descriptor) {
KotlinType coroutineControllerType = CoroutineUtilKt.getControllerTypeIfCoroutine(descriptor);
if (coroutineControllerType != null) {
ClassDescriptor thisDescriptor = context.getThisDescriptor();
ClassDescriptor classDescriptor = bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, descriptor);
assert classDescriptor != null : "class descriptor for coroutine " + descriptor + " should not be null";
StackValue coroutineReceiver = StackValue.thisOrOuter(this, classDescriptor, /* isSuper =*/ false, /* castReceiver */ false);
return StackValue.field(
FieldInfo.createForHiddenField(
typeMapper.mapClass(thisDescriptor),
FieldInfo.createForHiddenField(
typeMapper.mapClass(classDescriptor),
typeMapper.mapType(coroutineControllerType),
CoroutineCodegenUtilKt.COROUTINE_CONTROLLER_FIELD_NAME),
StackValue.thisOrOuter(this, thisDescriptor, /* isSuper =*/ false, /* castReceiver */ false));
coroutineReceiver);
}
return context.generateReceiver(descriptor, state, false);
@@ -0,0 +1,31 @@
class Controller {
suspend fun suspendHere(v: Int, x: Continuation<Int>) {
x.resume(v * 2)
}
}
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
c(Controller()).resume(Unit)
}
inline fun foo(x: (Int) -> Unit) {
for (i in 1..2) {
x(i)
}
}
fun box(): String {
var result = ""
builder {
result += "-"
foo {
result += suspendHere(it).toString()
}
result += "+"
}
if (result != "-24+") return "fail: $result"
return "OK"
}
@@ -4147,6 +4147,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("suspendFromInlineLambda.kt")
public void testSuspendFromInlineLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFromInlineLambda.kt");
doTest(fileName);
}
@TestMetadata("suspendInCycle.kt")
public void testSuspendInCycle() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendInCycle.kt");