From 1203df7405ae26dac12b2c03cdf51fac59028d73 Mon Sep 17 00:00:00 2001 From: Abduqodiri Qurbonzoda Date: Fri, 17 Jan 2020 06:07:49 +0300 Subject: [PATCH] Deprecate floating point to integral types lesser than Int #KT-30360 --- .../fir/resolve/testData/builtIns/kotlin.txt | 8 +- .../evaluate/OperationsMapGenerated.kt | 2 +- .../builtin-classes/default/kotlin.txt | 8 +- .../testData/builtin-classes/java6/kotlin.txt | 8 +- .../testData/builtin-classes/java8/kotlin.txt | 8 +- .../builtin-classes/newMethods/kotlin.txt | 8 +- .../pseudocodeMemoryOverhead.kt | 8 +- core/builtins/native/kotlin/Primitives.kt | 4 + generators/builtins/primitives.kt | 9 + generators/evaluate/GenerateOperationsMap.kt | 3 +- .../stdlib/common/src/generated/_Ranges.kt | 8 +- libraries/stdlib/js-ir/builtins/Primitives.kt | 205 ++++++++++++++++++ .../stdlib/test/collections/ArraysTest.kt | 2 +- .../kotlin-stdlib-gen/src/templates/Ranges.kt | 6 +- 14 files changed, 255 insertions(+), 32 deletions(-) diff --git a/compiler/fir/resolve/testData/builtIns/kotlin.txt b/compiler/fir/resolve/testData/builtIns/kotlin.txt index 98b4b459925..62f680ea9ce 100644 --- a/compiler/fir/resolve/testData/builtIns/kotlin.txt +++ b/compiler/fir/resolve/testData/builtIns/kotlin.txt @@ -459,7 +459,7 @@ public final class Double : R|kotlin/Number|, R|kotlin/Comparable public final operator fun times(other: R|kotlin/Short|): R|kotlin/Double| - public open fun toByte(): R|kotlin/Byte| + @R|kotlin/Deprecated|(message = String(Unclear conversion. To achieve the same result convert to Int explicitly and then to Byte.), replaceWith = @R|kotlin/ReplaceWith|(expression = String(toInt().toByte()))) public open fun toByte(): R|kotlin/Byte| public open fun toChar(): R|kotlin/Char| @@ -471,7 +471,7 @@ public final class Double : R|kotlin/Number|, R|kotlin/Comparable public open fun toLong(): R|kotlin/Long| - public open fun toShort(): R|kotlin/Short| + @R|kotlin/Deprecated|(message = String(Unclear conversion. To achieve the same result convert to Int explicitly and then to Short.), replaceWith = @R|kotlin/ReplaceWith|(expression = String(toInt().toShort()))) public open fun toShort(): R|kotlin/Short| public final operator fun unaryMinus(): R|kotlin/Double| @@ -642,7 +642,7 @@ public final class Float : R|kotlin/Number|, R|kotlin/Comparable| public final operator fun times(other: R|kotlin/Short|): R|kotlin/Float| - public open fun toByte(): R|kotlin/Byte| + @R|kotlin/Deprecated|(message = String(Unclear conversion. To achieve the same result convert to Int explicitly and then to Byte.), replaceWith = @R|kotlin/ReplaceWith|(expression = String(toInt().toByte()))) public open fun toByte(): R|kotlin/Byte| public open fun toChar(): R|kotlin/Char| @@ -654,7 +654,7 @@ public final class Float : R|kotlin/Number|, R|kotlin/Comparable| public open fun toLong(): R|kotlin/Long| - public open fun toShort(): R|kotlin/Short| + @R|kotlin/Deprecated|(message = String(Unclear conversion. To achieve the same result convert to Int explicitly and then to Short.), replaceWith = @R|kotlin/ReplaceWith|(expression = String(toInt().toShort()))) public open fun toShort(): R|kotlin/Short| public final operator fun unaryMinus(): R|kotlin/Float| diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/OperationsMapGenerated.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/OperationsMapGenerated.kt index 8d4a5c24b13..58309fa6d85 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/OperationsMapGenerated.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/OperationsMapGenerated.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -@file:Suppress("DEPRECATION_ERROR") +@file:Suppress("DEPRECATION", "DEPRECATION_ERROR") package org.jetbrains.kotlin.resolve.constants.evaluate diff --git a/compiler/testData/builtin-classes/default/kotlin.txt b/compiler/testData/builtin-classes/default/kotlin.txt index f1167e045bf..307d110af0e 100644 --- a/compiler/testData/builtin-classes/default/kotlin.txt +++ b/compiler/testData/builtin-classes/default/kotlin.txt @@ -277,13 +277,13 @@ public final class Double : kotlin.Number, kotlin.Comparable { public final operator fun times(/*0*/ other: kotlin.Int): kotlin.Double public final operator fun times(/*0*/ other: kotlin.Long): kotlin.Double public final operator fun times(/*0*/ other: kotlin.Short): kotlin.Double - public open override /*1*/ fun toByte(): kotlin.Byte + @kotlin.Deprecated(message = "Unclear conversion. To achieve the same result convert to Int explicitly and then to Byte.", replaceWith = kotlin.ReplaceWith(expression = "toInt().toByte()", imports = {})) public open override /*1*/ fun toByte(): kotlin.Byte public open override /*1*/ fun toChar(): kotlin.Char public open override /*1*/ fun toDouble(): kotlin.Double public open override /*1*/ fun toFloat(): kotlin.Float public open override /*1*/ fun toInt(): kotlin.Int public open override /*1*/ fun toLong(): kotlin.Long - public open override /*1*/ fun toShort(): kotlin.Short + @kotlin.Deprecated(message = "Unclear conversion. To achieve the same result convert to Int explicitly and then to Short.", replaceWith = kotlin.ReplaceWith(expression = "toInt().toShort()", imports = {})) public open override /*1*/ fun toShort(): kotlin.Short public final operator fun unaryMinus(): kotlin.Double public final operator fun unaryPlus(): kotlin.Double @@ -380,13 +380,13 @@ public final class Float : kotlin.Number, kotlin.Comparable { public final operator fun times(/*0*/ other: kotlin.Int): kotlin.Float public final operator fun times(/*0*/ other: kotlin.Long): kotlin.Float public final operator fun times(/*0*/ other: kotlin.Short): kotlin.Float - public open override /*1*/ fun toByte(): kotlin.Byte + @kotlin.Deprecated(message = "Unclear conversion. To achieve the same result convert to Int explicitly and then to Byte.", replaceWith = kotlin.ReplaceWith(expression = "toInt().toByte()", imports = {})) public open override /*1*/ fun toByte(): kotlin.Byte public open override /*1*/ fun toChar(): kotlin.Char public open override /*1*/ fun toDouble(): kotlin.Double public open override /*1*/ fun toFloat(): kotlin.Float public open override /*1*/ fun toInt(): kotlin.Int public open override /*1*/ fun toLong(): kotlin.Long - public open override /*1*/ fun toShort(): kotlin.Short + @kotlin.Deprecated(message = "Unclear conversion. To achieve the same result convert to Int explicitly and then to Short.", replaceWith = kotlin.ReplaceWith(expression = "toInt().toShort()", imports = {})) public open override /*1*/ fun toShort(): kotlin.Short public final operator fun unaryMinus(): kotlin.Float public final operator fun unaryPlus(): kotlin.Float diff --git a/compiler/testData/builtin-classes/java6/kotlin.txt b/compiler/testData/builtin-classes/java6/kotlin.txt index c830f983c03..93a90c22e95 100644 --- a/compiler/testData/builtin-classes/java6/kotlin.txt +++ b/compiler/testData/builtin-classes/java6/kotlin.txt @@ -287,13 +287,13 @@ public final class Double : kotlin.Number, kotlin.Comparable, jav public final operator fun times(/*0*/ other: kotlin.Int): kotlin.Double public final operator fun times(/*0*/ other: kotlin.Long): kotlin.Double public final operator fun times(/*0*/ other: kotlin.Short): kotlin.Double - public open override /*1*/ fun toByte(): kotlin.Byte + @kotlin.Deprecated(message = "Unclear conversion. To achieve the same result convert to Int explicitly and then to Byte.", replaceWith = kotlin.ReplaceWith(expression = "toInt().toByte()", imports = {})) public open override /*1*/ fun toByte(): kotlin.Byte public open override /*1*/ fun toChar(): kotlin.Char public open override /*1*/ fun toDouble(): kotlin.Double public open override /*1*/ fun toFloat(): kotlin.Float public open override /*1*/ fun toInt(): kotlin.Int public open override /*1*/ fun toLong(): kotlin.Long - public open override /*1*/ fun toShort(): kotlin.Short + @kotlin.Deprecated(message = "Unclear conversion. To achieve the same result convert to Int explicitly and then to Short.", replaceWith = kotlin.ReplaceWith(expression = "toInt().toShort()", imports = {})) public open override /*1*/ fun toShort(): kotlin.Short public final operator fun unaryMinus(): kotlin.Double public final operator fun unaryPlus(): kotlin.Double @@ -393,13 +393,13 @@ public final class Float : kotlin.Number, kotlin.Comparable, java. public final operator fun times(/*0*/ other: kotlin.Int): kotlin.Float public final operator fun times(/*0*/ other: kotlin.Long): kotlin.Float public final operator fun times(/*0*/ other: kotlin.Short): kotlin.Float - public open override /*1*/ fun toByte(): kotlin.Byte + @kotlin.Deprecated(message = "Unclear conversion. To achieve the same result convert to Int explicitly and then to Byte.", replaceWith = kotlin.ReplaceWith(expression = "toInt().toByte()", imports = {})) public open override /*1*/ fun toByte(): kotlin.Byte public open override /*1*/ fun toChar(): kotlin.Char public open override /*1*/ fun toDouble(): kotlin.Double public open override /*1*/ fun toFloat(): kotlin.Float public open override /*1*/ fun toInt(): kotlin.Int public open override /*1*/ fun toLong(): kotlin.Long - public open override /*1*/ fun toShort(): kotlin.Short + @kotlin.Deprecated(message = "Unclear conversion. To achieve the same result convert to Int explicitly and then to Short.", replaceWith = kotlin.ReplaceWith(expression = "toInt().toShort()", imports = {})) public open override /*1*/ fun toShort(): kotlin.Short public final operator fun unaryMinus(): kotlin.Float public final operator fun unaryPlus(): kotlin.Float diff --git a/compiler/testData/builtin-classes/java8/kotlin.txt b/compiler/testData/builtin-classes/java8/kotlin.txt index 348f27ce759..e9086779364 100644 --- a/compiler/testData/builtin-classes/java8/kotlin.txt +++ b/compiler/testData/builtin-classes/java8/kotlin.txt @@ -289,13 +289,13 @@ public final class Double : kotlin.Number, kotlin.Comparable, jav public final operator fun times(/*0*/ other: kotlin.Int): kotlin.Double public final operator fun times(/*0*/ other: kotlin.Long): kotlin.Double public final operator fun times(/*0*/ other: kotlin.Short): kotlin.Double - public open override /*1*/ fun toByte(): kotlin.Byte + @kotlin.Deprecated(message = "Unclear conversion. To achieve the same result convert to Int explicitly and then to Byte.", replaceWith = kotlin.ReplaceWith(expression = "toInt().toByte()", imports = {})) public open override /*1*/ fun toByte(): kotlin.Byte public open override /*1*/ fun toChar(): kotlin.Char public open override /*1*/ fun toDouble(): kotlin.Double public open override /*1*/ fun toFloat(): kotlin.Float public open override /*1*/ fun toInt(): kotlin.Int public open override /*1*/ fun toLong(): kotlin.Long - public open override /*1*/ fun toShort(): kotlin.Short + @kotlin.Deprecated(message = "Unclear conversion. To achieve the same result convert to Int explicitly and then to Short.", replaceWith = kotlin.ReplaceWith(expression = "toInt().toShort()", imports = {})) public open override /*1*/ fun toShort(): kotlin.Short public final operator fun unaryMinus(): kotlin.Double public final operator fun unaryPlus(): kotlin.Double @@ -395,13 +395,13 @@ public final class Float : kotlin.Number, kotlin.Comparable, java. public final operator fun times(/*0*/ other: kotlin.Int): kotlin.Float public final operator fun times(/*0*/ other: kotlin.Long): kotlin.Float public final operator fun times(/*0*/ other: kotlin.Short): kotlin.Float - public open override /*1*/ fun toByte(): kotlin.Byte + @kotlin.Deprecated(message = "Unclear conversion. To achieve the same result convert to Int explicitly and then to Byte.", replaceWith = kotlin.ReplaceWith(expression = "toInt().toByte()", imports = {})) public open override /*1*/ fun toByte(): kotlin.Byte public open override /*1*/ fun toChar(): kotlin.Char public open override /*1*/ fun toDouble(): kotlin.Double public open override /*1*/ fun toFloat(): kotlin.Float public open override /*1*/ fun toInt(): kotlin.Int public open override /*1*/ fun toLong(): kotlin.Long - public open override /*1*/ fun toShort(): kotlin.Short + @kotlin.Deprecated(message = "Unclear conversion. To achieve the same result convert to Int explicitly and then to Short.", replaceWith = kotlin.ReplaceWith(expression = "toInt().toShort()", imports = {})) public open override /*1*/ fun toShort(): kotlin.Short public final operator fun unaryMinus(): kotlin.Float public final operator fun unaryPlus(): kotlin.Float diff --git a/compiler/testData/builtin-classes/newMethods/kotlin.txt b/compiler/testData/builtin-classes/newMethods/kotlin.txt index 36220ae9bb9..449daf5bb8c 100644 --- a/compiler/testData/builtin-classes/newMethods/kotlin.txt +++ b/compiler/testData/builtin-classes/newMethods/kotlin.txt @@ -287,13 +287,13 @@ public final class Double : kotlin.Number, kotlin.Comparable, jav public final operator fun times(/*0*/ other: kotlin.Int): kotlin.Double public final operator fun times(/*0*/ other: kotlin.Long): kotlin.Double public final operator fun times(/*0*/ other: kotlin.Short): kotlin.Double - public open override /*1*/ fun toByte(): kotlin.Byte + @kotlin.Deprecated(message = "Unclear conversion. To achieve the same result convert to Int explicitly and then to Byte.", replaceWith = kotlin.ReplaceWith(expression = "toInt().toByte()", imports = {})) public open override /*1*/ fun toByte(): kotlin.Byte public open override /*1*/ fun toChar(): kotlin.Char public open override /*1*/ fun toDouble(): kotlin.Double public open override /*1*/ fun toFloat(): kotlin.Float public open override /*1*/ fun toInt(): kotlin.Int public open override /*1*/ fun toLong(): kotlin.Long - public open override /*1*/ fun toShort(): kotlin.Short + @kotlin.Deprecated(message = "Unclear conversion. To achieve the same result convert to Int explicitly and then to Short.", replaceWith = kotlin.ReplaceWith(expression = "toInt().toShort()", imports = {})) public open override /*1*/ fun toShort(): kotlin.Short public final operator fun unaryMinus(): kotlin.Double public final operator fun unaryPlus(): kotlin.Double @@ -393,13 +393,13 @@ public final class Float : kotlin.Number, kotlin.Comparable, java. public final operator fun times(/*0*/ other: kotlin.Int): kotlin.Float public final operator fun times(/*0*/ other: kotlin.Long): kotlin.Float public final operator fun times(/*0*/ other: kotlin.Short): kotlin.Float - public open override /*1*/ fun toByte(): kotlin.Byte + @kotlin.Deprecated(message = "Unclear conversion. To achieve the same result convert to Int explicitly and then to Byte.", replaceWith = kotlin.ReplaceWith(expression = "toInt().toByte()", imports = {})) public open override /*1*/ fun toByte(): kotlin.Byte public open override /*1*/ fun toChar(): kotlin.Char public open override /*1*/ fun toDouble(): kotlin.Double public open override /*1*/ fun toFloat(): kotlin.Float public open override /*1*/ fun toInt(): kotlin.Int public open override /*1*/ fun toLong(): kotlin.Long - public open override /*1*/ fun toShort(): kotlin.Short + @kotlin.Deprecated(message = "Unclear conversion. To achieve the same result convert to Int explicitly and then to Short.", replaceWith = kotlin.ReplaceWith(expression = "toInt().toShort()", imports = {})) public open override /*1*/ fun toShort(): kotlin.Short public final operator fun unaryMinus(): kotlin.Float public final operator fun unaryPlus(): kotlin.Float diff --git a/compiler/testData/diagnostics/testsWithStdLib/functionLiterals/pseudocodeMemoryOverhead.kt b/compiler/testData/diagnostics/testsWithStdLib/functionLiterals/pseudocodeMemoryOverhead.kt index 448b1c1b126..454bbe5dca7 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/functionLiterals/pseudocodeMemoryOverhead.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/functionLiterals/pseudocodeMemoryOverhead.kt @@ -63,8 +63,8 @@ private val unaryOperations: HashMap, Pair a.unaryPlus() }, emptyUnaryFun), unaryOperation(DOUBLE, "toFloat", { a -> a.toFloat() }, emptyUnaryFun), unaryOperation(DOUBLE, "toDouble", { a -> a.toDouble() }, emptyUnaryFun), - unaryOperation(DOUBLE, "toShort", { a -> a.toShort() }, emptyUnaryFun), - unaryOperation(DOUBLE, "toByte", { a -> a.toByte() }, emptyUnaryFun), + unaryOperation(DOUBLE, "toShort", { a -> a.toShort() }, emptyUnaryFun), + unaryOperation(DOUBLE, "toByte", { a -> a.toByte() }, emptyUnaryFun), unaryOperation(FLOAT, "toInt", { a -> a.toInt() }, emptyUnaryFun), unaryOperation(FLOAT, "minus", { a -> a.unaryMinus() }, emptyUnaryFun), unaryOperation(FLOAT, "toChar", { a -> a.toChar() }, emptyUnaryFun), @@ -72,8 +72,8 @@ private val unaryOperations: HashMap, Pair a.unaryPlus() }, emptyUnaryFun), unaryOperation(FLOAT, "toFloat", { a -> a.toFloat() }, emptyUnaryFun), unaryOperation(FLOAT, "toDouble", { a -> a.toDouble() }, emptyUnaryFun), - unaryOperation(FLOAT, "toShort", { a -> a.toShort() }, emptyUnaryFun), - unaryOperation(FLOAT, "toByte", { a -> a.toByte() }, emptyUnaryFun), + unaryOperation(FLOAT, "toShort", { a -> a.toShort() }, emptyUnaryFun), + unaryOperation(FLOAT, "toByte", { a -> a.toByte() }, emptyUnaryFun), unaryOperation(INT, "plus", { a -> a.unaryPlus() }, emptyUnaryFun), unaryOperation(INT, "toShort", { a -> a.toShort() }, emptyUnaryFun), unaryOperation(INT, "toByte", { a -> a.toByte() }, emptyUnaryFun), diff --git a/core/builtins/native/kotlin/Primitives.kt b/core/builtins/native/kotlin/Primitives.kt index 19ad4ebe7f8..84d300efaae 100644 --- a/core/builtins/native/kotlin/Primitives.kt +++ b/core/builtins/native/kotlin/Primitives.kt @@ -1144,6 +1144,7 @@ public class Float private constructor() : Number(), Comparable { * * The resulting `Byte` value is equal to `this.toInt().toByte()`. */ + @Deprecated("Unclear conversion. To achieve the same result convert to Int explicitly and then to Byte.", ReplaceWith("toInt().toByte()")) public override fun toByte(): Byte /** * Converts this [Float] value to [Char]. @@ -1156,6 +1157,7 @@ public class Float private constructor() : Number(), Comparable { * * The resulting `Short` value is equal to `this.toInt().toShort()`. */ + @Deprecated("Unclear conversion. To achieve the same result convert to Int explicitly and then to Short.", ReplaceWith("toInt().toShort()")) public override fun toShort(): Short /** * Converts this [Float] value to [Int]. @@ -1362,6 +1364,7 @@ public class Double private constructor() : Number(), Comparable { * * The resulting `Byte` value is equal to `this.toInt().toByte()`. */ + @Deprecated("Unclear conversion. To achieve the same result convert to Int explicitly and then to Byte.", ReplaceWith("toInt().toByte()")) public override fun toByte(): Byte /** * Converts this [Double] value to [Char]. @@ -1374,6 +1377,7 @@ public class Double private constructor() : Number(), Comparable { * * The resulting `Short` value is equal to `this.toInt().toShort()`. */ + @Deprecated("Unclear conversion. To achieve the same result convert to Int explicitly and then to Short.", ReplaceWith("toInt().toShort()")) public override fun toShort(): Short /** * Converts this [Double] value to [Int]. diff --git a/generators/builtins/primitives.kt b/generators/builtins/primitives.kt index b8a5c0f8cfd..dd71f1533a3 100644 --- a/generators/builtins/primitives.kt +++ b/generators/builtins/primitives.kt @@ -344,6 +344,10 @@ class GeneratePrimitives(out: PrintWriter) : BuiltInsSourceGenerator(out) { } private fun generateConversions(kind: PrimitiveType) { + fun isConversionDeprecated(otherKind: PrimitiveType): Boolean { + return kind in PrimitiveType.floatingPoint && otherKind in listOf(PrimitiveType.BYTE, PrimitiveType.SHORT) + } + val thisName = kind.capitalized for (otherKind in PrimitiveType.exceptBoolean) { val otherName = otherKind.capitalized @@ -367,6 +371,11 @@ class GeneratePrimitives(out: PrintWriter) : BuiltInsSourceGenerator(out) { " /**\n * Converts this [$thisName] value to [$otherName].\n *\n" + detail.replaceIndent(" ") } out.println(doc) + + if (isConversionDeprecated(otherKind)) { + out.println(" @Deprecated(\"Unclear conversion. To achieve the same result convert to Int explicitly and then to $otherName.\", ReplaceWith(\"toInt().to$otherName()\"))") + } + out.println(" public override fun to$otherName(): $otherName") } } diff --git a/generators/evaluate/GenerateOperationsMap.kt b/generators/evaluate/GenerateOperationsMap.kt index eb22982abbc..2e3f574a5c5 100644 --- a/generators/evaluate/GenerateOperationsMap.kt +++ b/generators/evaluate/GenerateOperationsMap.kt @@ -27,7 +27,8 @@ fun generate(): String { val sb = StringBuilder() val p = Printer(sb) p.println(File("license/COPYRIGHT.txt").readText()) - p.println("@file:Suppress(\"DEPRECATION_ERROR\")") + p.println("@file:Suppress(\"DEPRECATION\", \"DEPRECATION_ERROR\")") + p.println() p.println("package org.jetbrains.kotlin.resolve.constants.evaluate") p.println() diff --git a/libraries/stdlib/common/src/generated/_Ranges.kt b/libraries/stdlib/common/src/generated/_Ranges.kt index 5812d1cb4d6..ad523c4e7e5 100644 --- a/libraries/stdlib/common/src/generated/_Ranges.kt +++ b/libraries/stdlib/common/src/generated/_Ranges.kt @@ -670,11 +670,11 @@ internal fun Short.toByteExactOrNull(): Byte? { } internal fun Double.toByteExactOrNull(): Byte? { - return if (this in Byte.MIN_VALUE.toDouble()..Byte.MAX_VALUE.toDouble()) this.toByte() else null + return if (this in Byte.MIN_VALUE.toDouble()..Byte.MAX_VALUE.toDouble()) this.toInt().toByte() else null } internal fun Float.toByteExactOrNull(): Byte? { - return if (this in Byte.MIN_VALUE.toFloat()..Byte.MAX_VALUE.toFloat()) this.toByte() else null + return if (this in Byte.MIN_VALUE.toFloat()..Byte.MAX_VALUE.toFloat()) this.toInt().toByte() else null } internal fun Long.toIntExactOrNull(): Int? { @@ -706,11 +706,11 @@ internal fun Long.toShortExactOrNull(): Short? { } internal fun Double.toShortExactOrNull(): Short? { - return if (this in Short.MIN_VALUE.toDouble()..Short.MAX_VALUE.toDouble()) this.toShort() else null + return if (this in Short.MIN_VALUE.toDouble()..Short.MAX_VALUE.toDouble()) this.toInt().toShort() else null } internal fun Float.toShortExactOrNull(): Short? { - return if (this in Short.MIN_VALUE.toFloat()..Short.MAX_VALUE.toFloat()) this.toShort() else null + return if (this in Short.MIN_VALUE.toFloat()..Short.MAX_VALUE.toFloat()) this.toInt().toShort() else null } /** diff --git a/libraries/stdlib/js-ir/builtins/Primitives.kt b/libraries/stdlib/js-ir/builtins/Primitives.kt index 42d62efe0c3..89f6fa9c87c 100644 --- a/libraries/stdlib/js-ir/builtins/Primitives.kt +++ b/libraries/stdlib/js-ir/builtins/Primitives.kt @@ -187,12 +187,55 @@ public class Byte private constructor() : Number(), Comparable { /** Creates a range from this value to the specified [other] value. */ public operator fun rangeTo(other: Long): LongRange + /** Returns this value. */ public override fun toByte(): Byte + /** + * Converts this [Byte] value to [Char]. + * + * If this value is non-negative, the resulting `Char` code is equal to this value. + * + * The least significant 8 bits of the resulting `Char` code are the same as the bits of this `Byte` value, + * whereas the most significant 8 bits are filled with the sign bit of this value. + */ public override fun toChar(): Char + /** + * Converts this [Byte] value to [Short]. + * + * The resulting `Short` value represents the same numerical value as this `Byte`. + * + * The least significant 8 bits of the resulting `Short` value are the same as the bits of this `Byte` value, + * whereas the most significant 8 bits are filled with the sign bit of this value. + */ public override fun toShort(): Short + /** + * Converts this [Byte] value to [Int]. + * + * The resulting `Int` value represents the same numerical value as this `Byte`. + * + * The least significant 8 bits of the resulting `Int` value are the same as the bits of this `Byte` value, + * whereas the most significant 24 bits are filled with the sign bit of this value. + */ public override fun toInt(): Int + /** + * Converts this [Byte] value to [Long]. + * + * The resulting `Long` value represents the same numerical value as this `Byte`. + * + * The least significant 8 bits of the resulting `Long` value are the same as the bits of this `Byte` value, + * whereas the most significant 56 bits are filled with the sign bit of this value. + */ public override fun toLong(): Long + /** + * Converts this [Byte] value to [Float]. + * + * The resulting `Float` value represents the same numerical value as this `Byte`. + */ public override fun toFloat(): Float + /** + * Converts this [Byte] value to [Double]. + * + * The resulting `Double` value represents the same numerical value as this `Byte`. + */ public override fun toDouble(): Double } @@ -375,12 +418,53 @@ public class Short private constructor() : Number(), Comparable { /** Creates a range from this value to the specified [other] value. */ public operator fun rangeTo(other: Long): LongRange + /** + * Converts this [Short] value to [Byte]. + * + * If this value is in [Byte.MIN_VALUE]..[Byte.MAX_VALUE], the resulting `Byte` value represents + * the same numerical value as this `Short`. + * + * The resulting `Byte` value is represented by the least significant 8 bits of this `Short` value. + */ public override fun toByte(): Byte + /** + * Converts this [Short] value to [Char]. + * + * The resulting `Char` code is equal to this value reinterpreted as an unsigned number, + * i.e. it has the same binary representation as this `Short`. + */ public override fun toChar(): Char + /** Returns this value. */ public override fun toShort(): Short + /** + * Converts this [Short] value to [Int]. + * + * The resulting `Int` value represents the same numerical value as this `Short`. + * + * The least significant 16 bits of the resulting `Int` value are the same as the bits of this `Short` value, + * whereas the most significant 16 bits are filled with the sign bit of this value. + */ public override fun toInt(): Int + /** + * Converts this [Short] value to [Long]. + * + * The resulting `Long` value represents the same numerical value as this `Short`. + * + * The least significant 16 bits of the resulting `Long` value are the same as the bits of this `Short` value, + * whereas the most significant 48 bits are filled with the sign bit of this value. + */ public override fun toLong(): Long + /** + * Converts this [Short] value to [Float]. + * + * The resulting `Float` value represents the same numerical value as this `Short`. + */ public override fun toFloat(): Float + /** + * Converts this [Short] value to [Double]. + * + * The resulting `Double` value represents the same numerical value as this `Short`. + */ public override fun toDouble(): Double } @@ -578,12 +662,57 @@ public class Int private constructor() : Number(), Comparable { /** Inverts the bits in this value. */ public fun inv(): Int + /** + * Converts this [Int] value to [Byte]. + * + * If this value is in [Byte.MIN_VALUE]..[Byte.MAX_VALUE], the resulting `Byte` value represents + * the same numerical value as this `Int`. + * + * The resulting `Byte` value is represented by the least significant 8 bits of this `Int` value. + */ public override fun toByte(): Byte + /** + * Converts this [Int] value to [Char]. + * + * If this value is in the range of `Char` codes `Char.MIN_VALUE..Char.MAX_VALUE`, + * the resulting `Char` code is equal to this value. + * + * The resulting `Char` code is represented by the least significant 16 bits of this `Int` value. + */ public override fun toChar(): Char + /** + * Converts this [Int] value to [Short]. + * + * If this value is in [Short.MIN_VALUE]..[Short.MAX_VALUE], the resulting `Short` value represents + * the same numerical value as this `Int`. + * + * The resulting `Short` value is represented by the least significant 16 bits of this `Int` value. + */ public override fun toShort(): Short + /** Returns this value. */ public override fun toInt(): Int + /** + * Converts this [Int] value to [Long]. + * + * The resulting `Long` value represents the same numerical value as this `Int`. + * + * The least significant 32 bits of the resulting `Long` value are the same as the bits of this `Int` value, + * whereas the most significant 32 bits are filled with the sign bit of this value. + */ public override fun toLong(): Long + /** + * Converts this [Int] value to [Float]. + * + * The resulting value is the closest `Float` to this `Int` value. + * In case when this `Int` value is exactly between two `Float`s, + * the one with zero at least significant bit of mantissa is selected. + */ public override fun toFloat(): Float + /** + * Converts this [Int] value to [Double]. + * + * The resulting `Double` value represents the same numerical value as this `Int`. + */ public override fun toDouble(): Double } @@ -766,12 +895,49 @@ public class Float private constructor() : Number(), Comparable { public operator fun unaryMinus(): Float + /** + * Converts this [Float] value to [Byte]. + * + * The resulting `Byte` value is equal to `this.toInt().toByte()`. + */ + @Deprecated("Unclear conversion. To achieve the same result convert to Int explicitly and then to Byte.", ReplaceWith("toInt().toByte()")) public override fun toByte(): Byte + /** + * Converts this [Float] value to [Char]. + * + * The resulting `Char` value is equal to `this.toInt().toChar()`. + */ public override fun toChar(): Char + /** + * Converts this [Float] value to [Short]. + * + * The resulting `Short` value is equal to `this.toInt().toShort()`. + */ + @Deprecated("Unclear conversion. To achieve the same result convert to Int explicitly and then to Short.", ReplaceWith("toInt().toShort()")) public override fun toShort(): Short + /** + * Converts this [Float] value to [Int]. + * + * The fractional part, if any, is rounded down towards zero. + * Returns zero if this `Float` value is `NaN`, [Int.MIN_VALUE] if it's less than `Int.MIN_VALUE`, + * [Int.MAX_VALUE] if it's bigger than `Int.MAX_VALUE`. + */ public override fun toInt(): Int + /** + * Converts this [Float] value to [Long]. + * + * The fractional part, if any, is rounded down towards zero. + * Returns zero if this `Float` value is `NaN`, [Long.MIN_VALUE] if it's less than `Long.MIN_VALUE`, + * [Long.MAX_VALUE] if it's bigger than `Long.MAX_VALUE`. + */ public override fun toLong(): Long + /** Returns this value. */ public override fun toFloat(): Float + /** + * Converts this [Float] value to [Double]. + * + * The resulting `Double` value represents the same numerical value as this `Float`. + */ public override fun toDouble(): Double } @@ -954,12 +1120,51 @@ public class Double private constructor() : Number(), Comparable { public operator fun unaryMinus(): Double + /** + * Converts this [Double] value to [Byte]. + * + * The resulting `Byte` value is equal to `this.toInt().toByte()`. + */ + @Deprecated("Unclear conversion. To achieve the same result convert to Int explicitly and then to Byte.", ReplaceWith("toInt().toByte()")) public override fun toByte(): Byte + /** + * Converts this [Double] value to [Char]. + * + * The resulting `Char` value is equal to `this.toInt().toChar()`. + */ public override fun toChar(): Char + /** + * Converts this [Double] value to [Short]. + * + * The resulting `Short` value is equal to `this.toInt().toShort()`. + */ + @Deprecated("Unclear conversion. To achieve the same result convert to Int explicitly and then to Short.", ReplaceWith("toInt().toShort()")) public override fun toShort(): Short + /** + * Converts this [Double] value to [Int]. + * + * The fractional part, if any, is rounded down towards zero. + * Returns zero if this `Double` value is `NaN`, [Int.MIN_VALUE] if it's less than `Int.MIN_VALUE`, + * [Int.MAX_VALUE] if it's bigger than `Int.MAX_VALUE`. + */ public override fun toInt(): Int + /** + * Converts this [Double] value to [Long]. + * + * The fractional part, if any, is rounded down towards zero. + * Returns zero if this `Double` value is `NaN`, [Long.MIN_VALUE] if it's less than `Long.MIN_VALUE`, + * [Long.MAX_VALUE] if it's bigger than `Long.MAX_VALUE`. + */ public override fun toLong(): Long + /** + * Converts this [Double] value to [Float]. + * + * The resulting value is the closest `Float` to this `Double` value. + * In case when this `Double` value is exactly between two `Float`s, + * the one with zero at least significant bit of mantissa is selected. + */ public override fun toFloat(): Float + /** Returns this value. */ public override fun toDouble(): Double } diff --git a/libraries/stdlib/test/collections/ArraysTest.kt b/libraries/stdlib/test/collections/ArraysTest.kt index 57084094d4f..6f845ae2c10 100644 --- a/libraries/stdlib/test/collections/ArraysTest.kt +++ b/libraries/stdlib/test/collections/ArraysTest.kt @@ -477,7 +477,7 @@ class ArraysTest { expect(3.8) { arrayOf(1, 2, 5, 8, 3).average() } expect(2.1) { arrayOf(1.6, 2.6, 3.6, 0.6).average() } expect(100.0) { arrayOf(100, 100, 100, 100, 100, 100).average() } - expect(0) { arrayOf(1, -1, 2, -2, 3, -3).average().toShort() } + expect(0) { arrayOf(1, -1, 2, -2, 3, -3).average().toInt() } // TODO: Property based tests // for each arr with size 1 arr.average() == arr[0] // for each arr with size > 0 arr.average() = arr.sum().toDouble() / arr.size() diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Ranges.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Ranges.kt index b4fa64bd3e4..2aad7dcdbbe 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Ranges.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Ranges.kt @@ -220,8 +220,12 @@ object RangeOps : TemplateGroupBase() { signature("to${toType}ExactOrNull()") returns("$toType?") + + val isConversionDeprecated = fromType.isFloatingPoint() && toType in listOf(PrimitiveType.Byte, PrimitiveType.Short) + val conversion = if (isConversionDeprecated) "toInt().to$toType" else "to$toType" + body { - "return if (this in $toType.MIN_VALUE.to$fromType()..$toType.MAX_VALUE.to$fromType()) this.to$toType() else null" + "return if (this in $toType.MIN_VALUE.to$fromType()..$toType.MAX_VALUE.to$fromType()) this.$conversion() else null" } } }