From a632e9e21d224cd6eefc4ba51202284c6ea990d1 Mon Sep 17 00:00:00 2001 From: Michael Nedzelsky Date: Sat, 6 Sep 2014 11:38:05 +0400 Subject: [PATCH] JS backend: fix KT-4601 JS: compareTo doesn't work on Numbers #KT-4601 Fixed --- .../k2js/test/semantics/NumberTest.java | 4 ++ .../PrimitiveBinaryOperationFIF.java | 26 +++++++- .../k2js/translate/utils/JsAstUtils.java | 16 +++++ js/js.translator/testData/kotlin_lib.js | 4 ++ .../testData/number/cases/numberCompareTo.kt | 60 +++++++++++++++++++ 5 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 js/js.translator/testData/number/cases/numberCompareTo.kt diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/NumberTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/NumberTest.java index 4a05a7dc8e6..88a1327432a 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/NumberTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/NumberTest.java @@ -65,4 +65,8 @@ public final class NumberTest extends SingleFileTranslationTest { Assert.assertTrue(cause.getMessage().startsWith("Unsupported long constant ")); } } + + public void testNumberCompareTo() throws Exception { + checkFooBoxIsOk(); + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java index dd8eeb72853..0785fb21a15 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java @@ -39,7 +39,7 @@ import java.util.List; import static org.jetbrains.k2js.translate.intrinsic.functions.factories.NumberConversionFIF.INTEGER_NUMBER_TYPES; import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern; -import static org.jetbrains.k2js.translate.utils.JsAstUtils.setArguments; +import static org.jetbrains.k2js.translate.utils.JsAstUtils.*; public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory { INSTANCE; @@ -76,9 +76,26 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory { } }; + @NotNull + private static final FunctionIntrinsic NUMBER_COMPARE_TO_INTRINSIC = new FunctionIntrinsic() { + @NotNull + @Override + public JsExpression apply( + @Nullable JsExpression receiver, + @NotNull List arguments, + @NotNull TranslationContext context + ) { + assert receiver != null; + assert arguments.size() == 1; + return JsAstUtils.compareTo(receiver, arguments.get(0), context); + } + }; + @NotNull private static final NamePredicate BINARY_OPERATIONS = new NamePredicate(OperatorConventions.BINARY_OPERATION_NAMES.values()); private static final DescriptorPredicate PRIMITIVE_NUMBERS_BINARY_OPERATIONS = pattern(NamePredicate.PRIMITIVE_NUMBERS, BINARY_OPERATIONS); + private static final DescriptorPredicate PRIMITIVE_NUMBERS_COMPARE_TO_OPERATIONS = + pattern(NamePredicate.PRIMITIVE_NUMBERS, "compareTo"); private static final DescriptorPredicate INT_WITH_BIT_OPERATIONS = pattern("Int.or|and|xor|shl|shr|ushr"); private static final DescriptorPredicate BOOLEAN_OPERATIONS = pattern("Boolean.or|and|xor"); private static final DescriptorPredicate STRING_PLUS = pattern("String.plus"); @@ -93,7 +110,8 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory { .build(); private static final Predicate PREDICATE = Predicates.or(PRIMITIVE_NUMBERS_BINARY_OPERATIONS, BOOLEAN_OPERATIONS, - STRING_PLUS, INT_WITH_BIT_OPERATIONS); + STRING_PLUS, INT_WITH_BIT_OPERATIONS, + PRIMITIVE_NUMBERS_COMPARE_TO_OPERATIONS); @Nullable @Override @@ -102,6 +120,10 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory { return null; } + if (PRIMITIVE_NUMBERS_COMPARE_TO_OPERATIONS.apply(descriptor)) { + return NUMBER_COMPARE_TO_INTRINSIC; + } + if (pattern(INTEGER_NUMBER_TYPES + ".div").apply(descriptor)) { JetType resultType = descriptor.getReturnType(); if (!KotlinBuiltIns.getInstance().getFloatType().equals(resultType) && diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java index a6a64f4bbaf..3c6e84c126d 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java @@ -20,6 +20,7 @@ import com.google.dart.compiler.backend.js.ast.*; import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.types.expressions.OperatorConventions; import org.jetbrains.k2js.translate.context.Namer; import org.jetbrains.k2js.translate.context.TranslationContext; @@ -122,6 +123,11 @@ public final class JsAstUtils { return new JsBinaryOperation(JsBinaryOperator.BIT_OR, expression, context.program().getNumberLiteral(0)); } + @NotNull + public static JsExpression compareTo(@NotNull JsExpression left, @NotNull JsExpression right) { + return new JsInvocation(new JsNameRef(OperatorConventions.COMPARE_TO.getIdentifier(), Namer.KOTLIN_OBJECT_REF), left, right); + } + @NotNull public static JsPrefixOperation negated(@NotNull JsExpression expression) { return new JsPrefixOperation(JsUnaryOperator.NOT, expression); @@ -171,6 +177,16 @@ public final class JsAstUtils { return new JsBinaryOperation(JsBinaryOperator.LTE, arg1, arg2); } + @NotNull + public static JsBinaryOperation lessThan(@NotNull JsExpression arg1, @NotNull JsExpression arg2) { + return new JsBinaryOperation(JsBinaryOperator.LT, arg1, arg2); + } + + @NotNull + public static JsBinaryOperation greaterThan(@NotNull JsExpression arg1, @NotNull JsExpression arg2) { + return new JsBinaryOperation(JsBinaryOperator.GT, arg1, arg2); + } + @NotNull public static JsExpression assignment(@NotNull JsExpression left, @NotNull JsExpression right) { return new JsBinaryOperation(JsBinaryOperator.ASG, left, right); diff --git a/js/js.translator/testData/kotlin_lib.js b/js/js.translator/testData/kotlin_lib.js index acfac5fbfb2..6b4ddc95761 100644 --- a/js/js.translator/testData/kotlin_lib.js +++ b/js/js.translator/testData/kotlin_lib.js @@ -85,6 +85,10 @@ return "[" + a.join(", ") + "]"; }; + Kotlin.compareTo = function(a, b) { + return a < b ? -1 : a > b ? 1 : 0; + }; + Kotlin.intUpto = function (from, to) { return new Kotlin.NumberRange(from, to); }; diff --git a/js/js.translator/testData/number/cases/numberCompareTo.kt b/js/js.translator/testData/number/cases/numberCompareTo.kt new file mode 100644 index 00000000000..4b64ce4b1fa --- /dev/null +++ b/js/js.translator/testData/number/cases/numberCompareTo.kt @@ -0,0 +1,60 @@ +package foo + +var global: String = "" + +fun id(s: String, value: Int): Int { + global += s + return value +} + +fun box(): String { + + assertEquals(-1, 1.compareTo(2)) + + assertEquals(-1, 1 compareTo 2) + assertEquals(-1, 1 compareTo (2:Short)) + assertEquals(-1, 1 compareTo (2:Byte)) + assertEquals(-1, 1 compareTo 2.0) + assertEquals(-1, 1 compareTo 2.0f) + + assertEquals(1, 10 compareTo 2) + assertEquals(1, 10 compareTo (2:Short)) + assertEquals(1, 10 compareTo (2:Byte)) + assertEquals(1, 10 compareTo 2.0) + assertEquals(1, 10 compareTo 2.0f) + + assertEquals(0, 2 compareTo 2) + assertEquals(0, 2 compareTo (2:Short)) + assertEquals(0, 2 compareTo (2:Byte)) + assertEquals(0, 2 compareTo 2.0) + assertEquals(0, 2 compareTo 2.0f) + + assertEquals(-1, (1: Short) compareTo 2) + assertEquals(-1, (1: Short) compareTo (2:Short)) + assertEquals(-1, (1: Short) compareTo (2:Byte)) + assertEquals(-1, (1: Short) compareTo 2.0) + assertEquals(-1, (1: Short) compareTo 2.0f) + + assertEquals(1, (10: Byte) compareTo 2) + assertEquals(1, (10: Byte) compareTo (2:Short)) + assertEquals(1, (10: Byte) compareTo (2:Byte)) + assertEquals(1, (10: Byte) compareTo 2.0) + assertEquals(1, (10: Byte) compareTo 2.0f) + + assertEquals(0, 2.0 compareTo 2) + assertEquals(0, 2.0 compareTo (2:Short)) + assertEquals(0, 2.0 compareTo (2:Byte)) + assertEquals(0, 2.0 compareTo 2.0) + assertEquals(0, 2.0 compareTo 2.0f) + + assertEquals(1, 3.0f compareTo 2) + assertEquals(1, 3.0f compareTo (2:Short)) + assertEquals(1, 3.0f compareTo (2:Byte)) + assertEquals(1, 3.0f compareTo 2.0) + assertEquals(1, 3.0f compareTo 2.0f) + + assertEquals(1, id("A", 10) compareTo id("B", 5)) + assertEquals("AB", global) + + return "OK" +} \ No newline at end of file