From 7d5fdb660d09a81b59ac3a061a4d3b448952bddf Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Mon, 28 May 2018 10:54:09 +0300 Subject: [PATCH] Treat number with unsigned literal as `UByte & UShort & UInt & ULong` --- .../JavaPropertyInitializerEvaluatorImpl.kt | 2 +- .../evaluate/ConstantExpressionEvaluator.kt | 40 ++++++++++++------ .../checkBasicUnsignedLiterals.kt | 16 ++++++++ .../box/inlineClasses/checkPlusOfUInt.kt | 11 ----- .../ConstraintSystemTestData.kt | 11 ++++- .../ir/IrBlackBoxCodegenTestGenerated.java | 10 ++--- .../codegen/BlackBoxCodegenTestGenerated.java | 10 ++--- .../LightAnalysisModeTestGenerated.java | 10 ++--- .../kotlin/builtins/KotlinBuiltIns.java | 25 +++++++++++ .../resolve/constants/CompileTimeConstant.kt | 14 ++++++- .../resolve/constants/ConstantValueFactory.kt | 36 ++++++++++------ .../constants/IntegerValueTypeConstructor.kt | 41 +++++++++++++++---- .../resolve/constants/constantValues.kt | 32 +++++++++++---- .../org/jetbrains/kotlin/types/TypeUtils.java | 24 +++++++++++ .../semantics/JsCodegenBoxTestGenerated.java | 10 ++--- 15 files changed, 217 insertions(+), 75 deletions(-) create mode 100644 compiler/testData/codegen/box/inlineClasses/checkBasicUnsignedLiterals.kt delete mode 100644 compiler/testData/codegen/box/inlineClasses/checkPlusOfUInt.kt diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/components/JavaPropertyInitializerEvaluatorImpl.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/components/JavaPropertyInitializerEvaluatorImpl.kt index f92608641b5..a2eca0c9a2c 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/components/JavaPropertyInitializerEvaluatorImpl.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/components/JavaPropertyInitializerEvaluatorImpl.kt @@ -29,7 +29,7 @@ class JavaPropertyInitializerEvaluatorImpl : JavaPropertyInitializerEvaluator { //Note: evaluated expression may be of class that does not match field type in some cases // tested for Int, left other checks just in case is Byte, is Short, is Int, is Long -> { - ConstantValueFactory.createIntegerConstantValue((evaluated as Number).toLong(), descriptor.type) + ConstantValueFactory.createIntegerConstantValue((evaluated as Number).toLong(), descriptor.type, false) } else -> { ConstantValueFactory.createConstantValue(evaluated) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt index 4475f800586..ff92fb2f54d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt @@ -387,11 +387,18 @@ private class ConstantExpressionEvaluatorVisitor( } } - val isLongWithSuffix = nodeElementType == KtNodeTypes.INTEGER_CONSTANT && hasLongSuffix(text) + val isUnsigned = hasUnsignedSuffix(text) + val typedConstant = nodeElementType == KtNodeTypes.INTEGER_CONSTANT && (hasLongSuffix(text) || isUnsigned) return createConstant( result, expectedType, - CompileTimeConstant.Parameters(true, !isLongWithSuffix, false, usesNonConstValAsConstant = false) + CompileTimeConstant.Parameters( + canBeUsedInAnnotation = true, + isPure = !typedConstant, + isUnsigned = isUnsigned, + usesVariableAsConstant = false, + usesNonConstValAsConstant = false + ) ) } @@ -435,6 +442,7 @@ private class ConstantExpressionEvaluatorVisitor( expectedType, CompileTimeConstant.Parameters( isPure = false, + isUnsigned = false, canBeUsedInAnnotation = canBeUsedInAnnotation, usesVariableAsConstant = usesVariableAsConstant, usesNonConstValAsConstant = usesNonConstantVariableAsConstant @@ -497,6 +505,7 @@ private class ConstantExpressionEvaluatorVisitor( CompileTimeConstant.Parameters( canBeUsedInAnnotation = true, isPure = false, + isUnsigned = false, usesVariableAsConstant = leftConstant.usesVariableAsConstant || rightConstant.usesVariableAsConstant, usesNonConstValAsConstant = leftConstant.usesNonConstValAsConstant || rightConstant.usesNonConstValAsConstant ) @@ -544,6 +553,7 @@ private class ConstantExpressionEvaluatorVisitor( CompileTimeConstant.Parameters( canBeUsedInAnnotation, !isNumberConversionMethod && isArgumentPure, + false, usesVariableAsConstant, usesNonConstValAsConstant ) ) @@ -575,8 +585,9 @@ private class ConstantExpressionEvaluatorVisitor( usesVariableAsConstant(argumentForReceiver.expression) || usesVariableAsConstant(argumentForParameter.expression) val usesNonConstValAsConstant = usesNonConstValAsConstant(argumentForReceiver.expression) || usesNonConstValAsConstant(argumentForParameter.expression) - val parameters = - CompileTimeConstant.Parameters(canBeUsedInAnnotation, areArgumentsPure, usesVariableAsConstant, usesNonConstValAsConstant) + val parameters = CompileTimeConstant.Parameters( + canBeUsedInAnnotation, areArgumentsPure, false, usesVariableAsConstant, usesNonConstValAsConstant + ) return when (resultingDescriptorName) { OperatorNameConventions.COMPARE_TO -> createCompileTimeConstantForCompareTo(result, callExpression)?.wrap(parameters) OperatorNameConventions.EQUALS -> createCompileTimeConstantForEquals(result, callExpression)?.wrap(parameters) @@ -696,6 +707,7 @@ private class ConstantExpressionEvaluatorVisitor( CompileTimeConstant.Parameters( canBeUsedInAnnotation = isPropertyCompileTimeConstant(callableDescriptor), isPure = false, + isUnsigned = false, usesVariableAsConstant = true, usesNonConstValAsConstant = !callableDescriptor.isConst ) @@ -899,7 +911,7 @@ private class ConstantExpressionEvaluatorVisitor( expectedType: KotlinType?, parameters: CompileTimeConstant.Parameters ): CompileTimeConstant<*>? { - return if (parameters.isPure) { + return if (parameters.isPure || parameters.isUnsigned) { return createCompileTimeConstant(value, parameters, expectedType ?: TypeUtils.NO_EXPECTED_TYPE) } else { ConstantValueFactory.createConstantValue(value)?.wrap(parameters) @@ -923,15 +935,17 @@ private class ConstantExpressionEvaluatorVisitor( expectedType: KotlinType ): CompileTimeConstant<*>? { if (TypeUtils.noExpectedType(expectedType) || expectedType.isError) { - return IntegerValueTypeConstant(value, builtIns, parameters) + return IntegerValueTypeConstant(value, constantExpressionEvaluator.module, parameters) } - val integerValue = ConstantValueFactory.createIntegerConstantValue(value, expectedType) + val integerValue = ConstantValueFactory.createIntegerConstantValue(value, expectedType, parameters.isUnsigned) if (integerValue != null) { return integerValue.wrap(parameters) } return when (value) { - value.toInt().toLong() -> IntValue(value.toInt()) - else -> LongValue(value) + value.toInt().toLong() -> + if (parameters.isUnsigned) UIntValue(value.toInt()) else IntValue(value.toInt()) + else -> + if (parameters.isUnsigned) ULongValue(value) else LongValue(value) }.wrap(parameters) } @@ -941,13 +955,15 @@ private class ConstantExpressionEvaluatorVisitor( private fun ConstantValue.wrap( canBeUsedInAnnotation: Boolean = this !is NullValue, isPure: Boolean = false, + isUnsigned: Boolean = false, usesVariableAsConstant: Boolean = false, usesNonConstValAsConstant: Boolean = false ): TypedCompileTimeConstant = - wrap(CompileTimeConstant.Parameters(canBeUsedInAnnotation, isPure, usesVariableAsConstant, usesNonConstValAsConstant)) + wrap(CompileTimeConstant.Parameters(canBeUsedInAnnotation, isPure, isUnsigned, usesVariableAsConstant, usesNonConstValAsConstant)) } private fun hasLongSuffix(text: String) = text.endsWith('l') || text.endsWith('L') +private fun hasUnsignedSuffix(text: String) = text.endsWith('u') private fun parseNumericLiteral(text: String, type: IElementType): Any? { val canonicalText = LiteralFormatUtil.removeUnderscores(text) @@ -960,8 +976,8 @@ private fun parseNumericLiteral(text: String, type: IElementType): Any? { private fun parseLong(text: String): Long? { try { - fun substringLongSuffix(s: String) = if (hasLongSuffix(text)) s.substring(0, s.length - 1) else s - fun parseLong(text: String, radix: Int) = java.lang.Long.parseLong(substringLongSuffix(text), radix) + fun substringSuffix(s: String) = if (hasLongSuffix(text) || hasUnsignedSuffix(text)) s.substring(0, s.length - 1) else s + fun parseLong(text: String, radix: Int) = java.lang.Long.parseLong(substringSuffix(text), radix) val (number, radix) = extractRadix(text) return parseLong(number, radix) diff --git a/compiler/testData/codegen/box/inlineClasses/checkBasicUnsignedLiterals.kt b/compiler/testData/codegen/box/inlineClasses/checkBasicUnsignedLiterals.kt new file mode 100644 index 00000000000..1b3bc786c2f --- /dev/null +++ b/compiler/testData/codegen/box/inlineClasses/checkBasicUnsignedLiterals.kt @@ -0,0 +1,16 @@ +// !LANGUAGE: +InlineClasses +// !SKIP_METADATA_VERSION_CHECK +// WITH_UNSIGNED + +fun box(): String { + val u1 = 1u + val u2 = 2u + val u3 = u1 + u2 + if (u3.toInt() != 3) return "fail" + + val max = 0u.dec().toLong() + val expected = Int.MAX_VALUE * 2L + 1 + if (max != expected) return "fail" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/inlineClasses/checkPlusOfUInt.kt b/compiler/testData/codegen/box/inlineClasses/checkPlusOfUInt.kt deleted file mode 100644 index 5a3a02a13c9..00000000000 --- a/compiler/testData/codegen/box/inlineClasses/checkPlusOfUInt.kt +++ /dev/null @@ -1,11 +0,0 @@ -// !LANGUAGE: +InlineClasses -// !SKIP_METADATA_VERSION_CHECK -// WITH_UNSIGNED - -@Suppress("INVISIBLE_MEMBER") -fun box(): String { - val u1 = UInt(1) - val u2 = UInt(2) - val u3 = u1 + u2 - return if (u3.toInt() == 3) "OK" else "fail" -} \ No newline at end of file diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/constraintSystem/ConstraintSystemTestData.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/constraintSystem/ConstraintSystemTestData.kt index 98853aeaa84..634f9128fad 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/constraintSystem/ConstraintSystemTestData.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/constraintSystem/ConstraintSystemTestData.kt @@ -25,8 +25,10 @@ import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.TypeResolver +import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.test.KotlinTestUtils @@ -64,8 +66,13 @@ class ConstraintSystemTestData( val matcher = INTEGER_VALUE_TYPE_PATTERN.matcher(name) if (matcher.find()) { val number = matcher.group(1)!! - return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(Annotations.EMPTY, IntegerValueTypeConstructor(number.toLong(), functionFoo.builtIns), - listOf(), false, MemberScope.Empty + val parameters = CompileTimeConstant.Parameters(false, false, false, false, false) + return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope( + Annotations.EMPTY, + IntegerValueTypeConstructor(number.toLong(), functionFoo.module, parameters), + listOf(), + false, + MemberScope.Empty ) } return typeResolver.resolveType( 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 6f0fc4a0494..f53cbfba631 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 @@ -11179,6 +11179,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt"); } + @TestMetadata("checkBasicUnsignedLiterals.kt") + public void testCheckBasicUnsignedLiterals() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/checkBasicUnsignedLiterals.kt"); + } + @TestMetadata("checkBoxUnboxOfArgumentsOnInlinedFunctions.kt") public void testCheckBoxUnboxOfArgumentsOnInlinedFunctions() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/checkBoxUnboxOfArgumentsOnInlinedFunctions.kt"); @@ -11229,11 +11234,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/inlineClasses/checkLambdaWithInlineClassesInFunctionalType.kt"); } - @TestMetadata("checkPlusOfUInt.kt") - public void testCheckPlusOfUInt() throws Exception { - runTest("compiler/testData/codegen/box/inlineClasses/checkPlusOfUInt.kt"); - } - @TestMetadata("checkUnboxingResultFromTypeVariable.kt") public void testCheckUnboxingResultFromTypeVariable() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/checkUnboxingResultFromTypeVariable.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index fcc375e9d52..ed265c2d887 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -11179,6 +11179,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt"); } + @TestMetadata("checkBasicUnsignedLiterals.kt") + public void testCheckBasicUnsignedLiterals() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/checkBasicUnsignedLiterals.kt"); + } + @TestMetadata("checkBoxUnboxOfArgumentsOnInlinedFunctions.kt") public void testCheckBoxUnboxOfArgumentsOnInlinedFunctions() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/checkBoxUnboxOfArgumentsOnInlinedFunctions.kt"); @@ -11229,11 +11234,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/inlineClasses/checkLambdaWithInlineClassesInFunctionalType.kt"); } - @TestMetadata("checkPlusOfUInt.kt") - public void testCheckPlusOfUInt() throws Exception { - runTest("compiler/testData/codegen/box/inlineClasses/checkPlusOfUInt.kt"); - } - @TestMetadata("checkUnboxingResultFromTypeVariable.kt") public void testCheckUnboxingResultFromTypeVariable() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/checkUnboxingResultFromTypeVariable.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 329daaaa0ed..3610b60b3c6 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -11179,6 +11179,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt"); } + @TestMetadata("checkBasicUnsignedLiterals.kt") + public void testCheckBasicUnsignedLiterals() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/checkBasicUnsignedLiterals.kt"); + } + @TestMetadata("checkBoxUnboxOfArgumentsOnInlinedFunctions.kt") public void testCheckBoxUnboxOfArgumentsOnInlinedFunctions() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/checkBoxUnboxOfArgumentsOnInlinedFunctions.kt"); @@ -11229,11 +11234,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/inlineClasses/checkLambdaWithInlineClassesInFunctionalType.kt"); } - @TestMetadata("checkPlusOfUInt.kt") - public void testCheckPlusOfUInt() throws Exception { - runTest("compiler/testData/codegen/box/inlineClasses/checkPlusOfUInt.kt"); - } - @TestMetadata("checkUnboxingResultFromTypeVariable.kt") public void testCheckUnboxingResultFromTypeVariable() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/checkUnboxingResultFromTypeVariable.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index b9540cb8548..0ef3976a2b0 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -332,6 +332,15 @@ public abstract class KotlinBuiltIns { public final FqNameUnsafe kMutableProperty2 = reflect("KMutableProperty2"); public final ClassId kProperty = ClassId.topLevel(reflect("KProperty").toSafe()); + public final FqName uByteFqName = fqName("UByte"); + public final FqName uShortFqName = fqName("UShort"); + public final FqName uIntFqName = fqName("UInt"); + public final FqName uLongFqName = fqName("ULong"); + public final ClassId uByte = ClassId.topLevel(uByteFqName); + public final ClassId uShort = ClassId.topLevel(uShortFqName); + public final ClassId uInt = ClassId.topLevel(uIntFqName); + public final ClassId uLong = ClassId.topLevel(uLongFqName); + public final Set primitiveTypeShortNames = newHashSetWithExpectedSize(PrimitiveType.values().length); public final Set primitiveArrayTypeShortNames = newHashSetWithExpectedSize(PrimitiveType.values().length); public final Map fqNameToPrimitiveType = newHashMapWithExpectedSize(PrimitiveType.values().length); @@ -975,6 +984,22 @@ public abstract class KotlinBuiltIns { return isDoubleOrNullableDouble(type) && !type.isMarkedNullable(); } + public static boolean isUByte(@NotNull KotlinType type) { + return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES.uByteFqName.toUnsafe()); + } + + public static boolean isUShort(@NotNull KotlinType type) { + return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES.uShortFqName.toUnsafe()); + } + + public static boolean isUInt(@NotNull KotlinType type) { + return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES.uIntFqName.toUnsafe()); + } + + public static boolean isULong(@NotNull KotlinType type) { + return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES.uLongFqName.toUnsafe()); + } + public static boolean isDoubleOrNullableDouble(@NotNull KotlinType type) { return isConstructedFromGivenClass(type, FQ_NAMES._double); } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstant.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstant.kt index a377e34028b..8d7a734462c 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstant.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstant.kt @@ -42,9 +42,12 @@ interface CompileTimeConstant { val isPure: Boolean get() = parameters.isPure + val isUnsigned: Boolean get() = parameters.isUnsigned + class Parameters( val canBeUsedInAnnotation: Boolean, val isPure: Boolean, + val isUnsigned: Boolean, val usesVariableAsConstant: Boolean, val usesNonConstValAsConstant: Boolean ) @@ -84,10 +87,10 @@ class TypedCompileTimeConstant( class IntegerValueTypeConstant( private val value: Number, - builtIns: KotlinBuiltIns, + module: ModuleDescriptor, override val parameters: CompileTimeConstant.Parameters ) : CompileTimeConstant { - private val typeConstructor = IntegerValueTypeConstructor(value.toLong(), builtIns) + private val typeConstructor = IntegerValueTypeConstructor(value.toLong(), module, parameters) override fun toConstantValue(expectedType: KotlinType): ConstantValue { val type = getType(expectedType) @@ -95,6 +98,13 @@ class IntegerValueTypeConstant( KotlinBuiltIns.isInt(type) -> IntValue(value.toInt()) KotlinBuiltIns.isByte(type) -> ByteValue(value.toByte()) KotlinBuiltIns.isShort(type) -> ShortValue(value.toShort()) + KotlinBuiltIns.isLong(type) -> LongValue(value.toLong()) + + KotlinBuiltIns.isUInt(type) -> UIntValue(value.toInt()) + KotlinBuiltIns.isUByte(type) -> UByteValue(value.toByte()) + KotlinBuiltIns.isUShort(type) -> UShortValue(value.toShort()) + KotlinBuiltIns.isULong(type) -> ULongValue(value.toLong()) + else -> LongValue(value.toLong()) } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ConstantValueFactory.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ConstantValueFactory.kt index f83e9fc82c4..cb8def2a96c 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ConstantValueFactory.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/ConstantValueFactory.kt @@ -18,7 +18,6 @@ package org.jetbrains.kotlin.resolve.constants import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.PrimitiveType -import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils @@ -51,10 +50,10 @@ object ConstantValueFactory { fun createUnsignedValue(constantValue: ConstantValue<*>, type: KotlinType): UnsignedValueConstant<*>? { return when (constantValue) { - is ByteValue -> UByteValue(constantValue, type) - is ShortValue -> UShortValue(constantValue, type) - is IntValue -> UIntValue(constantValue, type) - is LongValue -> ULongValue(constantValue, type) + is ByteValue -> UByteValue(constantValue.value) + is ShortValue -> UShortValue(constantValue.value) + is IntValue -> UIntValue(constantValue.value) + is LongValue -> ULongValue(constantValue.value) else -> null } } @@ -66,16 +65,27 @@ object ConstantValueFactory { fun createIntegerConstantValue( value: Long, - expectedType: KotlinType + expectedType: KotlinType, + isUnsigned: Boolean ): ConstantValue<*>? { val notNullExpected = TypeUtils.makeNotNullable(expectedType) - return when { - KotlinBuiltIns.isLong(notNullExpected) -> LongValue(value) - KotlinBuiltIns.isInt(notNullExpected) && value == value.toInt().toLong() -> IntValue(value.toInt()) - KotlinBuiltIns.isShort(notNullExpected) && value == value.toShort().toLong() -> ShortValue(value.toShort()) - KotlinBuiltIns.isByte(notNullExpected) && value == value.toByte().toLong() -> ByteValue(value.toByte()) - KotlinBuiltIns.isChar(notNullExpected) -> IntValue(value.toInt()) - else -> null + return if (isUnsigned) { + when { + KotlinBuiltIns.isUByte(notNullExpected) && value == value.toByte().toLong() -> UByteValue(value.toByte()) + KotlinBuiltIns.isUShort(notNullExpected) && value == value.toShort().toLong() -> UShortValue(value.toShort()) + KotlinBuiltIns.isUInt(notNullExpected) && value == value.toInt().toLong() -> UIntValue(value.toInt()) + KotlinBuiltIns.isULong(notNullExpected) -> ULongValue(value) + else -> null + } + } else { + when { + KotlinBuiltIns.isLong(notNullExpected) -> LongValue(value) + KotlinBuiltIns.isInt(notNullExpected) && value == value.toInt().toLong() -> IntValue(value.toInt()) + KotlinBuiltIns.isShort(notNullExpected) && value == value.toShort().toLong() -> ShortValue(value.toShort()) + KotlinBuiltIns.isByte(notNullExpected) && value == value.toByte().toLong() -> ByteValue(value.toByte()) + KotlinBuiltIns.isChar(notNullExpected) -> IntValue(value.toInt()) + else -> null + } } } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueTypeConstructor.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueTypeConstructor.kt index c1d268f169d..3112201e2a5 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueTypeConstructor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueTypeConstructor.kt @@ -17,14 +17,20 @@ package org.jetbrains.kotlin.resolve.constants import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.SimpleType import org.jetbrains.kotlin.types.TypeConstructor import java.util.* class IntegerValueTypeConstructor( - private val value: Long, - private val builtIns: KotlinBuiltIns + private val value: Long, + private val module: ModuleDescriptor, + parameters: CompileTimeConstant.Parameters ) : TypeConstructor { private val supertypes = ArrayList(4) @@ -32,10 +38,28 @@ class IntegerValueTypeConstructor( // order of types matters // 'getPrimitiveNumberType' returns first of supertypes that is a subtype of expected type // for expected type 'Any' result type 'Int' should be returned - checkBoundsAndAddSuperType(value, Integer.MIN_VALUE.toLong(), Integer.MAX_VALUE.toLong(), builtIns.intType) - checkBoundsAndAddSuperType(value, java.lang.Byte.MIN_VALUE.toLong(), java.lang.Byte.MAX_VALUE.toLong(), builtIns.byteType) - checkBoundsAndAddSuperType(value, java.lang.Short.MIN_VALUE.toLong(), java.lang.Short.MAX_VALUE.toLong(), builtIns.shortType) - supertypes.add(builtIns.longType) + val isUnsigned = parameters.isUnsigned + + // TODO: fix value ranges for unsigned types + checkBoundsAndAddSuperType( + value, + 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) } private fun checkBoundsAndAddSuperType(value: Long, minValue: Long, maxValue: Long, kotlinType: KotlinType) { @@ -44,6 +68,9 @@ class IntegerValueTypeConstructor( } } + private fun unsignedType(classId: ClassId): SimpleType = + module.findClassAcrossModuleDependencies(classId)?.defaultType ?: ErrorUtils.createErrorType("Error type for $classId") + override fun getSupertypes(): Collection = supertypes override fun getParameters(): List = emptyList() @@ -57,7 +84,7 @@ class IntegerValueTypeConstructor( fun getValue(): Long = value override fun getBuiltIns(): KotlinBuiltIns { - return builtIns + return module.builtIns } override fun toString() = "IntegerValueType($value)" diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt index 09c47bb16aa..8f2e9141232 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt @@ -40,9 +40,7 @@ abstract class ConstantValue(open val value: T) { } abstract class IntegerValueConstant protected constructor(value: T) : ConstantValue(value) -abstract class UnsignedValueConstant protected constructor(value: T, private val kotlinType: KotlinType) : ConstantValue(value) { - override fun getType(module: ModuleDescriptor): KotlinType = kotlinType -} +abstract class UnsignedValueConstant protected constructor(value: T) : ConstantValue(value) class AnnotationValue(value: AnnotationDescriptor) : ConstantValue(value) { override fun getType(module: ModuleDescriptor): KotlinType = value.type @@ -193,25 +191,45 @@ class StringValue(value: String) : ConstantValue(value) { override fun toString() = "\"$value\"" } -class UByteValue(byteValue: ByteValue, kotlinType: KotlinType) : UnsignedValueConstant(byteValue.value, kotlinType) { +class UByteValue(byteValue: Byte) : UnsignedValueConstant(byteValue) { + override fun getType(module: ModuleDescriptor): KotlinType { + return module.findClassAcrossModuleDependencies(KotlinBuiltIns.FQ_NAMES.uByte)?.defaultType + ?: ErrorUtils.createErrorType("Unsigned type UByte not found") + } + override fun accept(visitor: AnnotationArgumentVisitor, data: D): R = visitor.visitUByteValue(this, data) override fun toString() = "$value.toUByte()" } -class UShortValue(shortValue: ShortValue, kotlinType: KotlinType) : UnsignedValueConstant(shortValue.value, kotlinType) { +class UShortValue(shortValue: Short) : UnsignedValueConstant(shortValue) { + override fun getType(module: ModuleDescriptor): KotlinType { + return module.findClassAcrossModuleDependencies(KotlinBuiltIns.FQ_NAMES.uShort)?.defaultType + ?: ErrorUtils.createErrorType("Unsigned type UByte not found") + } + override fun accept(visitor: AnnotationArgumentVisitor, data: D): R = visitor.visitUShortValue(this, data) override fun toString() = "$value.toUShort()" } -class UIntValue(intValue: IntValue, kotlinType: KotlinType) : UnsignedValueConstant(intValue.value, kotlinType) { +class UIntValue(intValue: Int) : UnsignedValueConstant(intValue) { + override fun getType(module: ModuleDescriptor): KotlinType { + return module.findClassAcrossModuleDependencies(KotlinBuiltIns.FQ_NAMES.uInt)?.defaultType + ?: ErrorUtils.createErrorType("Unsigned type UByte not found") + } + override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitUIntValue(this, data) override fun toString() = "$value.toUInt()" } -class ULongValue(longValue: LongValue, kotlinType: KotlinType) : UnsignedValueConstant(longValue.value, kotlinType) { +class ULongValue(longValue: Long) : UnsignedValueConstant(longValue) { + override fun getType(module: ModuleDescriptor): KotlinType { + return module.findClassAcrossModuleDependencies(KotlinBuiltIns.FQ_NAMES.uLong)?.defaultType + ?: ErrorUtils.createErrorType("Unsigned type UByte not found") + } + override fun accept(visitor: AnnotationArgumentVisitor, data: D): R = visitor.visitULongValue(this, data) override fun toString() = "$value.toULong()" diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java index c816e97b65f..18f0536ee8a 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java @@ -15,6 +15,9 @@ import org.jetbrains.kotlin.descriptors.ClassifierDescriptor; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; import org.jetbrains.kotlin.descriptors.annotations.Annotations; +import org.jetbrains.kotlin.name.FqName; +import org.jetbrains.kotlin.name.FqNameUnsafe; +import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor; import org.jetbrains.kotlin.resolve.scopes.MemberScope; import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; @@ -445,6 +448,27 @@ public class TypeUtils { if (supertypes.contains(longType)) { return longType; } + + KotlinType uIntType = findByFqName(supertypes, KotlinBuiltIns.FQ_NAMES.uIntFqName); + if (uIntType != null) return uIntType; + + KotlinType uLongType = findByFqName(supertypes, KotlinBuiltIns.FQ_NAMES.uLongFqName); + if (uLongType != null) return uLongType; + + return null; + } + + @Nullable + private static KotlinType findByFqName(@NotNull Collection supertypes, FqName fqName) { + for (KotlinType supertype : supertypes) { + ClassifierDescriptor descriptor = supertype.getConstructor().getDeclarationDescriptor(); + if (descriptor == null) continue; + + FqNameUnsafe descriptorFqName = DescriptorUtils.getFqName(descriptor); + if (descriptorFqName.equals(fqName.toUnsafe())) { + return supertype; + } + } return null; } 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 426225a8dbf..8e07baf71eb 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 @@ -9715,6 +9715,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt"); } + @TestMetadata("checkBasicUnsignedLiterals.kt") + public void testCheckBasicUnsignedLiterals() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/checkBasicUnsignedLiterals.kt"); + } + @TestMetadata("checkBoxUnboxOfArgumentsOnInlinedFunctions.kt") public void testCheckBoxUnboxOfArgumentsOnInlinedFunctions() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/checkBoxUnboxOfArgumentsOnInlinedFunctions.kt"); @@ -9765,11 +9770,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/inlineClasses/checkLambdaWithInlineClassesInFunctionalType.kt"); } - @TestMetadata("checkPlusOfUInt.kt") - public void testCheckPlusOfUInt() throws Exception { - runTest("compiler/testData/codegen/box/inlineClasses/checkPlusOfUInt.kt"); - } - @TestMetadata("checkUnboxingResultFromTypeVariable.kt") public void testCheckUnboxingResultFromTypeVariable() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/checkUnboxingResultFromTypeVariable.kt");