KT-2280 Recursive function declared in function results in VerifyError
#KT-2280 Fixed A closure's constructor should not take an instance of itself as an argument, because it would require caller to pass yet uninitialized value. Instead it should initialize a corresponding field with 'this'
This commit is contained in:
@@ -146,7 +146,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
|
||||
if (enclosingType == null)
|
||||
captureThis = null;
|
||||
|
||||
final Method constructor = generateConstructor(funClass, fun);
|
||||
final Method constructor = generateConstructor(funClass, fun, funDescriptor);
|
||||
|
||||
if (captureThis != null) {
|
||||
cv.newField(fun, ACC_FINAL, "this$0", enclosingType.getDescriptor(), null, null);
|
||||
@@ -160,6 +160,9 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
|
||||
|
||||
final GeneratedAnonymousClassDescriptor answer = new GeneratedAnonymousClassDescriptor(name, constructor, captureThis, captureReceiver);
|
||||
for (DeclarationDescriptor descriptor : closure.keySet()) {
|
||||
if (descriptor == funDescriptor) {
|
||||
continue;
|
||||
}
|
||||
if (descriptor instanceof VariableDescriptor) {
|
||||
final EnclosedValueDescriptor valueDescriptor = closure.get(descriptor);
|
||||
answer.addArg(valueDescriptor.getOuterValue());
|
||||
@@ -253,13 +256,16 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
private Method generateConstructor(JvmClassName funClass, PsiElement fun) {
|
||||
private Method generateConstructor(JvmClassName funClass, JetExpression fun, FunctionDescriptor funDescriptor) {
|
||||
int argCount = captureThis != null ? 1 : 0;
|
||||
argCount += (captureReceiver != null ? 1 : 0);
|
||||
|
||||
ArrayList<DeclarationDescriptor> variableDescriptors = new ArrayList<DeclarationDescriptor>();
|
||||
|
||||
for (DeclarationDescriptor descriptor : closure.keySet()) {
|
||||
if (descriptor == funDescriptor) {
|
||||
continue;
|
||||
}
|
||||
if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
|
||||
argCount++;
|
||||
variableDescriptors.add(descriptor);
|
||||
@@ -284,7 +290,13 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
|
||||
argTypes[i++] = captureReceiver;
|
||||
}
|
||||
|
||||
boolean putFieldForMyself = false;
|
||||
|
||||
for (DeclarationDescriptor descriptor : closure.keySet()) {
|
||||
if (descriptor == funDescriptor) {
|
||||
putFieldForMyself = true;
|
||||
continue;
|
||||
}
|
||||
if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
|
||||
final Type sharedVarType = state.getInjector().getJetTypeMapper().getSharedVarType(descriptor);
|
||||
final Type type;
|
||||
@@ -336,6 +348,14 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
|
||||
StackValue.field(type, name, fieldName, false).store(type, iv);
|
||||
}
|
||||
|
||||
if (putFieldForMyself) {
|
||||
Type type = name.getAsmType();
|
||||
String fieldName = "$" + funDescriptor.getName();
|
||||
iv.load(0, type);
|
||||
iv.dup();
|
||||
StackValue.field(type, name, fieldName, false).store(type, iv);
|
||||
}
|
||||
|
||||
iv.visitInsn(RETURN);
|
||||
|
||||
FunctionCodegen.endVisit(iv, "constructor", fun);
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(s: String): String {
|
||||
fun bar(count: Int): String =
|
||||
if (count == 0) s else bar(count - 1)
|
||||
return bar(239)
|
||||
}
|
||||
|
||||
fun box(): String = foo("OK")
|
||||
@@ -0,0 +1,7 @@
|
||||
fun box(): String {
|
||||
fun rmrf(i: Int) {
|
||||
if (i > 0) rmrf(i - 1)
|
||||
}
|
||||
rmrf(5)
|
||||
return "OK"
|
||||
}
|
||||
@@ -66,4 +66,8 @@ public class ClosuresGenTest extends CodegenTestCase {
|
||||
public void testKt2151() {
|
||||
blackBoxFile("regressions/kt2151.kt");
|
||||
}
|
||||
|
||||
public void testRecursiveClosure() {
|
||||
blackBoxFile("classes/recursiveClosure.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +125,10 @@ public class FunctionGenTest extends CodegenTestCase {
|
||||
blackBoxFile("regressions/kt2481.kt");
|
||||
}
|
||||
|
||||
public void testKt2280() {
|
||||
blackBoxFile("regressions/kt2280.kt");
|
||||
}
|
||||
|
||||
public static class WithJavaFunctionGenTest extends CodegenTestCase {
|
||||
private void blackBoxFileWithJava(@NotNull String ktFile) throws Exception {
|
||||
File javaClassesTempDirectory = new File(FileUtil.getTempDirectory(), "java-classes");
|
||||
|
||||
Reference in New Issue
Block a user