Treat any coroutine as it has non-const closure

Because it's always does capture controller
This commit is contained in:
Denis Zharkov
2016-07-04 15:32:54 +03:00
parent df4bf61378
commit d657bc8110
8 changed files with 83 additions and 2 deletions
@@ -101,7 +101,10 @@ public class JvmCodegenUtil {
}
public static boolean isConst(@NotNull CalculatedClosure closure) {
return closure.getCaptureThis() == null && closure.getCaptureReceiverType() == null && closure.getCaptureVariables().isEmpty();
return closure.getCaptureThis() == null &&
closure.getCaptureReceiverType() == null &&
closure.getCaptureVariables().isEmpty() &&
!closure.isCoroutine();
}
private static boolean isCallInsideSameClassAsDeclared(@NotNull CallableMemberDescriptor descriptor, @NotNull CodegenContext context) {
@@ -40,4 +40,6 @@ public interface CalculatedClosure {
@NotNull
List<Pair<String, Type>> getRecordedFields();
boolean isCoroutine();
}
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt;
import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping;
import org.jetbrains.kotlin.coroutines.CoroutineUtilKt;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
@@ -270,7 +271,11 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
String name = inventAnonymousClassName();
Collection<KotlinType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
ClassDescriptor classDescriptor = recordClassForCallable(functionLiteral, functionDescriptor, supertypes, name);
recordClosure(classDescriptor, name);
MutableClosure closure = recordClosure(classDescriptor, name);
if (CoroutineUtilKt.getControllerTypeIfCoroutine(functionDescriptor) != null) {
closure.setCoroutine(true);
}
classStack.push(classDescriptor);
nameStack.push(name);
@@ -39,6 +39,7 @@ public final class MutableClosure implements CalculatedClosure {
private Map<DeclarationDescriptor, Integer> parameterOffsetInConstructor;
private List<Pair<String, Type>> recordedFields;
private KotlinType captureReceiverType;
private boolean isCoroutine;
MutableClosure(@NotNull ClassDescriptor classDescriptor, @Nullable ClassDescriptor enclosingClass) {
this.enclosingClass = enclosingClass;
@@ -109,6 +110,15 @@ public final class MutableClosure implements CalculatedClosure {
return recordedFields != null ? recordedFields : Collections.<Pair<String, Type>>emptyList();
}
@Override
public boolean isCoroutine() {
return isCoroutine;
}
public void setCoroutine(boolean coroutine) {
this.isCoroutine = coroutine;
}
public void recordField(String name, Type type) {
if (recordedFields == null) {
recordedFields = new LinkedList<Pair<String, Type>>();
@@ -0,0 +1,26 @@
var result = 0
class Controller {
suspend fun suspendHere(x: Continuation<String>) {
result++
x.resume("OK")
}
}
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
c(Controller()).resume(Unit)
}
fun box(): String {
for (i in 1..3) {
builder {
if (suspendHere() != "OK") throw java.lang.RuntimeException("fail 1")
}
}
if (result != 3) return "fail 2: $result"
return "OK"
}
@@ -0,0 +1,23 @@
class Controller {
suspend fun suspendHere(x: Continuation<String>) {
}
}
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
c(Controller()).resume(Unit)
}
fun box(): String {
for (i in 1..3) {
builder {
if (suspendHere() != "OK") throw java.lang.RuntimeException("fail 1")
}
}
return "OK"
}
// 1 GETSTATIC kotlin/Unit.INSTANCE : Lkotlin/Unit;
// 1 GETSTATIC
@@ -4159,6 +4159,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("emptyClosure.kt")
public void testEmptyClosure() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/emptyClosure.kt");
doTest(fileName);
}
@TestMetadata("generate.kt")
public void testGenerate() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/generate.kt");
@@ -113,6 +113,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
doTest(fileName);
}
@TestMetadata("constCoroutine.kt")
public void testConstCoroutine() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/constCoroutine.kt");
doTest(fileName);
}
@TestMetadata("falseSmartCast.kt")
public void testFalseSmartCast() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/falseSmartCast.kt");