KT-4173: Can't pass a non-trivial closure to a super-call for object expression

#KT-4173 Fixed
This commit is contained in:
Mikhael Bogdanov
2013-11-08 13:58:58 +04:00
parent 2c75bdacc5
commit df03eb5330
5 changed files with 151 additions and 22 deletions
@@ -44,10 +44,7 @@ import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import static org.jetbrains.jet.codegen.CodegenUtil.peekFromStack;
import static org.jetbrains.jet.codegen.FunctionTypesUtil.getSuperTypeForClosure;
@@ -59,9 +56,32 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
private static final TokenSet BINARY_OPERATIONS = TokenSet.orSet(
AUGMENTED_ASSIGNMENTS, TokenSet.create(PLUS, MINUS, MUL, DIV, PERC, RANGE, LT, GT, LTEQ, GTEQ, IDENTIFIER));
private static class ClassDescriptorWithState {
private boolean isDelegationToSuperCall;
private ClassDescriptor descriptor;
public ClassDescriptorWithState(ClassDescriptor descriptor) {
this.descriptor = descriptor;
}
public boolean isDelegationToSuperCall() {
return isDelegationToSuperCall;
}
public void setDelegationToSuperCall(boolean isDelegationToSuperCall) {
this.isDelegationToSuperCall = isDelegationToSuperCall;
}
public ClassDescriptor getDescriptor() {
return descriptor;
}
}
private final Map<String, Integer> anonymousSubclassesCount = new HashMap<String, Integer>();
private final Stack<ClassDescriptor> classStack = new Stack<ClassDescriptor>();
private final Stack<ClassDescriptorWithState> classStack = new Stack<ClassDescriptorWithState>();
private final Stack<String> nameStack = new Stack<String>();
private final BindingTrace bindingTrace;
private final BindingContext bindingContext;
@@ -129,7 +149,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
if (file.isScript()) {
//noinspection ConstantConditions
ClassDescriptor classDescriptor = bindingContext.get(CLASS_FOR_SCRIPT, bindingContext.get(SCRIPT, file.getScript()));
classStack.push(classDescriptor);
pushClassDescriptor(classDescriptor);
//noinspection ConstantConditions
nameStack.push(asmTypeForScriptPsi(bindingContext, file.getScript()).getInternalName());
}
@@ -139,7 +159,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
file.acceptChildren(this);
nameStack.pop();
if (file.isScript()) {
classStack.pop();
popClassDescriptor();
}
}
@@ -154,7 +174,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
super.visitEnumEntry(enumEntry);
}
else {
Type asmType = bindingTrace.get(ASM_TYPE, peekFromStack(classStack));
Type asmType = bindingTrace.get(ASM_TYPE, getOuterClassDescriptor());
assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, descriptor, asmType);
bindingTrace.record(ASM_TYPE, descriptor, asmType);
}
@@ -168,11 +188,11 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
String name = peekFromStack(nameStack) + JvmAbi.CLASS_OBJECT_SUFFIX;
recordClosure(classObject, classDescriptor, name);
classStack.push(classDescriptor);
pushClassDescriptor(classDescriptor);
nameStack.push(name);
super.visitClassObject(classObject);
nameStack.pop();
classStack.pop();
popClassDescriptor();
}
@Override
@@ -188,11 +208,11 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
String name = getName(classDescriptor);
recordClosure(declaration, classDescriptor, name);
classStack.push(classDescriptor);
pushClassDescriptor(classDescriptor);
nameStack.push(name);
super.visitObjectDeclaration(declaration);
nameStack.pop();
classStack.pop();
popClassDescriptor();
}
}
@@ -205,11 +225,11 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
String name = getName(classDescriptor);
recordClosure(klass, classDescriptor, name);
classStack.push(classDescriptor);
pushClassDescriptor(classDescriptor);
nameStack.push(name);
super.visitClass(klass);
nameStack.pop();
classStack.pop();
popClassDescriptor();
}
private String getName(ClassDescriptor classDescriptor) {
@@ -230,12 +250,12 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
String name = inventAnonymousClassName(expression.getObjectDeclaration());
recordClosure(expression.getObjectDeclaration(), classDescriptor, name);
classStack.push(classDescriptor);
pushClassDescriptor(classDescriptor);
//noinspection ConstantConditions
nameStack.push(bindingContext.get(ASM_TYPE, classDescriptor).getInternalName());
super.visitObjectLiteralExpression(expression);
nameStack.pop();
classStack.pop();
popClassDescriptor();
}
@Override
@@ -251,13 +271,41 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType);
recordClosure(functionLiteral, classDescriptor, name);
classStack.push(classDescriptor);
pushClassDescriptor(classDescriptor);
nameStack.push(name);
super.visitFunctionLiteralExpression(expression);
nameStack.pop();
popClassDescriptor();
}
private void pushClassDescriptor(ClassDescriptor classDescriptor) {
classStack.push(new ClassDescriptorWithState(classDescriptor));
}
private void popClassDescriptor() {
classStack.pop();
}
private ClassDescriptor getOuterClassDescriptor() {
ListIterator<ClassDescriptorWithState> iterator = classStack.listIterator(classStack.size());
while(iterator.hasPrevious()) {
ClassDescriptorWithState previous = iterator.previous();
if (!previous.isDelegationToSuperCall()) {//find last not delegated to super call
return previous.getDescriptor();
}
}
return null;
}
@Override
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
ClassDescriptorWithState state = peekFromStack(classStack);
assert state != null : "Class descriptor should be recorded before " + call + " processing";
state.setDelegationToSuperCall(true);
super.visitDelegationToSuperCallSpecifier(call);
state.setDelegationToSuperCall(false);
}
@Override
public void visitCallableReferenceExpression(JetCallableReferenceExpression expression) {
FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
@@ -273,19 +321,20 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType);
recordClosure(expression, classDescriptor, name);
classStack.push(classDescriptor);
pushClassDescriptor(classDescriptor);
nameStack.push(name);
super.visitCallableReferenceExpression(expression);
nameStack.pop();
classStack.pop();
popClassDescriptor();
}
private void recordClosure(
@NotNull JetElement element,
@NotNull ClassDescriptor classDescriptor,
@NotNull String name
) {
CodegenBinding.recordClosure(bindingTrace, element, classDescriptor, peekFromStack(classStack),
CodegenBinding.recordClosure(bindingTrace, element, classDescriptor, getOuterClassDescriptor(),
Type.getObjectType(name));
}
@@ -324,11 +373,11 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType);
recordClosure(function, classDescriptor, name);
classStack.push(classDescriptor);
pushClassDescriptor(classDescriptor);
nameStack.push(name);
super.visitNamedFunction(function);
nameStack.pop();
classStack.pop();
popClassDescriptor();
}
}
@@ -0,0 +1,18 @@
open class C(val f: () -> Unit) {
fun test() {
f()
}
}
class B(var x: Int) {
fun foo() {
object : C({x = 3}) {}.test()
}
}
fun box() : String {
val b = B(1)
b.foo()
return if (b.x != 3) "fail: b.x = ${b.x}" else "OK"
}
@@ -0,0 +1,20 @@
open class X(var s: ()-> Unit)
open class C(val f: X) {
fun test() {
f.s()
}
}
class B(var x: Int) {
fun foo() {
object : C(object: X({x = 3}) {}) {}.test()
}
}
fun box() : String {
val b = B(1)
b.foo()
return if (b.x != 3) "fail: b.x = ${b.x}" else "OK"
}
@@ -0,0 +1,27 @@
open class C(s: Int) {
fun test() {
}
}
class B(var x: Int) {
fun foo() {
class A(val a: Int) : C({a}()) {
}
A(11).test()
class B(val a: Int) : C(a) {
}
B(11).test()
}
}
fun box() : String {
val b = B(1)
b.foo()
return "OK"
}
@@ -4200,6 +4200,21 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest("compiler/testData/codegen/box/super/kt3538.kt");
}
@TestMetadata("kt4173.kt")
public void testKt4173() throws Exception {
doTest("compiler/testData/codegen/box/super/kt4173.kt");
}
@TestMetadata("kt4173_2.kt")
public void testKt4173_2() throws Exception {
doTest("compiler/testData/codegen/box/super/kt4173_2.kt");
}
@TestMetadata("kt4173_3.kt")
public void testKt4173_3() throws Exception {
doTest("compiler/testData/codegen/box/super/kt4173_3.kt");
}
@TestMetadata("multipleSuperTraits.kt")
public void testMultipleSuperTraits() throws Exception {
doTest("compiler/testData/codegen/box/super/multipleSuperTraits.kt");