[FIR] Don't create ILT for integer literal if its value don't fit to Int type

This commit is contained in:
Dmitriy Novozhilov
2022-01-28 16:36:22 +03:00
committed by teamcity
parent 10c38ba47c
commit bb5217be72
4 changed files with 77 additions and 59 deletions
@@ -175,7 +175,7 @@ fun <T : ConeKotlinType> T.withNullability(
ConeNullability.NULLABLE -> original.withNullability(nullability, typeContext) ConeNullability.NULLABLE -> original.withNullability(nullability, typeContext)
ConeNullability.UNKNOWN -> 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}") else -> error("sealed: ${this::class}")
} as T } as T
} }
@@ -906,17 +906,27 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
val type = when (val kind = constExpression.kind) { val type = when (val kind = constExpression.kind) {
ConstantValueKind.IntegerLiteral, ConstantValueKind.UnsignedIntegerLiteral -> { ConstantValueKind.IntegerLiteral, ConstantValueKind.UnsignedIntegerLiteral -> {
val integerLiteralType = val expressionType = ConeIntegerLiteralTypeImpl.create(
ConeIntegerLiteralTypeImpl(constExpression.value as Long, isUnsigned = kind == ConstantValueKind.UnsignedIntegerLiteral) constExpression.value as Long,
if (data.expectedType != null) { isUnsigned = kind == ConstantValueKind.UnsignedIntegerLiteral
val coneType = data.expectedType?.coneTypeSafe<ConeKotlinType>()?.fullyExpandedType(session) )
val approximatedType = integerLiteralType.getApproximatedType(coneType) val expectedTypeRef = data.expectedType
val newConstKind = approximatedType.toConstKind()
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
constExpression.replaceKind(newConstKind as ConstantValueKind<T>) when {
expressionType is ConeClassLikeType -> {
constExpression.replaceKind(expressionType.toConstKind() as ConstantValueKind<T>)
expressionType
}
expectedTypeRef != null -> {
require(expressionType is ConeIntegerLiteralTypeImpl)
val coneType = expectedTypeRef.coneTypeSafe<ConeKotlinType>()?.fullyExpandedType(session)
val approximatedType= expressionType.getApproximatedType(coneType)
constExpression.replaceKind(approximatedType.toConstKind() as ConstantValueKind<T>)
approximatedType approximatedType
} else { }
integerLiteralType else -> {
expressionType
}
} }
} }
else -> kind.expectedConeType(session) else -> kind.expectedConeType(session)
@@ -39,6 +39,8 @@ fun ConeClassLikeType.isByte(): Boolean = lookupTag.classId == StandardClassIds.
fun ConeClassLikeType.isBoolean(): Boolean = lookupTag.classId == StandardClassIds.Boolean fun ConeClassLikeType.isBoolean(): Boolean = lookupTag.classId == StandardClassIds.Boolean
fun ConeClassLikeType.isChar(): Boolean = lookupTag.classId == StandardClassIds.Char fun ConeClassLikeType.isChar(): Boolean = lookupTag.classId == StandardClassIds.Char
fun ConeClassLikeType.isULong(): Boolean = lookupTag.classId == StandardClassIds.ULong
fun ConeClassLikeType.isPrimitiveType(): Boolean = fun ConeClassLikeType.isPrimitiveType(): Boolean =
isPrimitiveNumberOrUnsignedNumberType() || isBoolean() || isByte() || isShort() || isChar() isPrimitiveNumberOrUnsignedNumberType() || isBoolean() || isByte() || isShort() || isChar()
@@ -5,24 +5,49 @@
package org.jetbrains.kotlin.fir.types 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.name.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.model.SimpleTypeMarker import org.jetbrains.kotlin.types.model.SimpleTypeMarker
class ConeIntegerLiteralTypeImpl : ConeIntegerLiteralType { class ConeIntegerLiteralTypeImpl(
override val possibleTypes: Collection<ConeClassLikeType> value: Long,
override val possibleTypes: Collection<ConeClassLikeType>,
isUnsigned: Boolean,
nullability: ConeNullability
) : ConeIntegerLiteralType(value, isUnsigned, nullability) {
override val attributes: ConeAttributes override val attributes: ConeAttributes
get() = ConeAttributes.Empty get() = ConeAttributes.Empty
constructor( override val supertypes: List<ConeClassLikeType> by lazy {
listOf(
createType(StandardClassIds.Number),
ConeClassLikeTypeImpl(COMPARABLE_TAG, arrayOf(ConeKotlinTypeProjectionIn(this)), false)
)
}
override fun getApproximatedType(expectedType: ConeKotlinType?): ConeClassLikeType {
val expectedTypeForApproximation = (expectedType?.lowerBoundIfFlexible() as? ConeClassLikeType)
?.withNullability(ConeNullability.NOT_NULL)
val approximatedType = when (expectedTypeForApproximation) {
null, !in possibleTypes -> possibleTypes.first()
else -> expectedTypeForApproximation
}
return approximatedType.withNullability(nullability)
}
@OptIn(ExperimentalUnsignedTypes::class)
companion object {
fun create(
value: Long, value: Long,
isUnsigned: Boolean, isUnsigned: Boolean,
nullability: ConeNullability = ConeNullability.NOT_NULL nullability: ConeNullability = ConeNullability.NOT_NULL
) : super(value, isUnsigned, nullability) { ): ConeSimpleKotlinType {
possibleTypes = mutableListOf() val possibleTypes = mutableListOf<ConeClassLikeType>()
fun checkBoundsAndAddPossibleType(classId: ClassId, range: LongRange) { fun checkBoundsAndAddPossibleType(classId: ClassId, range: LongRange) {
if (value in range) { if (value in range) {
@@ -49,36 +74,17 @@ class ConeIntegerLiteralTypeImpl : ConeIntegerLiteralType {
} else { } else {
addSignedPossibleTypes() 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 constructor(
value: Long,
possibleTypes: Collection<ConeClassLikeType>,
isUnsigned: Boolean,
nullability: ConeNullability = ConeNullability.NOT_NULL
) : super(value, isUnsigned, nullability) {
this.possibleTypes = possibleTypes
}
override val supertypes: List<ConeClassLikeType> by lazy {
listOf(
createType(StandardClassIds.Number),
ConeClassLikeTypeImpl(COMPARABLE_TAG, arrayOf(ConeKotlinTypeProjectionIn(this)), false)
)
}
override fun getApproximatedType(expectedType: ConeKotlinType?): ConeClassLikeType {
val expectedTypeForApproximation = (expectedType?.lowerBoundIfFlexible() as? ConeClassLikeType)
?.withNullability(ConeNullability.NOT_NULL)
val approximatedType = when (expectedTypeForApproximation) {
null, !in possibleTypes -> possibleTypes.first()
else -> expectedTypeForApproximation
}
return approximatedType.withNullability(nullability)
}
@OptIn(ExperimentalUnsignedTypes::class)
companion object {
private fun createType(classId: ClassId): ConeClassLikeType { private fun createType(classId: ClassId): ConeClassLikeType {
return ConeClassLikeTypeImpl(ConeClassLikeLookupTagImpl(classId), emptyArray(), false) return ConeClassLikeTypeImpl(ConeClassLikeLookupTagImpl(classId), emptyArray(), false)
} }
@@ -137,7 +143,7 @@ class ConeIntegerLiteralTypeImpl : ConeIntegerLiteralType {
Mode.COMMON_SUPER_TYPE -> left.possibleTypes intersect right.possibleTypes Mode.COMMON_SUPER_TYPE -> left.possibleTypes intersect right.possibleTypes
Mode.INTERSECTION_TYPE -> left.possibleTypes union 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? = private fun fold(left: ConeIntegerLiteralType, right: SimpleTypeMarker): SimpleTypeMarker? =