From bb5217be7279cd771932e00dd26c9cdec38ca02c Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Fri, 28 Jan 2022 16:36:22 +0300 Subject: [PATCH] [FIR] Don't create ILT for integer literal if its value don't fit to Int type --- .../jetbrains/kotlin/fir/types/TypeUtils.kt | 2 +- .../FirExpressionsResolveTransformer.kt | 32 ++++-- .../org/jetbrains/kotlin/fir/Primitives.kt | 2 + .../fir/types/ConeIntegerLiteralTypeImpl.kt | 100 ++++++++++-------- 4 files changed, 77 insertions(+), 59 deletions(-) diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt index d12c81d99f8..6e86bdcbaa2 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt @@ -175,7 +175,7 @@ fun T.withNullability( ConeNullability.NULLABLE -> original.withNullability(nullability, typeContext) ConeNullability.UNKNOWN -> original.withNullability(nullability, typeContext) } - is ConeIntegerLiteralType -> ConeIntegerLiteralTypeImpl(value, isUnsigned, nullability) + is ConeIntegerLiteralTypeImpl -> ConeIntegerLiteralTypeImpl(value, possibleTypes, isUnsigned, nullability) else -> error("sealed: ${this::class}") } as T } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index f2115278119..1cd5896a55d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -906,17 +906,27 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform val type = when (val kind = constExpression.kind) { ConstantValueKind.IntegerLiteral, ConstantValueKind.UnsignedIntegerLiteral -> { - val integerLiteralType = - ConeIntegerLiteralTypeImpl(constExpression.value as Long, isUnsigned = kind == ConstantValueKind.UnsignedIntegerLiteral) - if (data.expectedType != null) { - val coneType = data.expectedType?.coneTypeSafe()?.fullyExpandedType(session) - val approximatedType = integerLiteralType.getApproximatedType(coneType) - val newConstKind = approximatedType.toConstKind() - @Suppress("UNCHECKED_CAST") - constExpression.replaceKind(newConstKind as ConstantValueKind) - approximatedType - } else { - integerLiteralType + val expressionType = ConeIntegerLiteralTypeImpl.create( + constExpression.value as Long, + isUnsigned = kind == ConstantValueKind.UnsignedIntegerLiteral + ) + val expectedTypeRef = data.expectedType + @Suppress("UNCHECKED_CAST") + when { + expressionType is ConeClassLikeType -> { + constExpression.replaceKind(expressionType.toConstKind() as ConstantValueKind) + expressionType + } + expectedTypeRef != null -> { + require(expressionType is ConeIntegerLiteralTypeImpl) + val coneType = expectedTypeRef.coneTypeSafe()?.fullyExpandedType(session) + val approximatedType= expressionType.getApproximatedType(coneType) + constExpression.replaceKind(approximatedType.toConstKind() as ConstantValueKind) + approximatedType + } + else -> { + expressionType + } } } else -> kind.expectedConeType(session) diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Primitives.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Primitives.kt index 1f339ee4e67..4998afa2282 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Primitives.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Primitives.kt @@ -39,6 +39,8 @@ fun ConeClassLikeType.isByte(): Boolean = lookupTag.classId == StandardClassIds. fun ConeClassLikeType.isBoolean(): Boolean = lookupTag.classId == StandardClassIds.Boolean fun ConeClassLikeType.isChar(): Boolean = lookupTag.classId == StandardClassIds.Char +fun ConeClassLikeType.isULong(): Boolean = lookupTag.classId == StandardClassIds.ULong + fun ConeClassLikeType.isPrimitiveType(): Boolean = isPrimitiveNumberOrUnsignedNumberType() || isBoolean() || isByte() || isShort() || isChar() diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/ConeIntegerLiteralTypeImpl.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/ConeIntegerLiteralTypeImpl.kt index 5a7e4f0f18e..3a64411a524 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/ConeIntegerLiteralTypeImpl.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/ConeIntegerLiteralTypeImpl.kt @@ -5,61 +5,24 @@ package org.jetbrains.kotlin.fir.types +import org.jetbrains.kotlin.fir.isLong +import org.jetbrains.kotlin.fir.isULong import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.model.SimpleTypeMarker -class ConeIntegerLiteralTypeImpl : ConeIntegerLiteralType { - override val possibleTypes: Collection - +class ConeIntegerLiteralTypeImpl( + value: Long, + override val possibleTypes: Collection, + isUnsigned: Boolean, + nullability: ConeNullability +) : ConeIntegerLiteralType(value, isUnsigned, nullability) { override val attributes: ConeAttributes get() = ConeAttributes.Empty - constructor( - value: Long, - isUnsigned: Boolean, - nullability: ConeNullability = ConeNullability.NOT_NULL - ) : super(value, isUnsigned, nullability) { - possibleTypes = mutableListOf() - - fun checkBoundsAndAddPossibleType(classId: ClassId, range: LongRange) { - if (value in range) { - possibleTypes.add(createType(classId)) - } - } - - fun addSignedPossibleTypes() { - checkBoundsAndAddPossibleType(StandardClassIds.Int, INT_RANGE) - possibleTypes += createType(StandardClassIds.Long) - checkBoundsAndAddPossibleType(StandardClassIds.Byte, BYTE_RANGE) - checkBoundsAndAddPossibleType(StandardClassIds.Short, SHORT_RANGE) - } - - fun addUnsignedPossibleType() { - checkBoundsAndAddPossibleType(StandardClassIds.UInt, UINT_RANGE) - possibleTypes += createType(StandardClassIds.ULong) - checkBoundsAndAddPossibleType(StandardClassIds.UByte, UBYTE_RANGE) - checkBoundsAndAddPossibleType(StandardClassIds.UShort, USHORT_RANGE) - } - - if (isUnsigned) { - addUnsignedPossibleType() - } else { - addSignedPossibleTypes() - } - } - - private constructor( - value: Long, - possibleTypes: Collection, - isUnsigned: Boolean, - nullability: ConeNullability = ConeNullability.NOT_NULL - ) : super(value, isUnsigned, nullability) { - this.possibleTypes = possibleTypes - } - override val supertypes: List by lazy { listOf( createType(StandardClassIds.Number), @@ -79,6 +42,49 @@ class ConeIntegerLiteralTypeImpl : ConeIntegerLiteralType { @OptIn(ExperimentalUnsignedTypes::class) companion object { + fun create( + value: Long, + isUnsigned: Boolean, + nullability: ConeNullability = ConeNullability.NOT_NULL + ): ConeSimpleKotlinType { + val possibleTypes = mutableListOf() + + fun checkBoundsAndAddPossibleType(classId: ClassId, range: LongRange) { + if (value in range) { + possibleTypes.add(createType(classId)) + } + } + + fun addSignedPossibleTypes() { + checkBoundsAndAddPossibleType(StandardClassIds.Int, INT_RANGE) + possibleTypes += createType(StandardClassIds.Long) + checkBoundsAndAddPossibleType(StandardClassIds.Byte, BYTE_RANGE) + checkBoundsAndAddPossibleType(StandardClassIds.Short, SHORT_RANGE) + } + + fun addUnsignedPossibleType() { + checkBoundsAndAddPossibleType(StandardClassIds.UInt, UINT_RANGE) + possibleTypes += createType(StandardClassIds.ULong) + checkBoundsAndAddPossibleType(StandardClassIds.UByte, UBYTE_RANGE) + checkBoundsAndAddPossibleType(StandardClassIds.UShort, USHORT_RANGE) + } + + if (isUnsigned) { + addUnsignedPossibleType() + } else { + addSignedPossibleTypes() + } + return if (possibleTypes.size == 1) { + possibleTypes.single().withNullability(nullability).also { + if (AbstractTypeChecker.RUN_SLOW_ASSERTIONS) { + assert(it.isLong() || it.isULong()) + } + } + } else { + ConeIntegerLiteralTypeImpl(value, possibleTypes, isUnsigned, nullability) + } + } + private fun createType(classId: ClassId): ConeClassLikeType { return ConeClassLikeTypeImpl(ConeClassLikeLookupTagImpl(classId), emptyArray(), false) } @@ -137,7 +143,7 @@ class ConeIntegerLiteralTypeImpl : ConeIntegerLiteralType { Mode.COMMON_SUPER_TYPE -> left.possibleTypes intersect right.possibleTypes Mode.INTERSECTION_TYPE -> left.possibleTypes union right.possibleTypes } - return ConeIntegerLiteralTypeImpl(left.value, possibleTypes, left.isUnsigned) + return ConeIntegerLiteralTypeImpl(left.value, possibleTypes, left.isUnsigned, left.nullability) } private fun fold(left: ConeIntegerLiteralType, right: SimpleTypeMarker): SimpleTypeMarker? =