Treat any coroutine as it has non-const closure
Because it's always does capture controller
This commit is contained in:
@@ -101,7 +101,10 @@ public class JvmCodegenUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isConst(@NotNull CalculatedClosure closure) {
|
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) {
|
private static boolean isCallInsideSameClassAsDeclared(@NotNull CallableMemberDescriptor descriptor, @NotNull CodegenContext context) {
|
||||||
|
|||||||
@@ -40,4 +40,6 @@ public interface CalculatedClosure {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
List<Pair<String, Type>> getRecordedFields();
|
List<Pair<String, Type>> getRecordedFields();
|
||||||
|
|
||||||
|
boolean isCoroutine();
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState;
|
|||||||
import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt;
|
import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt;
|
||||||
import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
|
import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
|
||||||
import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping;
|
import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping;
|
||||||
|
import org.jetbrains.kotlin.coroutines.CoroutineUtilKt;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||||
@@ -270,7 +271,11 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
|||||||
String name = inventAnonymousClassName();
|
String name = inventAnonymousClassName();
|
||||||
Collection<KotlinType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
|
Collection<KotlinType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
|
||||||
ClassDescriptor classDescriptor = recordClassForCallable(functionLiteral, functionDescriptor, supertypes, name);
|
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);
|
classStack.push(classDescriptor);
|
||||||
nameStack.push(name);
|
nameStack.push(name);
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ public final class MutableClosure implements CalculatedClosure {
|
|||||||
private Map<DeclarationDescriptor, Integer> parameterOffsetInConstructor;
|
private Map<DeclarationDescriptor, Integer> parameterOffsetInConstructor;
|
||||||
private List<Pair<String, Type>> recordedFields;
|
private List<Pair<String, Type>> recordedFields;
|
||||||
private KotlinType captureReceiverType;
|
private KotlinType captureReceiverType;
|
||||||
|
private boolean isCoroutine;
|
||||||
|
|
||||||
MutableClosure(@NotNull ClassDescriptor classDescriptor, @Nullable ClassDescriptor enclosingClass) {
|
MutableClosure(@NotNull ClassDescriptor classDescriptor, @Nullable ClassDescriptor enclosingClass) {
|
||||||
this.enclosingClass = enclosingClass;
|
this.enclosingClass = enclosingClass;
|
||||||
@@ -109,6 +110,15 @@ public final class MutableClosure implements CalculatedClosure {
|
|||||||
return recordedFields != null ? recordedFields : Collections.<Pair<String, Type>>emptyList();
|
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) {
|
public void recordField(String name, Type type) {
|
||||||
if (recordedFields == null) {
|
if (recordedFields == null) {
|
||||||
recordedFields = new LinkedList<Pair<String, Type>>();
|
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);
|
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")
|
@TestMetadata("generate.kt")
|
||||||
public void testGenerate() throws Exception {
|
public void testGenerate() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/generate.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/generate.kt");
|
||||||
|
|||||||
@@ -113,6 +113,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("falseSmartCast.kt")
|
||||||
public void testFalseSmartCast() throws Exception {
|
public void testFalseSmartCast() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/falseSmartCast.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/falseSmartCast.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user