Treat number with unsigned literal as UByte & UShort & UInt & ULong

This commit is contained in:
Mikhail Zarechenskiy
2018-05-28 10:54:09 +03:00
parent 656f6cbded
commit 7d5fdb660d
15 changed files with 217 additions and 75 deletions
@@ -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<Name> primitiveTypeShortNames = newHashSetWithExpectedSize(PrimitiveType.values().length);
public final Set<Name> primitiveArrayTypeShortNames = newHashSetWithExpectedSize(PrimitiveType.values().length);
public final Map<FqNameUnsafe, PrimitiveType> 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);
}
@@ -42,9 +42,12 @@ interface CompileTimeConstant<out T> {
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<out T>(
class IntegerValueTypeConstant(
private val value: Number,
builtIns: KotlinBuiltIns,
module: ModuleDescriptor,
override val parameters: CompileTimeConstant.Parameters
) : CompileTimeConstant<Number> {
private val typeConstructor = IntegerValueTypeConstructor(value.toLong(), builtIns)
private val typeConstructor = IntegerValueTypeConstructor(value.toLong(), module, parameters)
override fun toConstantValue(expectedType: KotlinType): ConstantValue<Number> {
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())
}
}
@@ -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
}
}
}
}
@@ -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<KotlinType>(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<KotlinType> = supertypes
override fun getParameters(): List<TypeParameterDescriptor> = 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)"
@@ -40,9 +40,7 @@ abstract class ConstantValue<out T>(open val value: T) {
}
abstract class IntegerValueConstant<out T> protected constructor(value: T) : ConstantValue<T>(value)
abstract class UnsignedValueConstant<out T> protected constructor(value: T, private val kotlinType: KotlinType) : ConstantValue<T>(value) {
override fun getType(module: ModuleDescriptor): KotlinType = kotlinType
}
abstract class UnsignedValueConstant<out T> protected constructor(value: T) : ConstantValue<T>(value)
class AnnotationValue(value: AnnotationDescriptor) : ConstantValue<AnnotationDescriptor>(value) {
override fun getType(module: ModuleDescriptor): KotlinType = value.type
@@ -193,25 +191,45 @@ class StringValue(value: String) : ConstantValue<String>(value) {
override fun toString() = "\"$value\""
}
class UByteValue(byteValue: ByteValue, kotlinType: KotlinType) : UnsignedValueConstant<Byte>(byteValue.value, kotlinType) {
class UByteValue(byteValue: Byte) : UnsignedValueConstant<Byte>(byteValue) {
override fun getType(module: ModuleDescriptor): KotlinType {
return module.findClassAcrossModuleDependencies(KotlinBuiltIns.FQ_NAMES.uByte)?.defaultType
?: ErrorUtils.createErrorType("Unsigned type UByte not found")
}
override fun <R, D> accept(visitor: AnnotationArgumentVisitor<R, D>, data: D): R = visitor.visitUByteValue(this, data)
override fun toString() = "$value.toUByte()"
}
class UShortValue(shortValue: ShortValue, kotlinType: KotlinType) : UnsignedValueConstant<Short>(shortValue.value, kotlinType) {
class UShortValue(shortValue: Short) : UnsignedValueConstant<Short>(shortValue) {
override fun getType(module: ModuleDescriptor): KotlinType {
return module.findClassAcrossModuleDependencies(KotlinBuiltIns.FQ_NAMES.uShort)?.defaultType
?: ErrorUtils.createErrorType("Unsigned type UByte not found")
}
override fun <R, D> accept(visitor: AnnotationArgumentVisitor<R, D>, data: D): R = visitor.visitUShortValue(this, data)
override fun toString() = "$value.toUShort()"
}
class UIntValue(intValue: IntValue, kotlinType: KotlinType) : UnsignedValueConstant<Int>(intValue.value, kotlinType) {
class UIntValue(intValue: Int) : UnsignedValueConstant<Int>(intValue) {
override fun getType(module: ModuleDescriptor): KotlinType {
return module.findClassAcrossModuleDependencies(KotlinBuiltIns.FQ_NAMES.uInt)?.defaultType
?: ErrorUtils.createErrorType("Unsigned type UByte not found")
}
override fun <R, D> accept(visitor: AnnotationArgumentVisitor<R, D>, data: D) = visitor.visitUIntValue(this, data)
override fun toString() = "$value.toUInt()"
}
class ULongValue(longValue: LongValue, kotlinType: KotlinType) : UnsignedValueConstant<Long>(longValue.value, kotlinType) {
class ULongValue(longValue: Long) : UnsignedValueConstant<Long>(longValue) {
override fun getType(module: ModuleDescriptor): KotlinType {
return module.findClassAcrossModuleDependencies(KotlinBuiltIns.FQ_NAMES.uLong)?.defaultType
?: ErrorUtils.createErrorType("Unsigned type UByte not found")
}
override fun <R, D> accept(visitor: AnnotationArgumentVisitor<R, D>, data: D): R = visitor.visitULongValue(this, data)
override fun toString() = "$value.toULong()"
@@ -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<KotlinType> 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;
}