From 78247520c7878303c37256cb9c6b8bfaef57d6b6 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 27 May 2011 19:03:11 +0400 Subject: [PATCH] correctly handle ensureReceiverOnStack() when the expression is itself a receiver; use correct type when putting/storing fields --- .../jetbrains/jet/codegen/ClassCodegen.java | 6 +++++- .../jet/codegen/ExpressionCodegen.java | 14 +++++++++++++- .../org/jetbrains/jet/codegen/StackValue.java | 4 ++-- .../properties/propertyReceiverOnStack.jet | 6 ++++++ .../jet/codegen/PropertyGenTest.java | 19 +++++++++++++------ 5 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 idea/testData/codegen/properties/propertyReceiverOnStack.jet diff --git a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java index c1deefae4b5..0ca6b3a33dc 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -353,7 +353,11 @@ public class ClassCodegen { propertyCodegen.gen((JetProperty) declaration, kind); } else if (declaration instanceof JetFunction) { - functionCodegen.gen((JetFunction) declaration, kind); + try { + functionCodegen.gen((JetFunction) declaration, kind); + } catch (RuntimeException e) { + throw new RuntimeException("Error generating method "+ aClass.getName() + "." + declaration.getName(), e); + } } } diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 0a2289ae946..6d72385558c 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -757,10 +757,13 @@ public class ExpressionCodegen extends JetVisitor { } private void ensureReceiverOnStack(JetElement expression) { - if (expression.getParent() instanceof JetDotQualifiedExpression) { + if (expression.getParent() instanceof JetDotQualifiedExpression && !isReceiver(expression)) { final JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent(); if (!resolvesToClassOrPackage(parent.getReceiverExpression())) { // we have a receiver on stack + if (myStack.isEmpty()) { + throw new IllegalStateException("expected receiver on stack but it's not there: " + parent.getReceiverExpression().getText()); + } myStack.pop().put(JetTypeMapper.TYPE_OBJECT, v); } } @@ -769,6 +772,15 @@ public class ExpressionCodegen extends JetVisitor { } } + private static boolean isReceiver(JetElement expression) { + final PsiElement parent = expression.getParent(); + if (parent instanceof JetQualifiedExpression) { + final JetExpression receiverExpression = ((JetQualifiedExpression) parent).getReceiverExpression(); + return expression == receiverExpression; + } + return false; + } + private void pushMethodArguments(JetCall expression, Method method) { final Type[] argTypes = method.getArgumentTypes(); List args = expression.getValueArguments(); diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index 071843bc48c..066cc83926c 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -408,7 +408,7 @@ public abstract class StackValue { @Override public void put(Type type, InstructionAdapter v) { if (getter == null) { - v.visitFieldInsn(isStatic ? Opcodes.GETSTATIC : Opcodes.GETFIELD, fieldOwner, name, type.getDescriptor()); + v.visitFieldInsn(isStatic ? Opcodes.GETSTATIC : Opcodes.GETFIELD, fieldOwner, name, this.type.getDescriptor()); } else { v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : fieldOwner == null ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, interfaceOwner, getter.getName(), getter.getDescriptor()); @@ -418,7 +418,7 @@ public abstract class StackValue { @Override public void store(InstructionAdapter v) { if (setter == null) { - v.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, fieldOwner, name, type.getDescriptor()); + v.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, fieldOwner, name, this.type.getDescriptor()); } else { v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : fieldOwner == null ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, interfaceOwner, setter.getName(), setter.getDescriptor()); diff --git a/idea/testData/codegen/properties/propertyReceiverOnStack.jet b/idea/testData/codegen/properties/propertyReceiverOnStack.jet new file mode 100644 index 00000000000..e94155ce0d6 --- /dev/null +++ b/idea/testData/codegen/properties/propertyReceiverOnStack.jet @@ -0,0 +1,6 @@ +class Evaluator(val expr: StringBuilder) { + fun evaluateArg(): Int { + return expr.length() + } +} + diff --git a/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java b/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java index 29bdf30d21f..37579d4063e 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.codegen; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -15,7 +16,6 @@ public class PropertyGenTest extends CodegenTestCase { public void testPrivateVal() throws Exception { loadFile(); - System.out.println(generateToText()); final Class aClass = loadImplementationClass(generateClassesInFile(), "PrivateVal"); final Field[] fields = aClass.getDeclaredFields(); assertEquals(2, fields.length); // $typeInfo, prop @@ -25,7 +25,6 @@ public class PropertyGenTest extends CodegenTestCase { public void testPrivateVar() throws Exception { loadFile(); - System.out.println(generateToText()); final Class aClass = loadImplementationClass(generateClassesInFile(), "PrivateVar"); final Object instance = aClass.newInstance(); Method setter = findMethodByName(aClass, "setValueOfX"); @@ -36,7 +35,6 @@ public class PropertyGenTest extends CodegenTestCase { public void testPublicVar() throws Exception { loadText("class PublicVar() { public var foo = 0; }"); - System.out.println(generateToText()); final Class aClass = loadImplementationClass(generateClassesInFile(), "PublicVar"); final Object instance = aClass.newInstance(); Method setter = findMethodByName(aClass, "setFoo"); @@ -79,7 +77,6 @@ public class PropertyGenTest extends CodegenTestCase { public void testFieldSetter() throws Exception { loadFile(); - System.out.println(generateToText()); final Method method = generateFunction("append"); method.invoke(null, "IntelliJ "); String value = (String) method.invoke(null, "IDEA"); @@ -88,7 +85,6 @@ public class PropertyGenTest extends CodegenTestCase { public void testFieldSetterPlusEq() throws Exception { loadFile(); - System.out.println(generateToText()); final Method method = generateFunction("append"); method.invoke(null, "IntelliJ "); String value = (String) method.invoke(null, "IDEA"); @@ -109,8 +105,19 @@ public class PropertyGenTest extends CodegenTestCase { public void testInitializersForNamespaceProperties() throws Exception { loadText("public val x = System.currentTimeMillis()"); - System.out.println(generateToText()); final Method method = generateFunction("getX"); assertIsCurrentTime((Long) method.invoke(null)); } + + public void testPropertyReceiverOnStack() throws Exception { + loadFile(); + System.out.println(generateToText()); + final Class aClass = loadImplementationClass(generateClassesInFile(), "Evaluator"); + final Constructor constructor = aClass.getConstructor(StringBuilder.class); + StringBuilder sb = new StringBuilder("xyzzy"); + final Object instance = constructor.newInstance(sb); + final Method method = aClass.getMethod("evaluateArg"); + Integer result = (Integer) method.invoke(instance); + assertEquals(5, result.intValue()); + } }