KT-4173: Can't pass a non-trivial closure to a super-call for object expression
#KT-4173 Fixed
This commit is contained in:
+71
-22
@@ -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.resolve.scopes.JetScope;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.jetbrains.jet.codegen.CodegenUtil.peekFromStack;
|
import static org.jetbrains.jet.codegen.CodegenUtil.peekFromStack;
|
||||||
import static org.jetbrains.jet.codegen.FunctionTypesUtil.getSuperTypeForClosure;
|
import static org.jetbrains.jet.codegen.FunctionTypesUtil.getSuperTypeForClosure;
|
||||||
@@ -59,9 +56,32 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
|||||||
private static final TokenSet BINARY_OPERATIONS = TokenSet.orSet(
|
private static final TokenSet BINARY_OPERATIONS = TokenSet.orSet(
|
||||||
AUGMENTED_ASSIGNMENTS, TokenSet.create(PLUS, MINUS, MUL, DIV, PERC, RANGE, LT, GT, LTEQ, GTEQ, IDENTIFIER));
|
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 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 Stack<String> nameStack = new Stack<String>();
|
||||||
private final BindingTrace bindingTrace;
|
private final BindingTrace bindingTrace;
|
||||||
private final BindingContext bindingContext;
|
private final BindingContext bindingContext;
|
||||||
@@ -129,7 +149,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
|||||||
if (file.isScript()) {
|
if (file.isScript()) {
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
ClassDescriptor classDescriptor = bindingContext.get(CLASS_FOR_SCRIPT, bindingContext.get(SCRIPT, file.getScript()));
|
ClassDescriptor classDescriptor = bindingContext.get(CLASS_FOR_SCRIPT, bindingContext.get(SCRIPT, file.getScript()));
|
||||||
classStack.push(classDescriptor);
|
pushClassDescriptor(classDescriptor);
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
nameStack.push(asmTypeForScriptPsi(bindingContext, file.getScript()).getInternalName());
|
nameStack.push(asmTypeForScriptPsi(bindingContext, file.getScript()).getInternalName());
|
||||||
}
|
}
|
||||||
@@ -139,7 +159,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
|||||||
file.acceptChildren(this);
|
file.acceptChildren(this);
|
||||||
nameStack.pop();
|
nameStack.pop();
|
||||||
if (file.isScript()) {
|
if (file.isScript()) {
|
||||||
classStack.pop();
|
popClassDescriptor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +174,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
|||||||
super.visitEnumEntry(enumEntry);
|
super.visitEnumEntry(enumEntry);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Type asmType = bindingTrace.get(ASM_TYPE, peekFromStack(classStack));
|
Type asmType = bindingTrace.get(ASM_TYPE, getOuterClassDescriptor());
|
||||||
assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, descriptor, asmType);
|
assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, descriptor, asmType);
|
||||||
bindingTrace.record(ASM_TYPE, descriptor, asmType);
|
bindingTrace.record(ASM_TYPE, descriptor, asmType);
|
||||||
}
|
}
|
||||||
@@ -168,11 +188,11 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
|||||||
String name = peekFromStack(nameStack) + JvmAbi.CLASS_OBJECT_SUFFIX;
|
String name = peekFromStack(nameStack) + JvmAbi.CLASS_OBJECT_SUFFIX;
|
||||||
recordClosure(classObject, classDescriptor, name);
|
recordClosure(classObject, classDescriptor, name);
|
||||||
|
|
||||||
classStack.push(classDescriptor);
|
pushClassDescriptor(classDescriptor);
|
||||||
nameStack.push(name);
|
nameStack.push(name);
|
||||||
super.visitClassObject(classObject);
|
super.visitClassObject(classObject);
|
||||||
nameStack.pop();
|
nameStack.pop();
|
||||||
classStack.pop();
|
popClassDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -188,11 +208,11 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
|||||||
String name = getName(classDescriptor);
|
String name = getName(classDescriptor);
|
||||||
recordClosure(declaration, classDescriptor, name);
|
recordClosure(declaration, classDescriptor, name);
|
||||||
|
|
||||||
classStack.push(classDescriptor);
|
pushClassDescriptor(classDescriptor);
|
||||||
nameStack.push(name);
|
nameStack.push(name);
|
||||||
super.visitObjectDeclaration(declaration);
|
super.visitObjectDeclaration(declaration);
|
||||||
nameStack.pop();
|
nameStack.pop();
|
||||||
classStack.pop();
|
popClassDescriptor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,11 +225,11 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
|||||||
String name = getName(classDescriptor);
|
String name = getName(classDescriptor);
|
||||||
recordClosure(klass, classDescriptor, name);
|
recordClosure(klass, classDescriptor, name);
|
||||||
|
|
||||||
classStack.push(classDescriptor);
|
pushClassDescriptor(classDescriptor);
|
||||||
nameStack.push(name);
|
nameStack.push(name);
|
||||||
super.visitClass(klass);
|
super.visitClass(klass);
|
||||||
nameStack.pop();
|
nameStack.pop();
|
||||||
classStack.pop();
|
popClassDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getName(ClassDescriptor classDescriptor) {
|
private String getName(ClassDescriptor classDescriptor) {
|
||||||
@@ -230,12 +250,12 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
|||||||
String name = inventAnonymousClassName(expression.getObjectDeclaration());
|
String name = inventAnonymousClassName(expression.getObjectDeclaration());
|
||||||
recordClosure(expression.getObjectDeclaration(), classDescriptor, name);
|
recordClosure(expression.getObjectDeclaration(), classDescriptor, name);
|
||||||
|
|
||||||
classStack.push(classDescriptor);
|
pushClassDescriptor(classDescriptor);
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
nameStack.push(bindingContext.get(ASM_TYPE, classDescriptor).getInternalName());
|
nameStack.push(bindingContext.get(ASM_TYPE, classDescriptor).getInternalName());
|
||||||
super.visitObjectLiteralExpression(expression);
|
super.visitObjectLiteralExpression(expression);
|
||||||
nameStack.pop();
|
nameStack.pop();
|
||||||
classStack.pop();
|
popClassDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -251,13 +271,41 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
|||||||
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType);
|
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType);
|
||||||
recordClosure(functionLiteral, classDescriptor, name);
|
recordClosure(functionLiteral, classDescriptor, name);
|
||||||
|
|
||||||
classStack.push(classDescriptor);
|
pushClassDescriptor(classDescriptor);
|
||||||
nameStack.push(name);
|
nameStack.push(name);
|
||||||
super.visitFunctionLiteralExpression(expression);
|
super.visitFunctionLiteralExpression(expression);
|
||||||
nameStack.pop();
|
nameStack.pop();
|
||||||
|
popClassDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pushClassDescriptor(ClassDescriptor classDescriptor) {
|
||||||
|
classStack.push(new ClassDescriptorWithState(classDescriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void popClassDescriptor() {
|
||||||
classStack.pop();
|
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
|
@Override
|
||||||
public void visitCallableReferenceExpression(JetCallableReferenceExpression expression) {
|
public void visitCallableReferenceExpression(JetCallableReferenceExpression expression) {
|
||||||
FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
|
FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
|
||||||
@@ -273,19 +321,20 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
|||||||
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType);
|
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType);
|
||||||
recordClosure(expression, classDescriptor, name);
|
recordClosure(expression, classDescriptor, name);
|
||||||
|
|
||||||
classStack.push(classDescriptor);
|
pushClassDescriptor(classDescriptor);
|
||||||
nameStack.push(name);
|
nameStack.push(name);
|
||||||
super.visitCallableReferenceExpression(expression);
|
super.visitCallableReferenceExpression(expression);
|
||||||
nameStack.pop();
|
nameStack.pop();
|
||||||
classStack.pop();
|
popClassDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void recordClosure(
|
private void recordClosure(
|
||||||
@NotNull JetElement element,
|
@NotNull JetElement element,
|
||||||
@NotNull ClassDescriptor classDescriptor,
|
@NotNull ClassDescriptor classDescriptor,
|
||||||
@NotNull String name
|
@NotNull String name
|
||||||
) {
|
) {
|
||||||
CodegenBinding.recordClosure(bindingTrace, element, classDescriptor, peekFromStack(classStack),
|
CodegenBinding.recordClosure(bindingTrace, element, classDescriptor, getOuterClassDescriptor(),
|
||||||
Type.getObjectType(name));
|
Type.getObjectType(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,11 +373,11 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
|||||||
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType);
|
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType);
|
||||||
recordClosure(function, classDescriptor, name);
|
recordClosure(function, classDescriptor, name);
|
||||||
|
|
||||||
classStack.push(classDescriptor);
|
pushClassDescriptor(classDescriptor);
|
||||||
nameStack.push(name);
|
nameStack.push(name);
|
||||||
super.visitNamedFunction(function);
|
super.visitNamedFunction(function);
|
||||||
nameStack.pop();
|
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");
|
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")
|
@TestMetadata("multipleSuperTraits.kt")
|
||||||
public void testMultipleSuperTraits() throws Exception {
|
public void testMultipleSuperTraits() throws Exception {
|
||||||
doTest("compiler/testData/codegen/box/super/multipleSuperTraits.kt");
|
doTest("compiler/testData/codegen/box/super/multipleSuperTraits.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user