diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java index da9d12ed685..51496fae653 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java @@ -48,6 +48,7 @@ import java.util.Collection; import java.util.Collections; import static org.jetbrains.kotlin.util.slicedMap.RewritePolicy.DO_NOTHING; +import static org.jetbrains.kotlin.util.slicedMap.Slices.COMPILE_TIME_VALUE_REWRITE_POLICY; public interface BindingContext { BindingContext EMPTY = new BindingContext() { @@ -89,7 +90,7 @@ public interface BindingContext { WritableSlice ANNOTATION = Slices.createSimpleSlice(); - WritableSlice> COMPILE_TIME_VALUE = Slices.createSimpleSlice(); + WritableSlice> COMPILE_TIME_VALUE = new BasicWritableSlice<>(COMPILE_TIME_VALUE_REWRITE_POLICY); WritableSlice TYPE = Slices.createSimpleSlice(); WritableSlice ABBREVIATED_TYPE = Slices.createSimpleSlice(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java index eb98195fb84..481676f64ac 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java @@ -23,15 +23,14 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.FunctionTypesKt; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.ReflectionTypes; +import org.jetbrains.kotlin.builtins.UnsignedTypes; +import org.jetbrains.kotlin.descriptors.ModuleDescriptor; import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.name.SpecialNames; import org.jetbrains.kotlin.psi.*; -import org.jetbrains.kotlin.resolve.BindingTrace; -import org.jetbrains.kotlin.resolve.StatementFilter; -import org.jetbrains.kotlin.resolve.TemporaryBindingTrace; -import org.jetbrains.kotlin.resolve.TypeResolver; +import org.jetbrains.kotlin.resolve.*; import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode; import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext; import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode; @@ -41,6 +40,8 @@ import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil; +import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; +import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant; import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor; import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator; import org.jetbrains.kotlin.resolve.scopes.LexicalScope; @@ -69,6 +70,7 @@ public class ArgumentTypeResolver { @NotNull private final ReflectionTypes reflectionTypes; @NotNull private final ConstantExpressionEvaluator constantExpressionEvaluator; @NotNull private final FunctionPlaceholders functionPlaceholders; + @NotNull private final ModuleDescriptor moduleDescriptor; private ExpressionTypingServices expressionTypingServices; @@ -78,7 +80,8 @@ public class ArgumentTypeResolver { @NotNull KotlinBuiltIns builtIns, @NotNull ReflectionTypes reflectionTypes, @NotNull ConstantExpressionEvaluator constantExpressionEvaluator, - @NotNull FunctionPlaceholders functionPlaceholders + @NotNull FunctionPlaceholders functionPlaceholders, + @NotNull ModuleDescriptor moduleDescriptor ) { this.typeResolver = typeResolver; this.doubleColonExpressionResolver = doubleColonExpressionResolver; @@ -86,6 +89,7 @@ public class ArgumentTypeResolver { this.reflectionTypes = reflectionTypes; this.constantExpressionEvaluator = constantExpressionEvaluator; this.functionPlaceholders = functionPlaceholders; + this.moduleDescriptor = moduleDescriptor; } // component dependency cycle @@ -218,6 +222,11 @@ public class ArgumentTypeResolver { return expressionTypingServices.getTypeInfo(expression, newContext); } + // TODO: probably should be "is unsigned type or is supertype of unsigned type" to support Comparable expected types too + if (UnsignedTypes.INSTANCE.isUnsignedType(context.expectedType)) { + convertSignedConstantToUnsigned(expression, context); + } + KotlinTypeInfo recordedTypeInfo = getRecordedTypeInfo(expression, context.trace.getBindingContext()); if (recordedTypeInfo != null) { return recordedTypeInfo; @@ -228,6 +237,28 @@ public class ArgumentTypeResolver { return expressionTypingServices.getTypeInfo(expression, newContext); } + private void convertSignedConstantToUnsigned( + @NotNull KtExpression expression, + @NotNull CallResolutionContext context + ) { + CompileTimeConstant constant = context.trace.get(BindingContext.COMPILE_TIME_VALUE, expression); + if (!(constant instanceof IntegerValueTypeConstant) || !constantCanBeConvertedToUnsigned(constant)) return; + + IntegerValueTypeConstant unsignedConstant = IntegerValueTypeConstant.convertToUnsignedConstant( + (IntegerValueTypeConstant) constant, moduleDescriptor + ); + + context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, unsignedConstant); + + updateResultArgumentTypeIfNotDenotable( + context.trace, context.statementFilter, context.expectedType, unsignedConstant.getUnknownIntegerType(), expression + ); + } + + public static boolean constantCanBeConvertedToUnsigned(@NotNull CompileTimeConstant constant) { + return !constant.isError() && constant.getParameters().isPure(); + } + @NotNull public KotlinTypeInfo getCallableReferenceTypeInfo( @NotNull KtExpression expression, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt index c122efdd3f1..2427ed1d7e5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt @@ -50,6 +50,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant +import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer @@ -309,9 +310,7 @@ class CallCompleter( private fun createTypeForConvertableConstant(constant: CompileTimeConstant<*>): SimpleType? { val value = constant.getValue(TypeUtils.NO_EXPECTED_TYPE).safeAs()?.toLong() ?: return null - val typeConstructor = IntegerValueTypeConstructor( - value, moduleDescriptor, constant.parameters - ) + val typeConstructor = IntegerValueTypeConstructor(value, moduleDescriptor, constant.parameters) return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope( Annotations.EMPTY, typeConstructor, emptyList(), false, ErrorUtils.createErrorScope("Scope for number value type ($typeConstructor)", true) @@ -332,11 +331,17 @@ class CallCompleter( var updatedType: KotlinType? = recordedType val results = completeCallForArgument(deparenthesized, context) + if (results != null && results.isSingleResult) { val resolvedCall = results.resultingCall - updatedType = if (resolvedCall.hasInferredReturnType()) { - resolvedCall.makeNullableTypeIfSafeReceiver(resolvedCall.resultingDescriptor?.returnType, context) - } else null + val constant = context.trace[BindingContext.COMPILE_TIME_VALUE, deparenthesized] + if (constant !is IntegerValueTypeConstant || !constant.convertedFromSigned) { + updatedType = + if (resolvedCall.hasInferredReturnType()) + resolvedCall.makeNullableTypeIfSafeReceiver(resolvedCall.resultingDescriptor?.returnType, context) + else + null + } } // For the cases like 'foo(1)' the type of '1' depends on expected type (it can be Int, Byte, etc.), diff --git a/compiler/frontend/src/org/jetbrains/kotlin/util/slicedMap/Slices.java b/compiler/frontend/src/org/jetbrains/kotlin/util/slicedMap/Slices.java index d89a3312bde..3b70747a8e6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/util/slicedMap/Slices.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/util/slicedMap/Slices.java @@ -20,6 +20,9 @@ import com.intellij.openapi.diagnostic.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.psi.KtElement; import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt; +import org.jetbrains.kotlin.resolve.constants.ConstantValueFactoryKt; +import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant; +import org.jetbrains.kotlin.types.TypeUtils; import java.util.Arrays; import java.util.List; @@ -36,17 +39,47 @@ public class Slices { @Override public boolean processRewrite(WritableSlice slice, K key, V oldValue, V newValue) { if (!((oldValue == null && newValue == null) || (oldValue != null && oldValue.equals(newValue)))) { - // NOTE: Use BindingTraceContext.TRACK_REWRITES to debug this exception - LOG.error("Rewrite at slice " + slice + - " key: " + key + - " old value: " + oldValue + '@' + System.identityHashCode(oldValue) + - " new value: " + newValue + '@' + System.identityHashCode(newValue) + - (key instanceof KtElement ? "\n" + PsiUtilsKt.getElementTextWithContext((KtElement) key) : "")); + logErrorAboutRewritingNonEqualObjects(slice, key, oldValue, newValue); } return true; } }; + // Rewrite is allowed for equal objects and for signed constant values that were converted to unsigned ones + // This is needed to avoid making `CompileTimeConstant` mutable + public static final RewritePolicy COMPILE_TIME_VALUE_REWRITE_POLICY = new RewritePolicy() { + @Override + public boolean rewriteProcessingNeeded(K key) { + return true; + } + + @Override + public boolean processRewrite(WritableSlice slice, K key, V oldValue, V newValue) { + if ((oldValue == null && newValue == null) || (oldValue != null && oldValue.equals(newValue))) return true; + + if (oldValue instanceof IntegerValueTypeConstant && newValue instanceof IntegerValueTypeConstant) { + IntegerValueTypeConstant oldConstant = (IntegerValueTypeConstant) oldValue; + IntegerValueTypeConstant newConstant = (IntegerValueTypeConstant) newValue; + + if (oldConstant.getParameters().isPure() && newConstant.getParameters().isUnsignedNumberLiteral()) { + long oldConstantValue = oldConstant.getValue(TypeUtils.NO_EXPECTED_TYPE).longValue(); + Number newConstantValue = newConstant.getValue(TypeUtils.NO_EXPECTED_TYPE); + if (oldConstantValue == newConstantValue.longValue() || + oldConstantValue == ConstantValueFactoryKt.fromUIntToLong(newConstantValue.intValue()) || + oldConstantValue == ConstantValueFactoryKt.fromUByteToLong(newConstantValue.byteValue()) || + oldConstantValue == ConstantValueFactoryKt.fromUShortToLong(newConstantValue.shortValue()) + ) { + return true; + } + } + } + + logErrorAboutRewritingNonEqualObjects(slice, key, oldValue, newValue); + + return true; + } + }; + private Slices() { } @@ -118,4 +151,13 @@ public class Slices { return new BasicWritableSlice<>(rewritePolicy); } } + + private static void logErrorAboutRewritingNonEqualObjects(WritableSlice slice, K key, V oldValue, V newValue) { + // NOTE: Use BindingTraceContext.TRACK_REWRITES to debug this exception + LOG.error("Rewrite at slice " + slice + + " key: " + key + + " old value: " + oldValue + '@' + System.identityHashCode(oldValue) + + " new value: " + newValue + '@' + System.identityHashCode(newValue) + + (key instanceof KtElement ? "\n" + PsiUtilsKt.getElementTextWithContext((KtElement) key) : "")); + } } diff --git a/compiler/testData/codegen/box/unsignedTypes/signedToUnsignedLiteralConversion.kt b/compiler/testData/codegen/box/unsignedTypes/signedToUnsignedLiteralConversion.kt new file mode 100644 index 00000000000..4945b14ea59 --- /dev/null +++ b/compiler/testData/codegen/box/unsignedTypes/signedToUnsignedLiteralConversion.kt @@ -0,0 +1,23 @@ +// WITH_UNSIGNED +// IGNORE_BACKEND: JS_IR, JVM_IR, JS + +fun takeUByte(u: UByte) = u.toByte() +fun takeUShort(u: UShort) = u.toShort() +fun takeUInt(u: UInt) = u.toInt() +fun takeULong(u: ULong) = u.toLong() + +fun box(): String { + val b = takeUByte(200 + 55) + if (b != (-1).toByte()) return "Fail 1: $b" + + val s = takeUShort(123) + if (s != 123.toShort()) return "Fail 2: $s" + + val i = takeUInt(0xFFFF_FFFF) + if (i != -1) return "Fail 3: $i" + + val l = takeULong(0xFFFF_FFFF_FFFF) + if (l != 0xFFFF_FFFF_FFFFL) return "Fail 4: $l" + + return "OK" +} diff --git a/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/inferenceForSignedAndUnsignedTypes.kt b/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/inferenceForSignedAndUnsignedTypes.kt new file mode 100644 index 00000000000..c3116fec67e --- /dev/null +++ b/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/inferenceForSignedAndUnsignedTypes.kt @@ -0,0 +1,17 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER, -UNUSED_VARIABLE +// !CHECK_TYPE + +// Here we mostly trying to fix behaviour in order to track changes in inference rules for unsigned types later + +fun id(x: T): T = x +fun select(x: K, y: K): K = TODO() + +fun takeUByte(u: UByte) {} + +fun foo() { + select(1, 1u) checkType { _>() } + takeUByte(id(1)) + + 1 + 1u + (1u + 1) checkType { _() } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/inferenceForSignedAndUnsignedTypes.txt b/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/inferenceForSignedAndUnsignedTypes.txt new file mode 100644 index 00000000000..76bd0a5be37 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/inferenceForSignedAndUnsignedTypes.txt @@ -0,0 +1,6 @@ +package + +public fun foo(): kotlin.Unit +public fun id(/*0*/ x: T): T +public fun select(/*0*/ x: K, /*1*/ y: K): K +public fun takeUByte(/*0*/ u: kotlin.UByte): kotlin.Unit diff --git a/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/signedToUnsignedConversionWithExpectedType.kt b/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/signedToUnsignedConversionWithExpectedType.kt new file mode 100644 index 00000000000..4d59ea179cf --- /dev/null +++ b/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/signedToUnsignedConversionWithExpectedType.kt @@ -0,0 +1,64 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun takeUByte(u: UByte) {} +fun takeUShort(u: UShort) {} +fun takeUInt(u: UInt) {} +fun takeULong(u: ULong) {} + +fun takeUBytes(vararg u: UByte) {} + +fun takeNullableUInt(u: UInt?) {} + +fun test() { + takeUInt(1 + 2) + takeUInt(1.plus(2)) + takeNullableUInt(4) + + takeUInt(Int.MAX_VALUE * 2L) + takeUInt(-1) + takeUInt(Int.MAX_VALUE * 2L + 2) + + takeUByte(1) + takeUByte(255) + takeUByte(1.toByte()) + + takeUShort(1) + takeUInt(1) + takeULong(1) + + takeULong(18446744073709551615) + takeULong(1844674407370955161) + takeULong(18446744073709551615u) + + takeUInt(Int.MAX_VALUE * 2) + takeUInt(4294967294) + + takeUBytes(1, 2, 255, 256, 0, -1, 40 + 2) + + takeUInt(1.myPlus(2)) + + val localVariable = 42 + takeUInt(localVariable) + + var localMutableVariable = 42 + takeUInt(localMutableVariable) + + val localNegativeVariable = -1 + takeUInt(localNegativeVariable) + + takeUInt(globalVariable) + + takeUInt(constVal) + + takeUInt(globalVariableWithGetter) +} + +val globalVariable = 10 + +const val constVal = 10 + +val globalVariableWithGetter: Int get() = 0 + +val prop: UByte = 255 + +fun Int.myPlus(other: Int): Int = this + other diff --git a/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/signedToUnsignedConversionWithExpectedType.txt b/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/signedToUnsignedConversionWithExpectedType.txt new file mode 100644 index 00000000000..707b79bc0ff --- /dev/null +++ b/compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/signedToUnsignedConversionWithExpectedType.txt @@ -0,0 +1,14 @@ +package + +public const val constVal: kotlin.Int = 10 +public val globalVariable: kotlin.Int = 10 +public val globalVariableWithGetter: kotlin.Int +public val prop: kotlin.UByte = 255 +public fun takeNullableUInt(/*0*/ u: kotlin.UInt?): kotlin.Unit +public fun takeUByte(/*0*/ u: kotlin.UByte): kotlin.Unit +public fun takeUBytes(/*0*/ vararg u: kotlin.UByte /*kotlin.UByteArray*/): kotlin.Unit +public fun takeUInt(/*0*/ u: kotlin.UInt): kotlin.Unit +public fun takeULong(/*0*/ u: kotlin.ULong): kotlin.Unit +public fun takeUShort(/*0*/ u: kotlin.UShort): kotlin.Unit +public fun test(): kotlin.Unit +public fun kotlin.Int.myPlus(/*0*/ other: kotlin.Int): kotlin.Int diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsWithUnsignedTypesGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsWithUnsignedTypesGenerated.java index b37c3714548..cd34b4f573a 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsWithUnsignedTypesGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsWithUnsignedTypesGenerated.java @@ -100,5 +100,20 @@ public class DiagnosticsWithUnsignedTypesGenerated extends AbstractDiagnosticsWi public void testConversionOfSignedToUnsigned() throws Exception { runTest("compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/conversionOfSignedToUnsigned.kt"); } + + @TestMetadata("inferenceForSignedAndUnsignedTypes.kt") + public void testInferenceForSignedAndUnsignedTypes() throws Exception { + runTest("compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/inferenceForSignedAndUnsignedTypes.kt"); + } + + @TestMetadata("overloadResolutionForSignedAndUnsignedTypes.kt") + public void testOverloadResolutionForSignedAndUnsignedTypes() throws Exception { + runTest("compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/overloadResolutionForSignedAndUnsignedTypes.kt"); + } + + @TestMetadata("signedToUnsignedConversionWithExpectedType.kt") + public void testSignedToUnsignedConversionWithExpectedType() throws Exception { + runTest("compiler/testData/diagnostics/testsWithUnsignedTypes/conversions/signedToUnsignedConversionWithExpectedType.kt"); + } } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index db2a0763e66..fec8ad9e1fb 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -21860,6 +21860,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/unsignedTypes/iterateOverListOfBoxedUnsignedValues.kt"); } + @TestMetadata("signedToUnsignedLiteralConversion.kt") + public void testSignedToUnsignedLiteralConversion() throws Exception { + runTest("compiler/testData/codegen/box/unsignedTypes/signedToUnsignedLiteralConversion.kt"); + } + @TestMetadata("unsignedLiteralsWithSignedOverflow.kt") public void testUnsignedLiteralsWithSignedOverflow() throws Exception { runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLiteralsWithSignedOverflow.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index fe284acf475..35974393b9b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -21860,6 +21860,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/unsignedTypes/iterateOverListOfBoxedUnsignedValues.kt"); } + @TestMetadata("signedToUnsignedLiteralConversion.kt") + public void testSignedToUnsignedLiteralConversion() throws Exception { + runTest("compiler/testData/codegen/box/unsignedTypes/signedToUnsignedLiteralConversion.kt"); + } + @TestMetadata("unsignedLiteralsWithSignedOverflow.kt") public void testUnsignedLiteralsWithSignedOverflow() throws Exception { runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLiteralsWithSignedOverflow.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 5042df6b66b..2ab60f14c4e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -21860,6 +21860,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/unsignedTypes/iterateOverListOfBoxedUnsignedValues.kt"); } + @TestMetadata("signedToUnsignedLiteralConversion.kt") + public void testSignedToUnsignedLiteralConversion() throws Exception { + runTest("compiler/testData/codegen/box/unsignedTypes/signedToUnsignedLiteralConversion.kt"); + } + @TestMetadata("unsignedLiteralsWithSignedOverflow.kt") public void testUnsignedLiteralsWithSignedOverflow() throws Exception { runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLiteralsWithSignedOverflow.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/UnsignedType.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/UnsignedType.kt index 1b63cfeed64..8ece3896068 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/UnsignedType.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/UnsignedType.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.KotlinType -import kotlin.reflect.KClass +import org.jetbrains.kotlin.types.TypeUtils enum class UnsignedType(val classId: ClassId) { @@ -28,6 +28,8 @@ object UnsignedTypes { val unsignedTypeNames = enumValues().map { it.typeName }.toSet() fun isUnsignedType(type: KotlinType): Boolean { + if (TypeUtils.noExpectedType(type)) return false + val descriptor = type.constructor.declarationDescriptor ?: return false return isUnsignedClass(descriptor) } 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 0043a7ba9e0..01681b74872 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstant.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstant.kt @@ -122,10 +122,28 @@ class UnsignedErrorValueTypeConstant( } class IntegerValueTypeConstant( - private val value: Number, - module: ModuleDescriptor, - override val parameters: CompileTimeConstant.Parameters + private val value: Number, + module: ModuleDescriptor, + override val parameters: CompileTimeConstant.Parameters, + val convertedFromSigned: Boolean = false ) : CompileTimeConstant { + companion object { + @JvmStatic + fun IntegerValueTypeConstant.convertToUnsignedConstant(module: ModuleDescriptor): IntegerValueTypeConstant { + val newParameters = CompileTimeConstant.Parameters( + parameters.canBeUsedInAnnotation, + parameters.isPure, + isUnsignedNumberLiteral = true, + isUnsignedLongNumberLiteral = parameters.isUnsignedLongNumberLiteral, + usesVariableAsConstant = parameters.usesVariableAsConstant, + usesNonConstValAsConstant = parameters.usesNonConstValAsConstant, + isConvertableConstVal = parameters.isConvertableConstVal + ) + + return IntegerValueTypeConstant(value, module, newParameters, convertedFromSigned = true) + } + } + private val typeConstructor = IntegerValueTypeConstructor(value.toLong(), module, parameters) override fun toConstantValue(expectedType: KotlinType): ConstantValue { @@ -146,8 +164,8 @@ class IntegerValueTypeConstant( } val unknownIntegerType = KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope( - Annotations.EMPTY, typeConstructor, emptyList(), false, - ErrorUtils.createErrorScope("Scope for number value type ($typeConstructor)", true) + Annotations.EMPTY, typeConstructor, emptyList(), false, + ErrorUtils.createErrorScope("Scope for number value type ($typeConstructor)", true) ) fun getType(expectedType: KotlinType): KotlinType = TypeUtils.getPrimitiveNumberType(typeConstructor, expectedType) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java index d750f479c88..9ffd5253dc4 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java @@ -19725,6 +19725,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/unsignedTypes/iterateOverListOfBoxedUnsignedValues.kt"); } + @TestMetadata("signedToUnsignedLiteralConversion.kt") + public void testSignedToUnsignedLiteralConversion() throws Exception { + runTest("compiler/testData/codegen/box/unsignedTypes/signedToUnsignedLiteralConversion.kt"); + } + @TestMetadata("unsignedTypeValuesInsideStringTemplates.kt") public void testUnsignedTypeValuesInsideStringTemplates() throws Exception { runTest("compiler/testData/codegen/box/unsignedTypes/unsignedTypeValuesInsideStringTemplates.kt"); 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 90c685a1901..73bb9b063ad 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 @@ -20775,6 +20775,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/unsignedTypes/iterateOverListOfBoxedUnsignedValues.kt"); } + @TestMetadata("signedToUnsignedLiteralConversion.kt") + public void testSignedToUnsignedLiteralConversion() throws Exception { + runTest("compiler/testData/codegen/box/unsignedTypes/signedToUnsignedLiteralConversion.kt"); + } + @TestMetadata("unsignedTypeValuesInsideStringTemplates.kt") public void testUnsignedTypeValuesInsideStringTemplates() throws Exception { runTest("compiler/testData/codegen/box/unsignedTypes/unsignedTypeValuesInsideStringTemplates.kt");