[NI] Refactor compiler representation of integer literals types
Add `IntegerLiteralTypeConstructor` that holds types, that can take integer literal with given value. It has two supertypes (`Number` and `Comparable<IntegerLiteralType>`) and have special rules for subtyping, `intersect` and `commonSuperType` functions with primitive number: Example (assuming that ILT holds Int type): * ILT <: Int * Int :> ILT * ILT intersect Int = Int * commonSuperType(ILT, Int) = Int #KT-30293 Fixed #KT-30446 Fixed
This commit is contained in:
+3
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
@@ -114,6 +115,8 @@ object NewCommonSuperTypeCalculator {
|
||||
val explicitSupertypes = uniqueTypes.filterSupertypes()
|
||||
if (explicitSupertypes.size == 1) return explicitSupertypes.single()
|
||||
|
||||
IntegerLiteralTypeConstructor.findCommonSuperType(explicitSupertypes)?.let { return it }
|
||||
|
||||
return findSuperTypeConstructorsAndIntersectResult(explicitSupertypes, depth)
|
||||
}
|
||||
|
||||
|
||||
+2
-12
@@ -14,12 +14,10 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage.Empt
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.forceResolution
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.IntersectionTypeConstructor
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
|
||||
|
||||
class KotlinCallCompleter(
|
||||
private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer,
|
||||
@@ -202,19 +200,11 @@ class KotlinCallCompleter(
|
||||
val variableWithConstraints = csBuilder.currentStorage().notFixedTypeVariables[constructor] ?: return false
|
||||
val constraints = variableWithConstraints.constraints
|
||||
return constraints.isNotEmpty() && constraints.all {
|
||||
!trivialConstraintTypeInferenceOracle.isTrivialConstraint(it) && !it.type.isIntegerValueType() &&
|
||||
!trivialConstraintTypeInferenceOracle.isTrivialConstraint(it) && it.type.constructor !is IntegerLiteralTypeConstructor &&
|
||||
it.kind.isLower() && csBuilder.isProperType(it.type)
|
||||
}
|
||||
}
|
||||
|
||||
private fun UnwrappedType.isIntegerValueType(): Boolean {
|
||||
if (constructor is IntegerValueTypeConstructor) return true
|
||||
if (constructor is IntersectionTypeConstructor)
|
||||
return constructor.supertypes.all { it.isPrimitiveNumberType() }
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun KotlinResolutionCandidate.computeReturnTypeWithSmartCastInfo(
|
||||
returnType: UnwrappedType,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ fun CallableDescriptor.substituteAndApproximateCapturedTypes(substitutor: NewTyp
|
||||
|
||||
override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) =
|
||||
substitutor.safeSubstitute(topLevelType.unwrap()).let { substitutedType ->
|
||||
TypeApproximator().approximateToSuperType(substitutedType, TypeApproximatorConfiguration.CapturedTypesApproximation)
|
||||
TypeApproximator().approximateToSuperType(substitutedType, TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation)
|
||||
?: substitutedType
|
||||
}
|
||||
}
|
||||
|
||||
+4
-39
@@ -21,10 +21,8 @@ import org.jetbrains.kotlin.resolve.calls.inference.components.TypeVariableDirec
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.checkConstraint
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.intersectTypes
|
||||
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
|
||||
|
||||
class ResultTypeResolver(
|
||||
val typeApproximator: TypeApproximator,
|
||||
@@ -88,7 +86,6 @@ class ResultTypeResolver(
|
||||
val lowerConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.LOWER && c.isProperType(it.type) }
|
||||
if (lowerConstraints.isNotEmpty()) {
|
||||
val commonSuperType = NewCommonSuperTypeCalculator.commonSuperType(lowerConstraints.map { it.type })
|
||||
val adjustedCommonSuperType = adjustCommonSupertypeWithKnowledgeOfNumberTypes(commonSuperType)
|
||||
/**
|
||||
*
|
||||
* fun <T> Array<out T>.intersect(other: Iterable<T>) {
|
||||
@@ -108,52 +105,20 @@ class ResultTypeResolver(
|
||||
*/
|
||||
|
||||
return typeApproximator.approximateToSuperType(
|
||||
adjustedCommonSuperType,
|
||||
TypeApproximatorConfiguration.CapturedTypesApproximation
|
||||
)
|
||||
?: adjustedCommonSuperType
|
||||
commonSuperType,
|
||||
TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation
|
||||
) ?: commonSuperType
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun adjustCommonSupertypeWithKnowledgeOfNumberTypes(commonSuperType: UnwrappedType): UnwrappedType {
|
||||
val constructor = commonSuperType.constructor
|
||||
|
||||
return when (constructor) {
|
||||
is IntegerValueTypeConstructor,
|
||||
is IntersectionTypeConstructor -> {
|
||||
val newSupertypes = arrayListOf<UnwrappedType>()
|
||||
val numberSupertypes = arrayListOf<KotlinType>()
|
||||
for (supertype in constructor.supertypes.map { it.unwrap() }) {
|
||||
if (supertype.isPrimitiveNumberType())
|
||||
numberSupertypes.add(supertype)
|
||||
else
|
||||
newSupertypes.add(supertype)
|
||||
}
|
||||
|
||||
|
||||
val representativeNumberType = TypeUtils.getDefaultPrimitiveNumberType(numberSupertypes)
|
||||
if (representativeNumberType != null) {
|
||||
newSupertypes.add(representativeNumberType.unwrap())
|
||||
} else {
|
||||
newSupertypes.addAll(numberSupertypes.map { it.unwrap() })
|
||||
}
|
||||
|
||||
intersectTypes(newSupertypes).makeNullableAsSpecified(commonSuperType.isMarkedNullable)
|
||||
}
|
||||
|
||||
else ->
|
||||
commonSuperType
|
||||
}
|
||||
}
|
||||
|
||||
private fun findSuperType(c: Context, variableWithConstraints: VariableWithConstraints): UnwrappedType? {
|
||||
val upperConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.UPPER && c.isProperType(it.type) }
|
||||
if (upperConstraints.isNotEmpty()) {
|
||||
val upperType = intersectTypes(upperConstraints.map { it.type })
|
||||
|
||||
return typeApproximator.approximateToSubType(upperType, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: upperType
|
||||
return typeApproximator.approximateToSubType(upperType, TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation) ?: upperType
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
+2
-2
@@ -241,10 +241,10 @@ abstract class TypeCheckerContextForConstraintSystem : ClassicTypeCheckerContext
|
||||
|
||||
private fun assertInputTypes(subType: UnwrappedType, superType: UnwrappedType) {
|
||||
fun correctSubType(subType: SimpleType) =
|
||||
subType.isSingleClassifierType || subType.isIntersectionType || isMyTypeVariable(subType) || subType.isError
|
||||
subType.isSingleClassifierType || subType.isIntersectionType || isMyTypeVariable(subType) || subType.isError || subType.isIntegerLiteralType
|
||||
|
||||
fun correctSuperType(superType: SimpleType) =
|
||||
superType.isSingleClassifierType || superType.isIntersectionType || isMyTypeVariable(superType) || superType.isError
|
||||
superType.isSingleClassifierType || superType.isIntersectionType || isMyTypeVariable(superType) || superType.isError || superType.isIntegerLiteralType
|
||||
|
||||
assert(subType.bothBounds(::correctSubType)) {
|
||||
"Not singleClassifierType and not intersection subType: $subType"
|
||||
|
||||
@@ -142,11 +142,11 @@ internal class MemberScopeTowerLevel(
|
||||
Variance.INVARIANT -> null
|
||||
Variance.OUT_VARIANCE -> approximator.approximateToSuperType(
|
||||
topLevelType.unwrap(),
|
||||
TypeApproximatorConfiguration.CapturedTypesApproximation
|
||||
TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation
|
||||
)
|
||||
Variance.IN_VARIANCE -> approximator.approximateToSubType(
|
||||
topLevelType.unwrap(),
|
||||
TypeApproximatorConfiguration.CapturedTypesApproximation
|
||||
TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation
|
||||
)
|
||||
} ?: topLevelType
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration.IntersectionStrategy.*
|
||||
import org.jetbrains.kotlin.types.checker.*
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
@@ -41,6 +42,7 @@ open class TypeApproximatorConfiguration {
|
||||
open val dynamic get() = false // DynamicType
|
||||
open val rawType get() = false // RawTypeImpl
|
||||
open val errorType get() = false
|
||||
open val integerLiteralType: Boolean = false // IntegerLiteralTypeConstructor
|
||||
open val definitelyNotNullType get() = true
|
||||
open val intersection: IntersectionStrategy = TO_COMMON_SUPERTYPE
|
||||
|
||||
@@ -59,12 +61,14 @@ open class TypeApproximatorConfiguration {
|
||||
override val allFlexible get() = true
|
||||
override val intersection get() = ALLOWED
|
||||
override val errorType get() = true
|
||||
override val integerLiteralType: Boolean get() = true
|
||||
}
|
||||
|
||||
object PublicDeclaration : AllFlexibleSameValue() {
|
||||
override val allFlexible get() = true
|
||||
override val errorType get() = true
|
||||
override val definitelyNotNullType get() = false
|
||||
override val integerLiteralType: Boolean get() = true
|
||||
}
|
||||
|
||||
abstract class AbstractCapturedTypesApproximation(val approximatedCapturedStatus: CaptureStatus) :
|
||||
@@ -80,7 +84,9 @@ open class TypeApproximatorConfiguration {
|
||||
|
||||
object IncorporationConfiguration : TypeApproximatorConfiguration.AbstractCapturedTypesApproximation(FOR_INCORPORATION)
|
||||
object SubtypeCapturedTypesApproximation : TypeApproximatorConfiguration.AbstractCapturedTypesApproximation(FOR_SUBTYPING)
|
||||
object CapturedTypesApproximation : TypeApproximatorConfiguration.AbstractCapturedTypesApproximation(FROM_EXPRESSION)
|
||||
object CapturedAndIntegerLiteralsTypesApproximation : TypeApproximatorConfiguration.AbstractCapturedTypesApproximation(FROM_EXPRESSION) {
|
||||
override val integerLiteralType: Boolean get() = true
|
||||
}
|
||||
}
|
||||
|
||||
class TypeApproximator {
|
||||
@@ -314,6 +320,13 @@ class TypeApproximator {
|
||||
return if (conf.typeVariable(typeConstructor)) null else type.defaultResult(toSuper)
|
||||
}
|
||||
|
||||
if (typeConstructor is IntegerLiteralTypeConstructor) {
|
||||
return if (conf.integerLiteralType)
|
||||
typeConstructor.getApproximatedType().unwrap().makeNullableAsSpecified(type.isMarkedNullable)
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
return null // simple classifier type
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user