diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/EqualsTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/EqualsTest.java index d9ad7e54983..ce6d2948d28 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/EqualsTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/EqualsTest.java @@ -22,7 +22,7 @@ public final class EqualsTest extends AbstractExpressionTest { super("equals/"); } - public void TODO_testCustomEqualsMethodOnAny() throws Exception { + public void testCustomEqualsMethodOnAny() throws Exception { fooBoxTest(); } @@ -34,6 +34,10 @@ public final class EqualsTest extends AbstractExpressionTest { fooBoxTest(); } + public void testExplicitEqualsMethodForPrimitives() throws Exception { + fooBoxTest(); + } + public void testStringsEqual() throws Exception { fooBoxTest(); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java index bb9f214fa22..d21dc16a036 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java @@ -19,7 +19,7 @@ package org.jetbrains.k2js.translate.intrinsic.functions.factories; import org.jetbrains.annotations.NotNull; import org.jetbrains.k2js.translate.intrinsic.functions.basic.BuiltInFunctionIntrinsic; import org.jetbrains.k2js.translate.intrinsic.functions.basic.CallStandardMethodIntrinsic; -import org.jetbrains.k2js.translate.intrinsic.functions.patterns.DescriptorPredicate; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.NamePredicate; import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern; @@ -27,16 +27,16 @@ import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternB * @author Pavel Talanov */ public final class TopLevelFIF extends CompositeFIF { - @NotNull - private static final DescriptorPredicate EXT_TO_STRING = pattern("toString"); - + public static final CallStandardMethodIntrinsic EQUALS = new CallStandardMethodIntrinsic("Kotlin.equals", true, 1); @NotNull public static final FunctionIntrinsicFactory INSTANCE = new TopLevelFIF(); private TopLevelFIF() { - add(EXT_TO_STRING, new BuiltInFunctionIntrinsic("toString")); - //TODO: add intrinsic for calling equals explicitly + add(pattern("toString"), new BuiltInFunctionIntrinsic("toString")); + add(pattern("equals"), EQUALS); + add(pattern(NamePredicate.PRIMITIVE_NUMBERS, "equals"), EQUALS); + add(pattern("String|Boolean|Char|Number.equals"), EQUALS); add(pattern("arrayOfNulls"), new CallStandardMethodIntrinsic("Kotlin.nullArray", false, 1)); } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/NamePredicate.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/NamePredicate.java index f42f2a3fa1e..3b9aab055a9 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/NamePredicate.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/NamePredicate.java @@ -32,7 +32,7 @@ import java.util.List; public final class NamePredicate implements Predicate { @NotNull - public static final NamePredicate PRIMITIVE_NUMBERS = new NamePredicate("Int", "Double", "Float", "Long", "Short"); + public static final NamePredicate PRIMITIVE_NUMBERS = new NamePredicate("Int", "Double", "Float", "Long", "Short", "Byte"); @NotNull private final List validNames = Lists.newArrayList(); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/BinaryOperationIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/BinaryOperationIntrinsic.java index 89f788e2ca8..d482f4878b4 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/BinaryOperationIntrinsic.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/BinaryOperationIntrinsic.java @@ -28,6 +28,7 @@ public interface BinaryOperationIntrinsic { boolean isApplicable(@NotNull JetBinaryExpression expression, @NotNull TranslationContext context); + @NotNull JsExpression apply(@NotNull JetBinaryExpression expression, @NotNull JsExpression left, @NotNull JsExpression right, @NotNull TranslationContext context); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/CompareToInstrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/CompareToInstrinsic.java index 4690f8fcb98..efabdab320f 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/CompareToInstrinsic.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/CompareToInstrinsic.java @@ -44,6 +44,7 @@ public final class CompareToInstrinsic implements BinaryOperationIntrinsic { return JsDescriptorUtils.isStandardDeclaration(functionDescriptor); } + @NotNull @Override public JsExpression apply(@NotNull JetBinaryExpression expression, @NotNull JsExpression left, diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/EqualsIntrinsic.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/EqualsIntrinsic.java index 81d223e349c..5f53c13acb6 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/EqualsIntrinsic.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/EqualsIntrinsic.java @@ -23,19 +23,20 @@ import org.jetbrains.jet.lang.psi.JetBinaryExpression; import org.jetbrains.jet.lang.types.expressions.OperatorConventions; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.k2js.translate.context.TranslationContext; +import org.jetbrains.k2js.translate.intrinsic.functions.factories.TopLevelFIF; +import org.jetbrains.k2js.translate.utils.JsAstUtils; import org.jetbrains.k2js.translate.utils.JsDescriptorUtils; +import java.util.Arrays; + import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression; -import static org.jetbrains.k2js.translate.utils.JsAstUtils.equality; -import static org.jetbrains.k2js.translate.utils.JsAstUtils.inequality; import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.isNullLiteral; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.nullCheck; /** * @author Pavel Talanov */ public final class EqualsIntrinsic implements BinaryOperationIntrinsic { + @Override public boolean isApplicable(@NotNull JetBinaryExpression expression, @NotNull TranslationContext context) { if (!OperatorConventions.EQUALS_OPERATIONS.contains(getOperationToken(expression))) { @@ -47,22 +48,13 @@ public final class EqualsIntrinsic implements BinaryOperationIntrinsic { } @Override + @NotNull public JsExpression apply(@NotNull JetBinaryExpression expression, @NotNull JsExpression left, @NotNull JsExpression right, @NotNull TranslationContext context) { boolean isNegated = getOperationToken(expression).equals(JetTokens.EXCLEQ); - if (isNullLiteral(context, right)) { - return nullCheck(context, left, !isNegated); - } - if (isNullLiteral(context, left)) { - return nullCheck(context, right, !isNegated); - } - if (isNegated) { - return inequality(left, right); - } - else { - return equality(left, right); - } + JsExpression result = TopLevelFIF.EQUALS.apply(left, Arrays.asList(right), context); + return isNegated ? JsAstUtils.negated(result) : result; } } diff --git a/js/js.translator/testFiles/expression/equals/cases/explicitEqualsMethod.kt b/js/js.translator/testFiles/expression/equals/cases/explicitEqualsMethod.kt index 273c9cd1370..7301668272a 100644 --- a/js/js.translator/testFiles/expression/equals/cases/explicitEqualsMethod.kt +++ b/js/js.translator/testFiles/expression/equals/cases/explicitEqualsMethod.kt @@ -9,8 +9,8 @@ class Foo(val name: String) { } } -fun callEqualsMethod(v1: Foo, v2: Foo): Boolean { - return v1.equals(v2) +class Bar() { + } fun box() : Boolean { @@ -18,7 +18,11 @@ fun box() : Boolean { val b = Foo("abc") val c = Foo("def") - if (!callEqualsMethod(a, b)) return false - if (callEqualsMethod(a, c)) return false + if (!(a equals b)) return false + if (a equals c) return false + if (Bar() equals Bar()) return false + val g = Bar() + if (!(g equals g)) return false + if (g equals Bar()) return false return true } \ No newline at end of file diff --git a/js/js.translator/testFiles/expression/equals/cases/explicitEqualsMethodForPrimitives.kt b/js/js.translator/testFiles/expression/equals/cases/explicitEqualsMethodForPrimitives.kt new file mode 100644 index 00000000000..e4abc8da6a8 --- /dev/null +++ b/js/js.translator/testFiles/expression/equals/cases/explicitEqualsMethodForPrimitives.kt @@ -0,0 +1,21 @@ +package foo + +fun box() : Boolean { + val a = 2 + if (!(a equals a)) return false + if (!(a equals 2)) return false + if (!(a equals 2.0)) return false + val c = "a" + if (!("a" equals c)) return false + if (!(null equals null)) return false + val d = 5.6 + if (!(d.toShort() equals 5.toShort())) return false + if (!(d.toByte() equals 5.toByte())) return false + if (!(d.toFloat() equals 5.6.toFloat())) return false + if (!(d.toInt() equals 5)) return false + if (true equals false) return false + + val n: Number = 3 + if (!(n equals 3.3.toInt())) return false + return true +} \ No newline at end of file diff --git a/js/js.translator/testFiles/kotlin_lib.js b/js/js.translator/testFiles/kotlin_lib.js index 899d6e2dcea..2558a20b3db 100644 --- a/js/js.translator/testFiles/kotlin_lib.js +++ b/js/js.translator/testFiles/kotlin_lib.js @@ -23,6 +23,7 @@ var kotlin = {set:function (receiver, key, value) { "use strict"; Kotlin.equals = function (obj1, obj2) { + if ((obj1 === null)|| (obj1 === undefined)) return obj2 === null; if (typeof obj1 == "object") { if (obj1.equals !== undefined) { return obj1.equals(obj2);