diff --git a/compiler/testData/codegen/box/primitiveTypes/conversions.kt b/compiler/testData/codegen/box/primitiveTypes/conversions.kt new file mode 100644 index 00000000000..a8521d51a0a --- /dev/null +++ b/compiler/testData/codegen/box/primitiveTypes/conversions.kt @@ -0,0 +1,56 @@ +// WITH_RUNTIME +import kotlin.test.assertEquals + +fun box(): String { + + assertEquals(-2147483648, Float.NEGATIVE_INFINITY.toInt()) + assertEquals(-2147483648, (-Float.MAX_VALUE).toInt()) + assertEquals(-1, (-1.9f).toInt()) + assertEquals(0, (-0.0f).toInt()) + assertEquals(0, (-Float.MIN_VALUE).toInt()) + assertEquals(0, 0.0f.toInt()) + assertEquals(0, Float.NaN.toInt()) + assertEquals(0, Float.MIN_VALUE.toInt()) + assertEquals(0, 0.9f.toInt()) + assertEquals(2147483647, Float.MAX_VALUE.toInt()) + assertEquals(2147483647, Float.POSITIVE_INFINITY.toInt()) + + assertEquals(-2147483648, Double.NEGATIVE_INFINITY.toInt()) + assertEquals(-2147483648, (-Double.MAX_VALUE).toInt()) + assertEquals(-2147483648, (-2147483649.0).toInt()) + assertEquals(-2147483648, (-2147483648.0).toInt()) + assertEquals(-2147483647, (-2147483647.9).toInt()) + assertEquals(-1, (-1.9).toInt()) + assertEquals(0, (-0.0).toInt()) + assertEquals(0, (-Double.MIN_VALUE).toInt()) + assertEquals(0, 0.0.toInt()) + assertEquals(0, Double.NaN.toInt()) + assertEquals(0, Double.MIN_VALUE.toInt()) + assertEquals(0, 0.9.toInt()) + assertEquals(2147483646, 2147483646.9.toInt()) + assertEquals(2147483647, 2147483647.0.toInt()) + assertEquals(2147483647, 2147483648.0.toInt()) + assertEquals(2147483647, Double.MAX_VALUE.toInt()) + assertEquals(2147483647, Double.POSITIVE_INFINITY.toInt()) + + for (d in doubleArrayOf(Double.NEGATIVE_INFINITY, -Double.MAX_VALUE, + -2147483649.0, -2147483648.0, -2147483647.0, + -65536.0, -65535.0, -65534.0, + -1.5, -Double.MIN_VALUE, + -0.0, 0.0, + Double.MIN_VALUE, 1.5, + 65534.0, 65535.0, 65536.0, + 2147483647.0, 2147483648.0, 2147483649.0, + Double.MAX_VALUE, Double.POSITIVE_INFINITY)) { + assertEquals(d.toInt().toByte(), d.toByte()) + assertEquals(d.toInt().toShort(), d.toShort()) + assertEquals(d.toInt().toChar(), d.toChar()) + + val f = d.toFloat() + assertEquals(f.toInt().toByte(), f.toByte()) + assertEquals(f.toInt().toShort(), f.toShort()) + assertEquals(f.toInt().toChar(), f.toChar()) + } + + return "OK" +} diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 22653ea8db8..ab19693dc42 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -12812,6 +12812,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("conversions.kt") + public void testConversions() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/conversions.kt"); + doTest(fileName); + } + @TestMetadata("ea35963.kt") public void testEa35963() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/ea35963.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 315ee959cfc..5e1f9130467 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -12812,6 +12812,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("conversions.kt") + public void testConversions() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/conversions.kt"); + doTest(fileName); + } + @TestMetadata("ea35963.kt") public void testEa35963() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/ea35963.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index da1836b3379..7a76830b088 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -12812,6 +12812,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("conversions.kt") + public void testConversions() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/conversions.kt"); + doTest(fileName); + } + @TestMetadata("ea35963.kt") public void testEa35963() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/ea35963.kt"); diff --git a/js/js.libraries/src/js/conversions.js b/js/js.libraries/src/js/conversions.js index 8e12ec10e1a..c11ed5e894c 100644 --- a/js/js.libraries/src/js/conversions.js +++ b/js/js.libraries/src/js/conversions.js @@ -31,7 +31,7 @@ Kotlin.numberToLong = function (a) { }; Kotlin.numberToInt = function (a) { - return a instanceof Kotlin.Long ? a.toInt() : (a | 0); + return a instanceof Kotlin.Long ? a.toInt() : Kotlin.doubleToInt(a); }; Kotlin.numberToShort = function (a) { @@ -50,6 +50,12 @@ Kotlin.numberToChar = function (a) { return Kotlin.toChar(Kotlin.numberToInt(a)); }; +Kotlin.doubleToInt = function(a) { + if (a > 2147483647) return 2147483647; + if (a < -2147483648) return -2147483648; + return a | 0; +}; + Kotlin.toBoxedChar = function (a) { if (a == null) return a; if (a instanceof Kotlin.BoxedChar) return a; diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index a66a0849ab2..c237a5f1c77 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -13994,6 +13994,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("conversions.kt") + public void testConversions() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/conversions.kt"); + doTest(fileName); + } + @TestMetadata("ea35963.kt") public void testEa35963() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/ea35963.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/NumberAndCharConversionFIF.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/NumberAndCharConversionFIF.kt index aa594bfee92..2f388328668 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/NumberAndCharConversionFIF.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/NumberAndCharConversionFIF.kt @@ -22,7 +22,10 @@ import org.jetbrains.kotlin.js.patterns.PatternBuilder.pattern import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsicWithReceiverComputed import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.* -import org.jetbrains.kotlin.utils.identity +import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.invokeKotlinFunction +import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.toByte +import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.toChar +import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.toShort import java.util.function.Predicate object NumberAndCharConversionFIF : CompositeFIF() { @@ -33,16 +36,18 @@ object NumberAndCharConversionFIF : CompositeFIF() { .or(pattern("Long.toLong")) .or(pattern("Char.toChar")) - private val convertOperations: Map = + private val convertOperations: Map = mapOf( - "Float|Double.toInt" to ConversionUnaryIntrinsic(::toInt32), - "Int|Float|Double.toShort" to ConversionUnaryIntrinsic(::toShort), - "Short|Int|Float|Double.toByte" to ConversionUnaryIntrinsic(::toByte), + "Float|Double.toInt" to ConversionUnaryIntrinsic { invokeKotlinFunction("numberToInt", it) }, + "Float|Double.toShort" to ConversionUnaryIntrinsic { toShort(invokeKotlinFunction("numberToInt", it)) }, + "Int.toShort" to ConversionUnaryIntrinsic { toShort(it) }, + "Float|Double.toByte" to ConversionUnaryIntrinsic { toByte(invokeKotlinFunction("numberToInt", it)) }, + "Short|Int.toByte" to ConversionUnaryIntrinsic { toByte(it) }, - "Int|Short|Byte.toLong" to ConversionUnaryIntrinsic(::longFromInt), - "Float|Double.toLong" to ConversionUnaryIntrinsic(::longFromNumber), + "Int|Short|Byte.toLong" to ConversionUnaryIntrinsic { longFromInt(it) }, + "Float|Double.toLong" to ConversionUnaryIntrinsic { longFromNumber(it) }, - "Char.toDouble|toFloat|toInt" to ConversionUnaryIntrinsic(::charToInt), + "Char.toDouble|toFloat|toInt" to ConversionUnaryIntrinsic { charToInt(it) }, "Char.toShort" to ConversionUnaryIntrinsic { toShort(charToInt(it)) }, "Char.toByte" to ConversionUnaryIntrinsic { toByte(charToInt(it)) }, "Char.toLong" to ConversionUnaryIntrinsic { longFromInt(charToInt(it)) }, @@ -54,7 +59,8 @@ object NumberAndCharConversionFIF : CompositeFIF() { "Number.toFloat|toDouble" to ConversionUnaryIntrinsic { invokeKotlinFunction("numberToDouble", it) }, "Number.toLong" to ConversionUnaryIntrinsic { invokeKotlinFunction("numberToLong", it) }, - "Int|Short|Byte|Float|Double.toChar" to ConversionUnaryIntrinsic(::toChar), + "Float|Double.toChar" to ConversionUnaryIntrinsic { toChar(invokeKotlinFunction("numberToInt", it)) }, + "Int|Short|Byte.toChar" to ConversionUnaryIntrinsic { toChar(it) }, "Long.toFloat|toDouble" to ConversionUnaryIntrinsic { invokeMethod(it, "toNumber") }, "Long.toInt" to ConversionUnaryIntrinsic { invokeMethod(it, "toInt") }, @@ -64,16 +70,16 @@ object NumberAndCharConversionFIF : CompositeFIF() { ) - class ConversionUnaryIntrinsic(val applyFun: (receiver: JsExpression) -> JsExpression) : FunctionIntrinsicWithReceiverComputed() { + class ConversionUnaryIntrinsic(val applyFun: TranslationContext.(receiver: JsExpression) -> JsExpression) : FunctionIntrinsicWithReceiverComputed() { override fun apply(receiver: JsExpression?, arguments: List, context: TranslationContext): JsExpression { assert(receiver != null) assert(arguments.isEmpty()) - return applyFun(receiver!!) + return context.applyFun(receiver!!) } } init { - add(USE_AS_IS, ConversionUnaryIntrinsic(identity())) + add(USE_AS_IS, ConversionUnaryIntrinsic { it }) for((stringPattern, intrinsic) in convertOperations) { add(pattern(stringPattern), intrinsic) } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java index 9d558b993ca..7d2f7d4e925 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntri import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.RangeToIntrinsic; import org.jetbrains.kotlin.js.translate.operation.OperatorTable; import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; +import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.AstUtilsKt; import org.jetbrains.kotlin.lexer.KtToken; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.types.expressions.OperatorConventions; @@ -283,7 +284,7 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory { @NotNull @Override public JsExpression doApply(@NotNull JsExpression left, @NotNull JsExpression right, @NotNull TranslationContext context) { - return JsAstUtils.toChar(functionIntrinsic.doApply(left, right, context)); + return AstUtilsKt.toChar(context, functionIntrinsic.doApply(left, right, context)); } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/PrimitiveUnaryOperationFIF.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/PrimitiveUnaryOperationFIF.java index 8ef26dbfad3..95e94faad97 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/PrimitiveUnaryOperationFIF.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/PrimitiveUnaryOperationFIF.java @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntri import org.jetbrains.kotlin.js.translate.operation.OperatorTable; import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils; +import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.AstUtilsKt; import org.jetbrains.kotlin.lexer.KtToken; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.types.expressions.OperatorConventions; @@ -99,7 +100,7 @@ public enum PrimitiveUnaryOperationFIF implements FunctionIntrinsicFactory { @NotNull List arguments, @NotNull TranslationContext context ) { - return JsAstUtils.toShort(underlyingIntrinsic.apply(receiver, arguments, context)); + return AstUtilsKt.toShort(context, underlyingIntrinsic.apply(receiver, arguments, context)); } } @@ -117,7 +118,7 @@ public enum PrimitiveUnaryOperationFIF implements FunctionIntrinsicFactory { @NotNull List arguments, @NotNull TranslationContext context ) { - return JsAstUtils.toByte(underlyingIntrinsic.apply(receiver, arguments, context)); + return AstUtilsKt.toByte(context, underlyingIntrinsic.apply(receiver, arguments, context)); } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java index 7a0eac82c8b..678fd9296c1 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java @@ -26,7 +26,6 @@ import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties; import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind; import org.jetbrains.kotlin.js.translate.context.Namer; import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt; -import org.jetbrains.kotlin.types.expressions.OperatorConventions; import org.jetbrains.kotlin.util.OperatorNameConventions; import java.util.Collections; @@ -157,26 +156,6 @@ public final class JsAstUtils { return new JsInvocation(new JsNameRef("fromCharCode", new JsNameRef("String")), expression); } - @NotNull - public static JsExpression toShort(@NotNull JsExpression expression) { - return invokeKotlinFunction(OperatorConventions.SHORT.getIdentifier(), expression); - } - - @NotNull - public static JsExpression toByte(@NotNull JsExpression expression) { - return invokeKotlinFunction(OperatorConventions.BYTE.getIdentifier(), expression); - } - - @NotNull - public static JsExpression toLong(@NotNull JsExpression expression) { - return invokeKotlinFunction(OperatorConventions.LONG.getIdentifier(), expression); - } - - @NotNull - public static JsExpression toChar(@NotNull JsExpression expression) { - return invokeKotlinFunction(OperatorConventions.CHAR.getIdentifier(), expression); - } - @NotNull public static JsExpression compareTo(@NotNull JsExpression left, @NotNull JsExpression right) { return invokeKotlinFunction(OperatorNameConventions.COMPARE_TO.getIdentifier(), left, right); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/astUtils.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/astUtils.kt index d95028a21b3..f76a55219d5 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/astUtils.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/astUtils.kt @@ -18,6 +18,8 @@ package org.jetbrains.kotlin.js.translate.utils.jsAstUtils import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.translate.context.Namer +import org.jetbrains.kotlin.js.translate.context.TranslationContext +import org.jetbrains.kotlin.types.expressions.OperatorConventions fun JsFunction.addStatement(stmt: JsStatement) { body.statements.add(stmt) @@ -103,3 +105,15 @@ var JsConditional.then: JsExpression var JsConditional.otherwise: JsExpression get() = elseExpression set(value) { elseExpression = value } + +// Extension functions below produce aliased invocations. +fun TranslationContext.invokeKotlinFunction(functionName: String, vararg arguments: JsExpression) + = JsInvocation(getReferenceToIntrinsic(functionName), arguments.toList()) + +fun TranslationContext.toByte(expression: JsExpression) = invokeKotlinFunction(OperatorConventions.BYTE.identifier, expression) + +fun TranslationContext.toShort(expression: JsExpression) = invokeKotlinFunction(OperatorConventions.SHORT.identifier, expression) + +fun TranslationContext.toChar(expression: JsExpression) = invokeKotlinFunction(OperatorConventions.CHAR.identifier, expression) + +fun TranslationContext.toLong(expression: JsExpression) = invokeKotlinFunction(OperatorConventions.LONG.identifier, expression) \ No newline at end of file diff --git a/js/js.translator/testData/box/incremental/jsModule.kt b/js/js.translator/testData/box/incremental/jsModule.kt index 7904eb29357..1e211e9ff89 100644 --- a/js/js.translator/testData/box/incremental/jsModule.kt +++ b/js/js.translator/testData/box/incremental/jsModule.kt @@ -1,4 +1,4 @@ -// EXPECTED_REACHABLE_NODES: 1018 +// EXPECTED_REACHABLE_NODES: 1126 // MODULE: lib // FILE: a.kt diff --git a/js/js.translator/testData/box/inlineSizeReduction/multiModuleDefaultArgsCleanup.kt b/js/js.translator/testData/box/inlineSizeReduction/multiModuleDefaultArgsCleanup.kt index 303d60680b7..6953d304c7c 100644 --- a/js/js.translator/testData/box/inlineSizeReduction/multiModuleDefaultArgsCleanup.kt +++ b/js/js.translator/testData/box/inlineSizeReduction/multiModuleDefaultArgsCleanup.kt @@ -1,4 +1,4 @@ -// EXPECTED_REACHABLE_NODES: 1018 +// EXPECTED_REACHABLE_NODES: 1124 // MODULE: lib // FILE: lib.kt inline fun foo(x: String = "x", y: String = "y") = x + y