diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 5920fa4f3a3..25bcd8039da 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -666,7 +666,7 @@ public class ExpressionCodegen extends JetVisitor { final Type fieldType = JetTypeMapper.psiTypeToAsm(psiField.getType()); final boolean isStatic = psiField.hasModifierProperty(PsiModifier.STATIC); if (!isStatic) { - ensureReceiverOnStack(expression, null); + ensureReceiverOnStack(expression, null, JetTypeMapper.TYPE_OBJECT); } myStack.push(StackValue.field(fieldType, owner, psiField.getName(), isStatic)); } @@ -710,7 +710,7 @@ public class ExpressionCodegen extends JetVisitor { final boolean forceInterface = receiver != null && !(receiver instanceof JetThisExpression); final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField, forceInterface); if (!isStatic) { - ensureReceiverOnStack(expression, container instanceof ClassDescriptor ? (ClassDescriptor) container : null); + ensureReceiverOnStack(expression, container instanceof ClassDescriptor ? (ClassDescriptor) container : null, JetTypeMapper.TYPE_OBJECT); } myStack.push(iValue); } @@ -877,7 +877,7 @@ public class ExpressionCodegen extends JetVisitor { setOwnerFromCall(callableMethod, expression); } if (callableMethod.needsReceiverOnStack() && !haveReceiver) { - ensureReceiverOnStack(expression, callableMethod.getReceiverClass()); + ensureReceiverOnStack(expression, callableMethod.getReceiverClass(), JetTypeMapper.TYPE_OBJECT); } pushMethodArguments(expression, callableMethod.getValueParameterTypes()); if (callableMethod.acceptsTypeArguments()) { @@ -906,7 +906,16 @@ public class ExpressionCodegen extends JetVisitor { return null; } - public void ensureReceiverOnStack(PsiElement expression, @Nullable ClassDescriptor calleeContainingClass) { + public void ensureReceiverOnStack(PsiElement expression, @Nullable ClassDescriptor calleeContainingClass, + final Type expectedReceiverType) { + final StackValue receiver = getReceiverAsStackValue(expression, calleeContainingClass, expectedReceiverType); + if (receiver != null) { + receiver.put(receiver.type, v); + } + } + + @Nullable + public StackValue getReceiverAsStackValue(PsiElement expression, @Nullable ClassDescriptor calleeContainingClass, Type expectedReceiverType) { JetExpression receiver = getReceiverForSelector(expression); if (receiver != null) { if (!resolvesToClassOrPackage(receiver)) { @@ -914,13 +923,14 @@ public class ExpressionCodegen extends JetVisitor { if (myStack.isEmpty()) { throw new IllegalStateException("expected receiver on stack but it's not there: " + receiver.getText()); } - myStack.pop().put(JetTypeMapper.TYPE_OBJECT, v); + return myStack.pop(); } } else if (!(expression.getParent() instanceof JetSafeQualifiedExpression) && !(expression.getParent() instanceof JetPredicateExpression)) { - generateThisOrOuter(calleeContainingClass); + return generateThisOrOuter(calleeContainingClass); } + return null; } private static boolean isSubclass(ClassDescriptor subClass, ClassDescriptor superClass) { @@ -948,8 +958,9 @@ public class ExpressionCodegen extends JetVisitor { } } - public void generateThisOrOuter(ClassDescriptor calleeContainingClass) { + public StackValue generateThisOrOuter(ClassDescriptor calleeContainingClass) { boolean thisDone = false; + StackValue result = null; ClassContext cur = context; while (true) { @@ -973,16 +984,16 @@ public class ExpressionCodegen extends JetVisitor { } thisDone = true; - outer.put(outer.type, v); - + result = outer; } cur = parentContext; } if (!thisDone) { - thisToStack(); + return thisExpression(); } + return result; } private static boolean isReceiver(PsiElement expression) { @@ -1513,8 +1524,7 @@ public class ExpressionCodegen extends JetVisitor { public void visitThisExpression(JetThisExpression expression) { final DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression.getThisReference()); if (descriptor instanceof ClassDescriptor) { - generateThisOrOuter((ClassDescriptor) descriptor); - myStack.push(StackValue.onStack(JetTypeMapper.TYPE_OBJECT)); + myStack.push(generateThisOrOuter((ClassDescriptor) descriptor)); } else { generateThis(); diff --git a/idea/src/org/jetbrains/jet/codegen/intrinsics/ArraySize.java b/idea/src/org/jetbrains/jet/codegen/intrinsics/ArraySize.java index 0d38b0ed319..24b58ea2fed 100644 --- a/idea/src/org/jetbrains/jet/codegen/intrinsics/ArraySize.java +++ b/idea/src/org/jetbrains/jet/codegen/intrinsics/ArraySize.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen.intrinsics; import com.intellij.psi.PsiElement; import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.JetTypeMapper; import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.lang.psi.JetExpression; import org.objectweb.asm.Type; @@ -15,7 +16,7 @@ import java.util.List; public class ArraySize implements IntrinsicMethod { @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, boolean haveReceiver) { - codegen.ensureReceiverOnStack(element, null); + codegen.ensureReceiverOnStack(element, null, JetTypeMapper.TYPE_OBJECT); v.arraylength(); return StackValue.onStack(Type.INT_TYPE); } diff --git a/idea/src/org/jetbrains/jet/codegen/intrinsics/BinaryOp.java b/idea/src/org/jetbrains/jet/codegen/intrinsics/BinaryOp.java index 08930c95cac..8cc3fa47fa1 100644 --- a/idea/src/org/jetbrains/jet/codegen/intrinsics/BinaryOp.java +++ b/idea/src/org/jetbrains/jet/codegen/intrinsics/BinaryOp.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen.intrinsics; import com.intellij.psi.PsiElement; import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.JetTypeMapper; import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.lang.psi.JetExpression; import org.objectweb.asm.Type; @@ -21,10 +22,17 @@ public class BinaryOp implements IntrinsicMethod { @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, boolean haveReceiver) { - if (!haveReceiver) { + if (arguments.size() == 1) { + // intrinsic is called as an ordinary function + codegen.ensureReceiverOnStack(element, null, expectedType); codegen.gen(arguments.get(0), expectedType); } - codegen.gen(arguments.get(1), expectedType); + else { + if (!haveReceiver) { + codegen.gen(arguments.get(0), expectedType); + } + codegen.gen(arguments.get(1), expectedType); + } v.visitInsn(expectedType.getOpcode(opcode)); return StackValue.onStack(expectedType); } diff --git a/idea/src/org/jetbrains/jet/codegen/intrinsics/Not.java b/idea/src/org/jetbrains/jet/codegen/intrinsics/Not.java index 4388a3944a4..43a66296b6d 100644 --- a/idea/src/org/jetbrains/jet/codegen/intrinsics/Not.java +++ b/idea/src/org/jetbrains/jet/codegen/intrinsics/Not.java @@ -15,7 +15,13 @@ import java.util.List; public class Not implements IntrinsicMethod { @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, boolean haveReceiver) { - final StackValue stackValue = codegen.generateIntermediateValue(arguments.get(0)); + final StackValue stackValue; + if (arguments.size() == 1) { + stackValue = codegen.generateIntermediateValue(arguments.get(0)); + } + else { + stackValue = codegen.getReceiverAsStackValue(element, null, expectedType); + } return StackValue.not(stackValue); } } diff --git a/idea/src/org/jetbrains/jet/codegen/intrinsics/UnaryMinus.java b/idea/src/org/jetbrains/jet/codegen/intrinsics/UnaryMinus.java index 96f57d3fc47..a04cfb7cb4a 100644 --- a/idea/src/org/jetbrains/jet/codegen/intrinsics/UnaryMinus.java +++ b/idea/src/org/jetbrains/jet/codegen/intrinsics/UnaryMinus.java @@ -15,7 +15,12 @@ import java.util.List; public class UnaryMinus implements IntrinsicMethod { @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, boolean haveReceiver) { - codegen.gen(arguments.get(0), expectedType); + if (arguments.size() == 1) { + codegen.gen(arguments.get(0), expectedType); + } + else { + codegen.ensureReceiverOnStack(element, null, expectedType); + } v.neg(expectedType); return StackValue.onStack(expectedType); } diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index 3df1dafb268..bb0a43193d5 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -463,4 +463,22 @@ public class NamespaceGenTest extends CodegenTestCase { final Method main = generateFunction(); assertEquals("IntelliJ IDEA Rulezzz", main.invoke(null, "IDEA")); } + + public void testExplicitCallOfBinaryOpIntrinsic() throws Exception { + loadText("fun foo(a: Int) = a.plus(1)"); + final Method main = generateFunction(); + assertEquals(2, ((Integer) main.invoke(null, 1)).intValue()); + } + + public void testExplicitCallOfUnaryMinusIntrinsic() throws Exception { + loadText("fun foo(a: Int) = a.minus()"); + final Method main = generateFunction(); + assertEquals(-1, ((Integer) main.invoke(null, 1)).intValue()); + } + + public void testExplicitCallOfBooleanNotIntrinsic() throws Exception { + loadText("fun foo(a: Boolean) = a.not()"); + final Method main = generateFunction(); + assertEquals(false, ((Boolean) main.invoke(null, true)).booleanValue()); + } }