Explicit equals method for primitives and correct global equals method.

Includes cosmetics.
#KT-2372 Fixed
This commit is contained in:
Pavel V. Talanov
2012-07-18 17:15:27 +04:00
parent e0651de9ed
commit b45c14b0ab
9 changed files with 52 additions and 28 deletions
@@ -22,7 +22,7 @@ public final class EqualsTest extends AbstractExpressionTest {
super("equals/"); super("equals/");
} }
public void TODO_testCustomEqualsMethodOnAny() throws Exception { public void testCustomEqualsMethodOnAny() throws Exception {
fooBoxTest(); fooBoxTest();
} }
@@ -34,6 +34,10 @@ public final class EqualsTest extends AbstractExpressionTest {
fooBoxTest(); fooBoxTest();
} }
public void testExplicitEqualsMethodForPrimitives() throws Exception {
fooBoxTest();
}
public void testStringsEqual() throws Exception { public void testStringsEqual() throws Exception {
fooBoxTest(); fooBoxTest();
} }
@@ -19,7 +19,7 @@ package org.jetbrains.k2js.translate.intrinsic.functions.factories;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.k2js.translate.intrinsic.functions.basic.BuiltInFunctionIntrinsic; 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.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; 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 * @author Pavel Talanov
*/ */
public final class TopLevelFIF extends CompositeFIF { public final class TopLevelFIF extends CompositeFIF {
@NotNull @NotNull
private static final DescriptorPredicate EXT_TO_STRING = pattern("toString"); public static final CallStandardMethodIntrinsic EQUALS = new CallStandardMethodIntrinsic("Kotlin.equals", true, 1);
@NotNull @NotNull
public static final FunctionIntrinsicFactory INSTANCE = new TopLevelFIF(); public static final FunctionIntrinsicFactory INSTANCE = new TopLevelFIF();
private TopLevelFIF() { private TopLevelFIF() {
add(EXT_TO_STRING, new BuiltInFunctionIntrinsic("toString")); add(pattern("toString"), new BuiltInFunctionIntrinsic("toString"));
//TODO: add intrinsic for calling equals explicitly 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)); add(pattern("arrayOfNulls"), new CallStandardMethodIntrinsic("Kotlin.nullArray", false, 1));
} }
} }
@@ -32,7 +32,7 @@ import java.util.List;
public final class NamePredicate implements Predicate<Name> { public final class NamePredicate implements Predicate<Name> {
@NotNull @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 @NotNull
private final List<Name> validNames = Lists.newArrayList(); private final List<Name> validNames = Lists.newArrayList();
@@ -28,6 +28,7 @@ public interface BinaryOperationIntrinsic {
boolean isApplicable(@NotNull JetBinaryExpression expression, @NotNull TranslationContext context); boolean isApplicable(@NotNull JetBinaryExpression expression, @NotNull TranslationContext context);
@NotNull
JsExpression apply(@NotNull JetBinaryExpression expression, @NotNull JsExpression left, JsExpression apply(@NotNull JetBinaryExpression expression, @NotNull JsExpression left,
@NotNull JsExpression right, @NotNull TranslationContext context); @NotNull JsExpression right, @NotNull TranslationContext context);
} }
@@ -44,6 +44,7 @@ public final class CompareToInstrinsic implements BinaryOperationIntrinsic {
return JsDescriptorUtils.isStandardDeclaration(functionDescriptor); return JsDescriptorUtils.isStandardDeclaration(functionDescriptor);
} }
@NotNull
@Override @Override
public JsExpression apply(@NotNull JetBinaryExpression expression, public JsExpression apply(@NotNull JetBinaryExpression expression,
@NotNull JsExpression left, @NotNull JsExpression left,
@@ -23,19 +23,20 @@ import org.jetbrains.jet.lang.psi.JetBinaryExpression;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions; import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.k2js.translate.context.TranslationContext; 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 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.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.PsiUtils.getOperationToken;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.isNullLiteral;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.nullCheck;
/** /**
* @author Pavel Talanov * @author Pavel Talanov
*/ */
public final class EqualsIntrinsic implements BinaryOperationIntrinsic { public final class EqualsIntrinsic implements BinaryOperationIntrinsic {
@Override @Override
public boolean isApplicable(@NotNull JetBinaryExpression expression, @NotNull TranslationContext context) { public boolean isApplicable(@NotNull JetBinaryExpression expression, @NotNull TranslationContext context) {
if (!OperatorConventions.EQUALS_OPERATIONS.contains(getOperationToken(expression))) { if (!OperatorConventions.EQUALS_OPERATIONS.contains(getOperationToken(expression))) {
@@ -47,22 +48,13 @@ public final class EqualsIntrinsic implements BinaryOperationIntrinsic {
} }
@Override @Override
@NotNull
public JsExpression apply(@NotNull JetBinaryExpression expression, public JsExpression apply(@NotNull JetBinaryExpression expression,
@NotNull JsExpression left, @NotNull JsExpression left,
@NotNull JsExpression right, @NotNull JsExpression right,
@NotNull TranslationContext context) { @NotNull TranslationContext context) {
boolean isNegated = getOperationToken(expression).equals(JetTokens.EXCLEQ); boolean isNegated = getOperationToken(expression).equals(JetTokens.EXCLEQ);
if (isNullLiteral(context, right)) { JsExpression result = TopLevelFIF.EQUALS.apply(left, Arrays.asList(right), context);
return nullCheck(context, left, !isNegated); return isNegated ? JsAstUtils.negated(result) : result;
}
if (isNullLiteral(context, left)) {
return nullCheck(context, right, !isNegated);
}
if (isNegated) {
return inequality(left, right);
}
else {
return equality(left, right);
}
} }
} }
@@ -9,8 +9,8 @@ class Foo(val name: String) {
} }
} }
fun callEqualsMethod(v1: Foo, v2: Foo): Boolean { class Bar() {
return v1.equals(v2)
} }
fun box() : Boolean { fun box() : Boolean {
@@ -18,7 +18,11 @@ fun box() : Boolean {
val b = Foo("abc") val b = Foo("abc")
val c = Foo("def") val c = Foo("def")
if (!callEqualsMethod(a, b)) return false if (!(a equals b)) return false
if (callEqualsMethod(a, c)) 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 return true
} }
@@ -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
}
+1
View File
@@ -23,6 +23,7 @@ var kotlin = {set:function (receiver, key, value) {
"use strict"; "use strict";
Kotlin.equals = function (obj1, obj2) { Kotlin.equals = function (obj1, obj2) {
if ((obj1 === null)|| (obj1 === undefined)) return obj2 === null;
if (typeof obj1 == "object") { if (typeof obj1 == "object") {
if (obj1.equals !== undefined) { if (obj1.equals !== undefined) {
return obj1.equals(obj2); return obj1.equals(obj2);