diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 0b577fedb1c..baddde3e04c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1462,7 +1462,7 @@ public class ExpressionCodegen extends JetVisitor { return StackValue.onStack(Type.BOOLEAN_TYPE); } - private StackValue generateEqualsForExpressionsOnStack(IElementType opToken, Type leftType, Type rightType, boolean leftNullable, boolean rightNullable) { + public StackValue generateEqualsForExpressionsOnStack(IElementType opToken, Type leftType, Type rightType, boolean leftNullable, boolean rightNullable) { if (isNumberPrimitive(leftType) && leftType == rightType) { return compareExpressionsOnStack(opToken, leftType); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 926b496e243..3d674335c81 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -39,6 +39,7 @@ public class JetTypeMapper { public static final Type JL_BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean"); public static final Type JL_NUMBER_TYPE = Type.getObjectType("java/lang/Number"); public static final Type JL_STRING_BUILDER = Type.getObjectType("java/lang/StringBuilder"); + public static final Type JL_STRING_TYPE = Type.getObjectType("java/lang/String"); public static final Type ARRAY_INT_TYPE = Type.getType(int[].class); public static final Type ARRAY_LONG_TYPE = Type.getType(long[].class); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Equals.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Equals.java new file mode 100644 index 00000000000..8a9280c0102 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Equals.java @@ -0,0 +1,43 @@ +package org.jetbrains.jet.codegen.intrinsics; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.JetTypeMapper; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.lang.psi.JetCallExpression; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lexer.JetTokens; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; + +import java.util.List; + +/** + * @author alex.tkachman + */ +public class Equals implements IntrinsicMethod { + @Override + public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { + receiver.put(JetTypeMapper.TYPE_OBJECT, v); + + boolean leftNullable = true; + if(element instanceof JetCallExpression) { + JetCallExpression jetCallExpression = (JetCallExpression) element; + JetExpression calleeExpression = jetCallExpression.getCalleeExpression(); + if(calleeExpression != null) { + JetType leftType = codegen.getBindingContext().get(BindingContext.EXPRESSION_TYPE, calleeExpression); + if(leftType != null) + leftNullable = leftType.isNullable(); + } + } + + JetExpression rightExpr = arguments.get(0); + JetType rightType = codegen.getBindingContext().get(BindingContext.EXPRESSION_TYPE, rightExpr); + codegen.gen(rightExpr).put(JetTypeMapper.TYPE_OBJECT, v); + + return codegen.generateEqualsForExpressionsOnStack(JetTokens.EQEQ, JetTypeMapper.TYPE_OBJECT, JetTypeMapper.TYPE_OBJECT, leftNullable, rightType.isNullable()); + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java index b1efba96116..edda1e0f96b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java @@ -73,6 +73,11 @@ public class IntrinsicMethods { declareIntrinsicFunction("String", "plus", 1, new Concat()); + declareOverload(myStdLib.getLibraryScope().getFunctions("toString"), 0, new ToString()); + declareOverload(myStdLib.getLibraryScope().getFunctions("equals"), 1, new Equals()); + +// declareIntrinsicFunction("Any", "equals", 1, new Equals()); +// declareIntrinsicStringMethods(); declareIntrinsicProperty("String", "length", new StringLength()); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ToString.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ToString.java new file mode 100644 index 00000000000..18e706a4b1f --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ToString.java @@ -0,0 +1,24 @@ +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.jetbrains.jet.lang.types.JetStandardClasses; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; + +import java.util.List; + +/** + * @author alex.tkachman + */ +public class ToString implements IntrinsicMethod { + @Override + public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { + receiver.put(JetTypeMapper.TYPE_OBJECT, v); + v.invokestatic("java/lang/String", "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;"); + return StackValue.onStack(JetTypeMapper.JL_STRING_TYPE); + } +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java index 130148eb40b..da0ecc0dd4b 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java @@ -1,5 +1,8 @@ package org.jetbrains.jet.codegen; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + /** * @author alex.tkachman */ @@ -13,4 +16,29 @@ public class FunctionGenTest extends CodegenTestCase { blackBoxFile("functions/nothisnoclosure.jet"); System.out.println(generateToText()); } + + public void testAnyToString () throws InvocationTargetException, IllegalAccessException { + loadText("fun foo(x: Any) = x.toString()"); + System.out.println(generateToText()); + Method foo = generateFunction(); + assertEquals("something", foo.invoke(null, "something")); + assertEquals("null", foo.invoke(null, new Object[]{null})); + + } + + public void testAnyEqualsNullable () throws InvocationTargetException, IllegalAccessException { + loadText("fun foo(x: Any?) = x.equals(\"lala\")"); + System.out.println(generateToText()); + Method foo = generateFunction(); + assertTrue((Boolean) foo.invoke(null, "lala")); + assertFalse((Boolean) foo.invoke(null, "mama")); + } + + public void testAnyEquals () throws InvocationTargetException, IllegalAccessException { + loadText("fun foo(x: Any) = x.equals(\"lala\")"); + System.out.println(generateToText()); + Method foo = generateFunction(); + assertTrue((Boolean) foo.invoke(null, "lala")); + assertFalse((Boolean) foo.invoke(null, "mama")); + } }