Allow unsigned integers overflow values of corresponding signed numbers
This commit is contained in:
+22
-11
@@ -941,11 +941,17 @@ private class ConstantExpressionEvaluatorVisitor(
|
|||||||
if (integerValue != null) {
|
if (integerValue != null) {
|
||||||
return integerValue.wrap(parameters)
|
return integerValue.wrap(parameters)
|
||||||
}
|
}
|
||||||
return when (value) {
|
|
||||||
value.toInt().toLong() ->
|
return if (parameters.isUnsigned) {
|
||||||
if (parameters.isUnsigned) UIntValue(value.toInt()) else IntValue(value.toInt())
|
when (value) {
|
||||||
else ->
|
value.toInt().fromUIntToLong() -> UIntValue(value.toInt())
|
||||||
if (parameters.isUnsigned) ULongValue(value) else LongValue(value)
|
else -> ULongValue(value)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
when (value) {
|
||||||
|
value.toInt().toLong() -> IntValue(value.toInt())
|
||||||
|
else -> LongValue(value)
|
||||||
|
}
|
||||||
}.wrap(parameters)
|
}.wrap(parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -975,14 +981,19 @@ private fun parseNumericLiteral(text: String, type: IElementType): Any? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun parseLong(text: String): Long? {
|
private fun parseLong(text: String): Long? {
|
||||||
try {
|
return try {
|
||||||
fun substringSuffix(s: String) = if (hasLongSuffix(text) || hasUnsignedSuffix(text)) s.substring(0, s.length - 1) else s
|
val hasUnsignedSuffix = hasUnsignedSuffix(text)
|
||||||
fun parseLong(text: String, radix: Int) = java.lang.Long.parseLong(substringSuffix(text), radix)
|
val hasLongSuffix = hasLongSuffix(text)
|
||||||
|
val textWithoutSuffix = if (hasUnsignedSuffix || hasLongSuffix) text.substring(0, text.length - 1) else text
|
||||||
|
val (number, radix) = extractRadix(textWithoutSuffix)
|
||||||
|
|
||||||
val (number, radix) = extractRadix(text)
|
if (hasUnsignedSuffix) {
|
||||||
return parseLong(number, radix)
|
java.lang.Long.parseUnsignedLong(number, radix)
|
||||||
|
} else {
|
||||||
|
java.lang.Long.parseLong(number, radix)
|
||||||
|
}
|
||||||
} catch (e: NumberFormatException) {
|
} catch (e: NumberFormatException) {
|
||||||
return null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
// !LANGUAGE: +InlineClasses
|
||||||
|
// !SKIP_METADATA_VERSION_CHECK
|
||||||
|
// WITH_UNSIGNED
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val u1: UByte = 255u
|
||||||
|
if (u1.toByte().toInt() != -1) return "fail"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
Vendored
+25
@@ -0,0 +1,25 @@
|
|||||||
|
// !LANGUAGE: +InlineClasses
|
||||||
|
// !SKIP_METADATA_VERSION_CHECK
|
||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
|
const val u1: UByte = 0xFFu
|
||||||
|
const val u2: UShort = 0xFFFFu
|
||||||
|
const val u3: UInt = 0xFFFF_FFFFu
|
||||||
|
const val u4: ULong = 0xFFFF_FFFF_FFFF_FFFFu
|
||||||
|
const val u5: ULong = 18446744073709551615u
|
||||||
|
|
||||||
|
const val u6 = 0xFFFF_FFFF_FFFF_FFFFu
|
||||||
|
const val u7 = 18446744073709551615u
|
||||||
|
|
||||||
|
val u8: Comparable<*> = 0xFFFF_FFFF_FFFF_FFFFu
|
||||||
|
|
||||||
|
fun takeUByte(ubyte: UByte) {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
takeUByte(200u)
|
||||||
|
takeUByte(255u)
|
||||||
|
takeUByte(0xFFu)
|
||||||
|
}
|
||||||
|
|
||||||
|
val s1: UByte = <!CONSTANT_EXPECTED_TYPE_MISMATCH!>256u<!>
|
||||||
|
val s2 = <!INT_LITERAL_OUT_OF_RANGE!>18446744073709551616u<!>
|
||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public val s1: kotlin.UByte = 256.toUInt()
|
||||||
|
public val s2: kotlin.Int
|
||||||
|
public const val u1: kotlin.UByte = -1.toUByte()
|
||||||
|
public const val u2: kotlin.UShort = -1.toUShort()
|
||||||
|
public const val u3: kotlin.UInt = -1.toUInt()
|
||||||
|
public const val u4: kotlin.ULong = -1.toULong()
|
||||||
|
public const val u5: kotlin.ULong = -1.toULong()
|
||||||
|
public const val u6: kotlin.ULong = -1.toULong()
|
||||||
|
public const val u7: kotlin.ULong = -1.toULong()
|
||||||
|
public val u8: kotlin.Comparable<*>
|
||||||
|
public fun takeUByte(/*0*/ ubyte: kotlin.UByte): kotlin.Unit
|
||||||
|
public fun test(): kotlin.Unit
|
||||||
Generated
+5
@@ -11304,6 +11304,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/inlineClasses/UIntArraySortExample.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/UIntArraySortExample.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("unsignedLiteralsWithSignedOverflow.kt")
|
||||||
|
public void testUnsignedLiteralsWithSignedOverflow() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/unsignedLiteralsWithSignedOverflow.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("useInlineClassesInsideElvisOperator.kt")
|
@TestMetadata("useInlineClassesInsideElvisOperator.kt")
|
||||||
public void testUseInlineClassesInsideElvisOperator() throws Exception {
|
public void testUseInlineClassesInsideElvisOperator() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/useInlineClassesInsideElvisOperator.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/useInlineClassesInsideElvisOperator.kt");
|
||||||
|
|||||||
+5
@@ -34,6 +34,11 @@ public class DiagnosticsWithUnsignedTypesGenerated extends AbstractDiagnosticsWi
|
|||||||
runTest("compiler/testData/diagnostics/testsWithUnsignedTypes/unsignedLiteralsInsideConstVals.kt");
|
runTest("compiler/testData/diagnostics/testsWithUnsignedTypes/unsignedLiteralsInsideConstVals.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("unsignedLiteralsOverflowSignedBorder.kt")
|
||||||
|
public void testUnsignedLiteralsOverflowSignedBorder() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithUnsignedTypes/unsignedLiteralsOverflowSignedBorder.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("unsignedLiteralsTypeCheck.kt")
|
@TestMetadata("unsignedLiteralsTypeCheck.kt")
|
||||||
public void testUnsignedLiteralsTypeCheck() throws Exception {
|
public void testUnsignedLiteralsTypeCheck() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithUnsignedTypes/unsignedLiteralsTypeCheck.kt");
|
runTest("compiler/testData/diagnostics/testsWithUnsignedTypes/unsignedLiteralsTypeCheck.kt");
|
||||||
|
|||||||
+5
@@ -11304,6 +11304,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/inlineClasses/UIntArraySortExample.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/UIntArraySortExample.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("unsignedLiteralsWithSignedOverflow.kt")
|
||||||
|
public void testUnsignedLiteralsWithSignedOverflow() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/unsignedLiteralsWithSignedOverflow.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("useInlineClassesInsideElvisOperator.kt")
|
@TestMetadata("useInlineClassesInsideElvisOperator.kt")
|
||||||
public void testUseInlineClassesInsideElvisOperator() throws Exception {
|
public void testUseInlineClassesInsideElvisOperator() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/useInlineClassesInsideElvisOperator.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/useInlineClassesInsideElvisOperator.kt");
|
||||||
|
|||||||
+5
@@ -11304,6 +11304,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/inlineClasses/UIntArraySortExample.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/UIntArraySortExample.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("unsignedLiteralsWithSignedOverflow.kt")
|
||||||
|
public void testUnsignedLiteralsWithSignedOverflow() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/unsignedLiteralsWithSignedOverflow.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("useInlineClassesInsideElvisOperator.kt")
|
@TestMetadata("useInlineClassesInsideElvisOperator.kt")
|
||||||
public void testUseInlineClassesInsideElvisOperator() throws Exception {
|
public void testUseInlineClassesInsideElvisOperator() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/useInlineClassesInsideElvisOperator.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/useInlineClassesInsideElvisOperator.kt");
|
||||||
|
|||||||
@@ -71,9 +71,9 @@ object ConstantValueFactory {
|
|||||||
val notNullExpected = TypeUtils.makeNotNullable(expectedType)
|
val notNullExpected = TypeUtils.makeNotNullable(expectedType)
|
||||||
return if (isUnsigned) {
|
return if (isUnsigned) {
|
||||||
when {
|
when {
|
||||||
KotlinBuiltIns.isUByte(notNullExpected) && value == value.toByte().toLong() -> UByteValue(value.toByte())
|
KotlinBuiltIns.isUByte(notNullExpected) && value == value.toByte().fromUByteToLong() -> UByteValue(value.toByte())
|
||||||
KotlinBuiltIns.isUShort(notNullExpected) && value == value.toShort().toLong() -> UShortValue(value.toShort())
|
KotlinBuiltIns.isUShort(notNullExpected) && value == value.toShort().fromUShortToLong() -> UShortValue(value.toShort())
|
||||||
KotlinBuiltIns.isUInt(notNullExpected) && value == value.toInt().toLong() -> UIntValue(value.toInt())
|
KotlinBuiltIns.isUInt(notNullExpected) && value == value.toInt().fromUIntToLong() -> UIntValue(value.toInt())
|
||||||
KotlinBuiltIns.isULong(notNullExpected) -> ULongValue(value)
|
KotlinBuiltIns.isULong(notNullExpected) -> ULongValue(value)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
@@ -89,3 +89,7 @@ object ConstantValueFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Byte.fromUByteToLong(): Long = this.toLong() and 0xFF
|
||||||
|
fun Short.fromUShortToLong(): Long = this.toLong() and 0xFFFF
|
||||||
|
fun Int.fromUIntToLong(): Long = this.toLong() and 0xFFFF_FFFF
|
||||||
|
|||||||
+35
-21
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.resolve.constants
|
package org.jetbrains.kotlin.resolve.constants
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.builtins.UnsignedTypes
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
|
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
|
||||||
@@ -45,30 +46,14 @@ class IntegerValueTypeConstructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: fix value ranges for unsigned types
|
checkBoundsAndAddSuperType(value, if (isUnsigned) unsignedType(KotlinBuiltIns.FQ_NAMES.uInt) else builtIns.intType)
|
||||||
checkBoundsAndAddSuperType(
|
checkBoundsAndAddSuperType(value, if (isUnsigned) unsignedType(KotlinBuiltIns.FQ_NAMES.uByte) else builtIns.byteType)
|
||||||
value,
|
checkBoundsAndAddSuperType(value, if (isUnsigned) unsignedType(KotlinBuiltIns.FQ_NAMES.uShort) else builtIns.shortType)
|
||||||
Integer.MIN_VALUE.toLong(),
|
|
||||||
Integer.MAX_VALUE.toLong(),
|
|
||||||
if (isUnsigned) unsignedType(KotlinBuiltIns.FQ_NAMES.uInt) else builtIns.intType
|
|
||||||
)
|
|
||||||
checkBoundsAndAddSuperType(
|
|
||||||
value,
|
|
||||||
java.lang.Byte.MIN_VALUE.toLong(),
|
|
||||||
java.lang.Byte.MAX_VALUE.toLong(),
|
|
||||||
if (isUnsigned) unsignedType(KotlinBuiltIns.FQ_NAMES.uByte) else builtIns.byteType
|
|
||||||
)
|
|
||||||
checkBoundsAndAddSuperType(
|
|
||||||
value,
|
|
||||||
java.lang.Short.MIN_VALUE.toLong(),
|
|
||||||
java.lang.Short.MAX_VALUE.toLong(),
|
|
||||||
if (isUnsigned) unsignedType(KotlinBuiltIns.FQ_NAMES.uShort) else builtIns.shortType
|
|
||||||
)
|
|
||||||
supertypes.add(if (isUnsigned) unsignedType(KotlinBuiltIns.FQ_NAMES.uLong) else builtIns.longType)
|
supertypes.add(if (isUnsigned) unsignedType(KotlinBuiltIns.FQ_NAMES.uLong) else builtIns.longType)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkBoundsAndAddSuperType(value: Long, minValue: Long, maxValue: Long, kotlinType: KotlinType) {
|
private fun checkBoundsAndAddSuperType(value: Long, kotlinType: KotlinType) {
|
||||||
if (value >= minValue && value <= maxValue) {
|
if (value in kotlinType.minValue()..kotlinType.maxValue()) {
|
||||||
supertypes.add(kotlinType)
|
supertypes.add(kotlinType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,3 +78,32 @@ class IntegerValueTypeConstructor(
|
|||||||
|
|
||||||
override fun toString() = "IntegerValueType($value)"
|
override fun toString() = "IntegerValueType($value)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun KotlinType.minValue(): Long {
|
||||||
|
if (UnsignedTypes.isUnsignedType(this)) return 0
|
||||||
|
return when {
|
||||||
|
KotlinBuiltIns.isByte(this) -> Byte.MIN_VALUE.toLong()
|
||||||
|
KotlinBuiltIns.isShort(this) -> Short.MIN_VALUE.toLong()
|
||||||
|
KotlinBuiltIns.isInt(this) -> Int.MIN_VALUE.toLong()
|
||||||
|
else -> error("Can't get min value for type: $this")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KotlinType.maxValue(): Long {
|
||||||
|
return when {
|
||||||
|
KotlinBuiltIns.isByte(this) -> Byte.MAX_VALUE.toLong()
|
||||||
|
KotlinBuiltIns.isShort(this) -> Short.MAX_VALUE.toLong()
|
||||||
|
KotlinBuiltIns.isInt(this) -> Int.MAX_VALUE.toLong()
|
||||||
|
|
||||||
|
KotlinBuiltIns.isUByte(this) -> UBYTE_MAX_VALUE
|
||||||
|
KotlinBuiltIns.isUShort(this) -> USHORT_MAX_VALUE
|
||||||
|
KotlinBuiltIns.isUInt(this) -> UINT_MAX_VALUE
|
||||||
|
|
||||||
|
else -> error("Can't get max value for type: $this")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val UBYTE_MAX_VALUE = (-1).toByte().fromUByteToLong()
|
||||||
|
private val USHORT_MAX_VALUE = (-1).toShort().fromUShortToLong()
|
||||||
|
private val UINT_MAX_VALUE = (-1).fromUIntToLong()
|
||||||
|
|
||||||
|
|||||||
+5
@@ -9840,6 +9840,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/inlineClasses/UIntArraySortExample.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/UIntArraySortExample.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("unsignedLiteralsWithSignedOverflow.kt")
|
||||||
|
public void testUnsignedLiteralsWithSignedOverflow() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/unsignedLiteralsWithSignedOverflow.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("useInlineClassesInsideElvisOperator.kt")
|
@TestMetadata("useInlineClassesInsideElvisOperator.kt")
|
||||||
public void testUseInlineClassesInsideElvisOperator() throws Exception {
|
public void testUseInlineClassesInsideElvisOperator() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/useInlineClassesInsideElvisOperator.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/useInlineClassesInsideElvisOperator.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user