[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:
Dmitriy Novozhilov
2019-03-18 18:03:23 +03:00
parent 9c3e452396
commit ca0e66bafc
30 changed files with 478 additions and 133 deletions
@@ -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)
}
@@ -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
@@ -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
}
}
@@ -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
}
@@ -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
}