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:
Alexander Udalov
2012-07-31 19:05:38 +04:00
parent b883bf6ef5
commit dcd5cad427
5 changed files with 44 additions and 2 deletions
@@ -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");