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 7ebe4de9adf..d9ad7e54983 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 @@ -30,6 +30,10 @@ public final class EqualsTest extends AbstractExpressionTest { fooBoxTest(); } + public void testExplicitEqualsMethod() throws Exception { + fooBoxTest(); + } + public void testStringsEqual() throws Exception { fooBoxTest(); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/Intrinsics.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/Intrinsics.java index 2d54401d80b..2373c6254ef 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/Intrinsics.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/Intrinsics.java @@ -56,15 +56,15 @@ public final class Intrinsics { @NotNull private final Map functionIntrinsics = - new HashMap(); + new HashMap(); @NotNull private final Map equalsIntrinsics = - new HashMap(); + new HashMap(); @NotNull private final Map compareToIntrinsics = - new HashMap(); + new HashMap(); @NotNull private final Intrinsic lengthPropertyIntrinsic = new BuiltInPropertyIntrinsic("length"); @@ -147,7 +147,7 @@ public final class Intrinsics { FunctionDescriptor iteratorFunction = getFunctionByName(arrayMemberScope, Name.identifier("iterator")); functionIntrinsics.put(iteratorFunction, new CallStandardMethodIntrinsic("Kotlin.arrayIterator", true, 0)); ConstructorDescriptor arrayConstructor = - ((ClassDescriptor)arrayMemberScope.getContainingDeclaration()).getConstructors().iterator().next(); + ((ClassDescriptor) arrayMemberScope.getContainingDeclaration()).getConstructors().iterator().next(); functionIntrinsics.put(arrayConstructor, new CallStandardMethodIntrinsic("Kotlin.arrayFromFun", false, 2)); } @@ -171,22 +171,22 @@ public final class Intrinsics { private void declareStringIntrinsics() { //TODO: same intrinsic for 2 different methods PropertyDescriptor stringLengthProperty = - getPropertyByName(library.getString().getDefaultType().getMemberScope(), Name.identifier("length")); + getPropertyByName(library.getString().getDefaultType().getMemberScope(), Name.identifier("length")); functionIntrinsics.put(stringLengthProperty.getGetter(), lengthPropertyIntrinsic); PropertyDescriptor charSequenceLengthProperty = - getPropertyByName(library.getCharSequence().getDefaultType().getMemberScope(), Name.identifier("length")); + getPropertyByName(library.getCharSequence().getDefaultType().getMemberScope(), Name.identifier("length")); functionIntrinsics.put(charSequenceLengthProperty.getGetter(), lengthPropertyIntrinsic); FunctionDescriptor getFunction = - getFunctionByName(library.getString().getDefaultType().getMemberScope(), Name.identifier("get")); + getFunctionByName(library.getString().getDefaultType().getMemberScope(), Name.identifier("get")); functionIntrinsics.put(getFunction, CharAtIntrinsic.INSTANCE); } private void declareTupleIntrinsicAccessors(@NotNull ClassifierDescriptor tupleDescriptor, - int tupleSize) { + int tupleSize) { for (int elementIndex = 0; elementIndex < tupleSize; ++elementIndex) { Name accessorName = Name.identifier("_" + (elementIndex + 1)); PropertyDescriptor propertyDescriptor = - getPropertyByName(tupleDescriptor.getDefaultType().getMemberScope(), accessorName); + getPropertyByName(tupleDescriptor.getDefaultType().getMemberScope(), accessorName); functionIntrinsics.put(propertyDescriptor.getGetter(), new TupleAccessIntrinsic(elementIndex)); } } @@ -202,7 +202,7 @@ public final class Intrinsics { public boolean isIntrinsic(@NotNull DeclarationDescriptor descriptor) { //NOTE: that if we want to add other intrinsics we have to modify this method if (descriptor instanceof FunctionDescriptor) { - FunctionDescriptor functionDescriptor = (FunctionDescriptor)descriptor.getOriginal(); + FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor.getOriginal(); return (equalsIntrinsics.containsKey(functionDescriptor) || compareToIntrinsics.containsKey(functionDescriptor) || functionIntrinsics.containsKey(functionDescriptor)); @@ -210,9 +210,17 @@ public final class Intrinsics { return false; } + //NOTE: that if we want to add other intrinsics we have to modify this method @NotNull - public Intrinsic getFunctionIntrinsic(@NotNull FunctionDescriptor descriptor) { - return functionIntrinsics.get(descriptor.getOriginal()); + public Intrinsic getIntrinsic(@NotNull FunctionDescriptor descriptor) { + Intrinsic intrinsic = functionIntrinsics.get(descriptor.getOriginal()); + if (intrinsic == null) { + intrinsic = equalsIntrinsics.get(descriptor.getOriginal()); + } + if (intrinsic == null) { + intrinsic = compareToIntrinsics.get(descriptor.getOriginal()); + } + return intrinsic; } @NotNull @@ -231,7 +239,7 @@ public final class Intrinsics { @Override public Void visitClassDescriptor(@NotNull ClassDescriptor descriptor, @Nullable Void nothing) { for (DeclarationDescriptor memberDescriptor : - descriptor.getDefaultType().getMemberScope().getAllDescriptors()) { + descriptor.getDefaultType().getMemberScope().getAllDescriptors()) { //noinspection NullableProblems memberDescriptor.accept(this, null); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java index 1ca078f5d6d..c5f582fa829 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java @@ -126,7 +126,7 @@ public final class CallTranslator extends AbstractTranslator { private JsExpression intrinsicInvocation() { assert descriptor instanceof FunctionDescriptor; try { - Intrinsic intrinsic = context().intrinsics().getFunctionIntrinsic((FunctionDescriptor) descriptor); + Intrinsic intrinsic = context().intrinsics().getIntrinsic((FunctionDescriptor) descriptor); return intrinsic.apply(callParameters.getThisOrReceiverOrNull(), arguments, context()); } catch (RuntimeException e) { diff --git a/js/js.translator/testFiles/expression/equals/cases/explicitEqualsMethod.kt b/js/js.translator/testFiles/expression/equals/cases/explicitEqualsMethod.kt new file mode 100644 index 00000000000..273c9cd1370 --- /dev/null +++ b/js/js.translator/testFiles/expression/equals/cases/explicitEqualsMethod.kt @@ -0,0 +1,24 @@ +package foo + +class Foo(val name: String) { + public fun equals(that: Any?): Boolean { + if (that !is Foo) { + return false + } + return this.name == that.name + } +} + +fun callEqualsMethod(v1: Foo, v2: Foo): Boolean { + return v1.equals(v2) +} + +fun box() : Boolean { + val a = Foo("abc") + val b = Foo("abc") + val c = Foo("def") + + if (!callEqualsMethod(a, b)) return false + if (callEqualsMethod(a, c)) return false + return true +} \ No newline at end of file