[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:
@@ -611,6 +611,11 @@ public abstract class KotlinBuiltIns {
|
||||
return getPrimitiveClassDescriptor(type).getDefaultType();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SimpleType getNumberType() {
|
||||
return getNumber().getDefaultType();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SimpleType getByteType() {
|
||||
return getPrimitiveKotlinType(BYTE);
|
||||
|
||||
@@ -91,9 +91,10 @@ class TypedCompileTimeConstant<out T>(
|
||||
fun createIntegerValueTypeConstant(
|
||||
value: Number,
|
||||
module: ModuleDescriptor,
|
||||
parameters: CompileTimeConstant.Parameters
|
||||
parameters: CompileTimeConstant.Parameters,
|
||||
newInferenceEnabled: Boolean
|
||||
): CompileTimeConstant<*> {
|
||||
return IntegerValueTypeConstant(value, module, parameters)
|
||||
return IntegerValueTypeConstant(value, module, parameters, newInferenceEnabled)
|
||||
}
|
||||
|
||||
fun hasUnsignedTypesInModuleDependencies(module: ModuleDescriptor): Boolean {
|
||||
@@ -121,6 +122,7 @@ class IntegerValueTypeConstant(
|
||||
private val value: Number,
|
||||
module: ModuleDescriptor,
|
||||
override val parameters: CompileTimeConstant.Parameters,
|
||||
private val newInferenceEnabled: Boolean,
|
||||
val convertedFromSigned: Boolean = false
|
||||
) : CompileTimeConstant<Number> {
|
||||
companion object {
|
||||
@@ -136,7 +138,7 @@ class IntegerValueTypeConstant(
|
||||
isConvertableConstVal = parameters.isConvertableConstVal
|
||||
)
|
||||
|
||||
return IntegerValueTypeConstant(value, module, newParameters, convertedFromSigned = true)
|
||||
return IntegerValueTypeConstant(value, module, newParameters, newInferenceEnabled, convertedFromSigned = true)
|
||||
}
|
||||
|
||||
fun IntegerValueTypeConstant.convertToSignedConstant(module: ModuleDescriptor): IntegerValueTypeConstant {
|
||||
@@ -150,11 +152,16 @@ class IntegerValueTypeConstant(
|
||||
isConvertableConstVal = parameters.isConvertableConstVal
|
||||
)
|
||||
|
||||
return IntegerValueTypeConstant(value, module, newParameters, convertedFromSigned = true)
|
||||
return IntegerValueTypeConstant(value, module, newParameters, newInferenceEnabled, convertedFromSigned = true)
|
||||
}
|
||||
}
|
||||
|
||||
private val typeConstructor = IntegerValueTypeConstructor(value.toLong(), module, parameters)
|
||||
private val typeConstructor =
|
||||
if (newInferenceEnabled) {
|
||||
IntegerLiteralTypeConstructor(value.toLong(), module, parameters)
|
||||
} else {
|
||||
IntegerValueTypeConstructor(value.toLong(), module, parameters)
|
||||
}
|
||||
|
||||
override fun toConstantValue(expectedType: KotlinType): ConstantValue<Number> {
|
||||
val type = getType(expectedType)
|
||||
@@ -178,7 +185,12 @@ class IntegerValueTypeConstant(
|
||||
ErrorUtils.createErrorScope("Scope for number value type ($typeConstructor)", true)
|
||||
)
|
||||
|
||||
fun getType(expectedType: KotlinType): KotlinType = TypeUtils.getPrimitiveNumberType(typeConstructor, expectedType)
|
||||
fun getType(expectedType: KotlinType): KotlinType =
|
||||
if (newInferenceEnabled) {
|
||||
TypeUtils.getPrimitiveNumberType(typeConstructor as IntegerLiteralTypeConstructor, expectedType)
|
||||
} else {
|
||||
TypeUtils.getPrimitiveNumberType(typeConstructor as IntegerValueTypeConstructor, expectedType)
|
||||
}
|
||||
|
||||
override fun toString() = typeConstructor.toString()
|
||||
|
||||
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.constants
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import java.lang.IllegalStateException
|
||||
|
||||
class IntegerLiteralTypeConstructor : TypeConstructor {
|
||||
companion object {
|
||||
fun findCommonSuperType(types: Collection<SimpleType>): SimpleType? =
|
||||
findCommonSuperTypeOrIntersectionType(types, Companion.Mode.COMMON_SUPER_TYPE)
|
||||
|
||||
fun findIntersectionType(types: Collection<SimpleType>): SimpleType? =
|
||||
findCommonSuperTypeOrIntersectionType(types, Companion.Mode.INTERSECTION_TYPE)
|
||||
|
||||
private enum class Mode {
|
||||
COMMON_SUPER_TYPE, INTERSECTION_TYPE
|
||||
}
|
||||
|
||||
/**
|
||||
* intersection(ILT(types), PrimitiveType) = commonSuperType(ILT(types), PrimitiveType) =
|
||||
* PrimitiveType in types -> PrimitiveType
|
||||
* PrimitiveType !in types -> null
|
||||
*
|
||||
* intersection(ILT(types_1), ILT(types_2)) = ILT(types_1 union types_2)
|
||||
*
|
||||
* commonSuperType(ILT(types_1), ILT(types_2)) = ILT(types_1 intersect types_2)
|
||||
*/
|
||||
private fun findCommonSuperTypeOrIntersectionType(types: Collection<SimpleType>, mode: Mode): SimpleType? {
|
||||
if (types.isEmpty()) return null
|
||||
return types.reduce { left: SimpleType?, right -> fold(left, right, mode) }
|
||||
}
|
||||
|
||||
private fun fold(left: SimpleType?, right: SimpleType?, mode: Mode): SimpleType? {
|
||||
if (left == null || right == null) return null
|
||||
val leftConstructor = left.constructor
|
||||
val rightConstructor = right.constructor
|
||||
return when {
|
||||
leftConstructor is IntegerLiteralTypeConstructor && rightConstructor is IntegerLiteralTypeConstructor ->
|
||||
fold(leftConstructor, rightConstructor, mode)
|
||||
|
||||
leftConstructor is IntegerLiteralTypeConstructor -> fold(leftConstructor, right)
|
||||
rightConstructor is IntegerLiteralTypeConstructor -> fold(rightConstructor, left)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun fold(left: IntegerLiteralTypeConstructor, right: IntegerLiteralTypeConstructor, mode: Mode): SimpleType? {
|
||||
val possibleTypes = when (mode) {
|
||||
Mode.COMMON_SUPER_TYPE -> left.possibleTypes intersect right.possibleTypes
|
||||
Mode.INTERSECTION_TYPE -> left.possibleTypes union right.possibleTypes
|
||||
}
|
||||
val constructor = IntegerLiteralTypeConstructor(left.value, left.module, possibleTypes)
|
||||
return KotlinTypeFactory.integerLiteralType(Annotations.EMPTY, constructor, false)
|
||||
}
|
||||
|
||||
private fun fold(left: IntegerLiteralTypeConstructor, right: SimpleType): SimpleType? =
|
||||
if (right in left.possibleTypes) right else null
|
||||
|
||||
}
|
||||
|
||||
private val value: Long
|
||||
private val module: ModuleDescriptor
|
||||
val possibleTypes: Set<KotlinType>
|
||||
|
||||
constructor(value: Long, module: ModuleDescriptor, parameters: CompileTimeConstant.Parameters) {
|
||||
this.value = value
|
||||
this.module = module
|
||||
|
||||
val possibleTypes = mutableSetOf<KotlinType>()
|
||||
|
||||
fun checkBoundsAndAddPossibleType(value: Long, kotlinType: KotlinType) {
|
||||
if (value in kotlinType.minValue()..kotlinType.maxValue()) {
|
||||
possibleTypes.add(kotlinType)
|
||||
}
|
||||
}
|
||||
|
||||
fun addSignedPossibleTypes() {
|
||||
checkBoundsAndAddPossibleType(value, builtIns.intType)
|
||||
possibleTypes.add(builtIns.longType)
|
||||
checkBoundsAndAddPossibleType(value, builtIns.byteType)
|
||||
checkBoundsAndAddPossibleType(value, builtIns.shortType)
|
||||
}
|
||||
|
||||
fun addUnsignedPossibleTypes() {
|
||||
checkBoundsAndAddPossibleType(value, module.uIntType)
|
||||
possibleTypes.add(module.uLongType)
|
||||
checkBoundsAndAddPossibleType(value, module.uByteType)
|
||||
checkBoundsAndAddPossibleType(value, module.uShortType)
|
||||
}
|
||||
|
||||
val isUnsigned = parameters.isUnsignedNumberLiteral
|
||||
val isConvertable = parameters.isConvertableConstVal
|
||||
|
||||
if (isUnsigned || isConvertable) {
|
||||
assert(hasUnsignedTypesInModuleDependencies(module)) {
|
||||
"Unsigned types should be on classpath to create an unsigned type constructor"
|
||||
}
|
||||
}
|
||||
|
||||
when {
|
||||
isConvertable -> {
|
||||
addSignedPossibleTypes()
|
||||
addUnsignedPossibleTypes()
|
||||
}
|
||||
|
||||
isUnsigned -> addUnsignedPossibleTypes()
|
||||
|
||||
else -> addSignedPossibleTypes()
|
||||
}
|
||||
|
||||
this.possibleTypes = possibleTypes
|
||||
}
|
||||
|
||||
private constructor(value: Long, module: ModuleDescriptor, possibleTypes: Set<KotlinType>) {
|
||||
this.value = value
|
||||
this.module = module
|
||||
this.possibleTypes = possibleTypes
|
||||
}
|
||||
|
||||
private val type = KotlinTypeFactory.integerLiteralType(Annotations.EMPTY, this, false)
|
||||
|
||||
private fun isContainsOnlyUnsignedTypes(): Boolean = module.allSignedLiteralTypes.all { it !in possibleTypes }
|
||||
|
||||
private val supertypes: List<KotlinType> by lazy {
|
||||
val result = mutableListOf(builtIns.comparable.defaultType.replace(listOf(TypeProjectionImpl(Variance.IN_VARIANCE, type))))
|
||||
if (!isContainsOnlyUnsignedTypes()) {
|
||||
result += builtIns.numberType
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fun getApproximatedType(): KotlinType = when {
|
||||
builtIns.intType in possibleTypes -> builtIns.intType
|
||||
builtIns.longType in possibleTypes -> builtIns.longType
|
||||
builtIns.byteType in possibleTypes -> builtIns.byteType
|
||||
builtIns.shortType in possibleTypes -> builtIns.shortType
|
||||
|
||||
module.uIntType in possibleTypes -> module.uIntType
|
||||
module.uLongType in possibleTypes -> module.uLongType
|
||||
module.uByteType in possibleTypes -> module.uByteType
|
||||
module.uShortType in possibleTypes -> module.uShortType
|
||||
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
|
||||
|
||||
override fun getParameters(): List<TypeParameterDescriptor> = emptyList()
|
||||
|
||||
override fun getSupertypes(): Collection<KotlinType> = supertypes
|
||||
|
||||
override fun isFinal(): Boolean = true
|
||||
|
||||
override fun isDenotable(): Boolean = false
|
||||
|
||||
override fun getDeclarationDescriptor(): ClassifierDescriptor? = null
|
||||
|
||||
override fun getBuiltIns(): KotlinBuiltIns = module.builtIns
|
||||
|
||||
override fun toString(): String {
|
||||
return "IntegerLiteralType${valueToString()}"
|
||||
}
|
||||
|
||||
fun checkConstructor(constructor: TypeConstructor): Boolean = possibleTypes.any { it.constructor == constructor }
|
||||
|
||||
private fun valueToString(): String = "[${possibleTypes.joinToString(",") { it.toString() }}]"
|
||||
}
|
||||
+4
-31
@@ -67,10 +67,10 @@ class IntegerValueTypeConstructor(
|
||||
}
|
||||
|
||||
private fun addUnsignedSuperTypes() {
|
||||
checkBoundsAndAddSuperType(value, unsignedType(KotlinBuiltIns.FQ_NAMES.uInt))
|
||||
checkBoundsAndAddSuperType(value, unsignedType(KotlinBuiltIns.FQ_NAMES.uByte))
|
||||
checkBoundsAndAddSuperType(value, unsignedType(KotlinBuiltIns.FQ_NAMES.uShort))
|
||||
supertypes.add(unsignedType(KotlinBuiltIns.FQ_NAMES.uLong))
|
||||
checkBoundsAndAddSuperType(value, module.unsignedType(KotlinBuiltIns.FQ_NAMES.uInt))
|
||||
checkBoundsAndAddSuperType(value, module.unsignedType(KotlinBuiltIns.FQ_NAMES.uByte))
|
||||
checkBoundsAndAddSuperType(value, module.unsignedType(KotlinBuiltIns.FQ_NAMES.uShort))
|
||||
supertypes.add(module.unsignedType(KotlinBuiltIns.FQ_NAMES.uLong))
|
||||
}
|
||||
|
||||
private fun checkBoundsAndAddSuperType(value: Long, kotlinType: KotlinType) {
|
||||
@@ -79,8 +79,6 @@ class IntegerValueTypeConstructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun unsignedType(classId: ClassId): SimpleType = module.findClassAcrossModuleDependencies(classId)!!.defaultType
|
||||
|
||||
override fun getSupertypes(): Collection<KotlinType> = supertypes
|
||||
|
||||
override fun getParameters(): List<TypeParameterDescriptor> = emptyList()
|
||||
@@ -100,28 +98,3 @@ class IntegerValueTypeConstructor(
|
||||
override fun toString() = "IntegerValueType($value)"
|
||||
}
|
||||
|
||||
private fun KotlinType.minValue(): Long {
|
||||
if (UnsignedTypes.isUnsignedType(this)) return 0
|
||||
return when {
|
||||
KotlinBuiltIns.isByte(this) -> Byte.MIN_VALUE.toLong()
|
||||
KotlinBuiltIns.isShort(this) -> Short.MIN_VALUE.toLong()
|
||||
KotlinBuiltIns.isInt(this) -> Int.MIN_VALUE.toLong()
|
||||
else -> error("Can't get min value for type: $this")
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
private fun KotlinType.maxValue(): Long {
|
||||
return when {
|
||||
KotlinBuiltIns.isByte(this) -> Byte.MAX_VALUE.toLong()
|
||||
KotlinBuiltIns.isShort(this) -> Short.MAX_VALUE.toLong()
|
||||
KotlinBuiltIns.isInt(this) -> Int.MAX_VALUE.toLong()
|
||||
|
||||
KotlinBuiltIns.isUByte(this) -> UByte.MAX_VALUE.toLong()
|
||||
KotlinBuiltIns.isUShort(this) -> UShort.MAX_VALUE.toLong()
|
||||
KotlinBuiltIns.isUInt(this) -> UInt.MAX_VALUE.toLong()
|
||||
|
||||
else -> error("Can't get max value for type: $this")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.constants
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.UnsignedTypes
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
|
||||
internal fun KotlinType.minValue(): Long {
|
||||
if (UnsignedTypes.isUnsignedType(this)) return 0
|
||||
return when {
|
||||
KotlinBuiltIns.isByte(this) -> Byte.MIN_VALUE.toLong()
|
||||
KotlinBuiltIns.isShort(this) -> Short.MIN_VALUE.toLong()
|
||||
KotlinBuiltIns.isInt(this) -> Int.MIN_VALUE.toLong()
|
||||
else -> error("Can't get min value for type: $this")
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
internal fun KotlinType.maxValue(): Long {
|
||||
return when {
|
||||
KotlinBuiltIns.isByte(this) -> Byte.MAX_VALUE.toLong()
|
||||
KotlinBuiltIns.isShort(this) -> Short.MAX_VALUE.toLong()
|
||||
KotlinBuiltIns.isInt(this) -> Int.MAX_VALUE.toLong()
|
||||
|
||||
KotlinBuiltIns.isUByte(this) -> UByte.MAX_VALUE.toLong()
|
||||
KotlinBuiltIns.isUShort(this) -> UShort.MAX_VALUE.toLong()
|
||||
KotlinBuiltIns.isUInt(this) -> UInt.MAX_VALUE.toLong()
|
||||
|
||||
else -> error("Can't get max value for type: $this")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ModuleDescriptor.unsignedType(classId: ClassId): SimpleType = findClassAcrossModuleDependencies(classId)!!.defaultType
|
||||
|
||||
internal val ModuleDescriptor.uIntType: SimpleType
|
||||
get() = unsignedType(KotlinBuiltIns.FQ_NAMES.uInt)
|
||||
|
||||
internal val ModuleDescriptor.uLongType: SimpleType
|
||||
get() = unsignedType(KotlinBuiltIns.FQ_NAMES.uLong)
|
||||
|
||||
internal val ModuleDescriptor.uByteType: SimpleType
|
||||
get() = unsignedType(KotlinBuiltIns.FQ_NAMES.uByte)
|
||||
|
||||
internal val ModuleDescriptor.uShortType: SimpleType
|
||||
get() = unsignedType(KotlinBuiltIns.FQ_NAMES.uShort)
|
||||
|
||||
internal val ModuleDescriptor.allSignedLiteralTypes: Collection<KotlinType>
|
||||
get() = listOf(builtIns.intType, builtIns.longType, builtIns.byteType, builtIns.shortType)
|
||||
|
||||
internal val ModuleDescriptor.allUnsignedLiteralTypes: Collection<KotlinType>
|
||||
get() = if (hasUnsignedTypesInModuleDependencies(this)) {
|
||||
listOf(
|
||||
unsignedType(KotlinBuiltIns.FQ_NAMES.uInt), unsignedType(KotlinBuiltIns.FQ_NAMES.uLong),
|
||||
unsignedType(KotlinBuiltIns.FQ_NAMES.uByte), unsignedType(KotlinBuiltIns.FQ_NAMES.uShort)
|
||||
)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
@@ -20,7 +20,9 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||
|
||||
object KotlinTypeFactory {
|
||||
private fun computeMemberScope(constructor: TypeConstructor, arguments: List<TypeProjection>): MemberScope {
|
||||
@@ -95,6 +97,19 @@ object KotlinTypeFactory {
|
||||
if (lowerBound == upperBound) return lowerBound
|
||||
return FlexibleTypeImpl(lowerBound, upperBound)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun integerLiteralType(
|
||||
annotations: Annotations,
|
||||
constructor: IntegerLiteralTypeConstructor,
|
||||
nullable: Boolean
|
||||
): SimpleType = simpleTypeWithNonTrivialMemberScope(
|
||||
annotations,
|
||||
constructor,
|
||||
emptyList(),
|
||||
nullable,
|
||||
ErrorUtils.createErrorScope("Scope for integer literal type", true)
|
||||
)
|
||||
}
|
||||
|
||||
private class SimpleTypeImpl(
|
||||
@@ -150,4 +165,4 @@ private class NullableSimpleType(delegate: SimpleType) : DelegatingSimpleTypeImp
|
||||
private class NotNullSimpleType(delegate: SimpleType) : DelegatingSimpleTypeImpl(delegate) {
|
||||
override val isMarkedNullable: Boolean
|
||||
get() = false
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ 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.IntegerLiteralTypeConstructor;
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor;
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||
@@ -498,6 +499,30 @@ public class TypeUtils {
|
||||
return getDefaultPrimitiveNumberType(numberValueTypeConstructor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static KotlinType getPrimitiveNumberType(
|
||||
@NotNull IntegerLiteralTypeConstructor literalTypeConstructor,
|
||||
@NotNull KotlinType expectedType
|
||||
) {
|
||||
if (noExpectedType(expectedType) || KotlinTypeKt.isError(expectedType)) {
|
||||
return literalTypeConstructor.getApproximatedType();
|
||||
}
|
||||
|
||||
// If approximated type does not mathc expected type then expected type is very
|
||||
// specific type (e.g. Comparable<Byte>), so only one of possible types could match it
|
||||
KotlinType approximatedType = literalTypeConstructor.getApproximatedType();
|
||||
if (KotlinTypeChecker.DEFAULT.isSubtypeOf(approximatedType, expectedType)) {
|
||||
return approximatedType;
|
||||
}
|
||||
|
||||
for (KotlinType primitiveNumberType : literalTypeConstructor.getPossibleTypes()) {
|
||||
if (KotlinTypeChecker.DEFAULT.isSubtypeOf(primitiveNumberType, expectedType)) {
|
||||
return primitiveNumberType;
|
||||
}
|
||||
}
|
||||
return literalTypeConstructor.getApproximatedType();
|
||||
}
|
||||
|
||||
public static boolean isTypeParameter(@NotNull KotlinType type) {
|
||||
return getTypeParameterDescriptorOrNull(type) != null || type.getConstructor() instanceof NewTypeVariableConstructor;
|
||||
}
|
||||
|
||||
+10
-2
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.types.checker
|
||||
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker.transformToNewType
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
@@ -41,8 +42,15 @@ open class ClassicTypeCheckerContext(val errorTypeEqualsToAnything: Boolean, val
|
||||
return areEqualTypeConstructors(a, b)
|
||||
}
|
||||
|
||||
open fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean {
|
||||
return a == b
|
||||
open fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean = when {
|
||||
/*
|
||||
* For integer literal types we have special rules for constructor's equality,
|
||||
* so we have to check it manually
|
||||
* For example: Int in ILT.possibleTypes -> ILT == Int
|
||||
*/
|
||||
a is IntegerLiteralTypeConstructor -> a.checkConstructor(b)
|
||||
b is IntegerLiteralTypeConstructor -> b.checkConstructor(a)
|
||||
else -> a == b
|
||||
}
|
||||
|
||||
override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy.DoCustomTransform {
|
||||
|
||||
+13
-1
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.CapturedType
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.model.*
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
@@ -20,6 +21,17 @@ interface ClassicTypeSystemContext : TypeSystemContext {
|
||||
return this.isDenotable
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isIntegerLiteralTypeConstructor(): Boolean {
|
||||
require(this is TypeConstructor, this::errorMessage)
|
||||
return this is IntegerLiteralTypeConstructor
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.possibleIntegerTypes(): Collection<KotlinTypeMarker> {
|
||||
val typeConstructor = typeConstructor()
|
||||
require(typeConstructor is IntegerLiteralTypeConstructor, this::errorMessage)
|
||||
return typeConstructor.possibleTypes
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.withNullability(nullable: Boolean): SimpleTypeMarker {
|
||||
require(this is SimpleType, this::errorMessage)
|
||||
return this.makeNullableAsSpecified(nullable)
|
||||
@@ -221,7 +233,7 @@ interface ClassicTypeSystemContext : TypeSystemContext {
|
||||
require(this is SimpleType, this::errorMessage)
|
||||
return !isError &&
|
||||
constructor.declarationDescriptor !is TypeAliasDescriptor &&
|
||||
(constructor.declarationDescriptor != null || this is CapturedType || this is NewCapturedType || this is DefinitelyNotNullType)
|
||||
(constructor.declarationDescriptor != null || this is CapturedType || this is NewCapturedType || this is DefinitelyNotNullType || constructor is IntegerLiteralTypeConstructor)
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isNotNullNothing(): Boolean {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.types.checker
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import java.util.*
|
||||
import kotlin.collections.LinkedHashSet
|
||||
@@ -71,14 +72,14 @@ object TypeIntersector {
|
||||
assert(types.size > 1) {
|
||||
"Size should be at least 2, but it is ${types.size}"
|
||||
}
|
||||
|
||||
val inputTypes = ArrayList<SimpleType>()
|
||||
for (type in types) {
|
||||
if (type.constructor is IntersectionTypeConstructor) {
|
||||
inputTypes.addAll(type.constructor.supertypes.map {
|
||||
it.upperIfFlexible().let { if (type.isMarkedNullable) it.makeNullableAsSpecified(true) else it }
|
||||
})
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
inputTypes.add(type)
|
||||
}
|
||||
}
|
||||
@@ -106,25 +107,41 @@ object TypeIntersector {
|
||||
|
||||
// Any and Nothing should leave
|
||||
// Note that duplicates should be dropped because we have Set here.
|
||||
val filteredSuperAndEqualTypes = ArrayList(inputTypes)
|
||||
val iterator = filteredSuperAndEqualTypes.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val upper = iterator.next()
|
||||
val strictSupertypeOrHasEqual = filteredSuperAndEqualTypes.any { lower ->
|
||||
lower !== upper && (isStrictSupertype(lower, upper) || NewKotlinTypeChecker.equalTypes(lower, upper))
|
||||
}
|
||||
val errorMessage = { "This collections cannot be empty! input types: ${inputTypes.joinToString()}" }
|
||||
|
||||
if (strictSupertypeOrHasEqual) iterator.remove()
|
||||
}
|
||||
val filteredEqualTypes = filterTypes(inputTypes, ::isStrictSupertype)
|
||||
assert(filteredEqualTypes.isNotEmpty(), errorMessage)
|
||||
|
||||
assert(filteredSuperAndEqualTypes.isNotEmpty()) {
|
||||
"This collections cannot be empty! input types: ${inputTypes.joinToString()}"
|
||||
}
|
||||
IntegerLiteralTypeConstructor.findIntersectionType(filteredEqualTypes)?.let { return it }
|
||||
|
||||
val filteredSuperAndEqualTypes = filterTypes(filteredEqualTypes, NewKotlinTypeChecker::equalTypes)
|
||||
assert(filteredSuperAndEqualTypes.isNotEmpty(), errorMessage)
|
||||
|
||||
if (filteredSuperAndEqualTypes.size < 2) return filteredSuperAndEqualTypes.single()
|
||||
|
||||
val constructor = IntersectionTypeConstructor(inputTypes)
|
||||
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(Annotations.EMPTY, constructor, listOf(), false, constructor.createScopeForKotlinType())
|
||||
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
|
||||
Annotations.EMPTY,
|
||||
constructor,
|
||||
listOf(),
|
||||
false,
|
||||
constructor.createScopeForKotlinType()
|
||||
)
|
||||
}
|
||||
|
||||
private fun filterTypes(
|
||||
inputTypes: Collection<SimpleType>,
|
||||
predicate: (lower: SimpleType, upper: SimpleType) -> Boolean
|
||||
): Collection<SimpleType> {
|
||||
val filteredTypes = ArrayList(inputTypes)
|
||||
val iterator = filteredTypes.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val upper = iterator.next()
|
||||
val shouldFilter = filteredTypes.any { lower -> lower !== upper && predicate(lower, upper) }
|
||||
|
||||
if (shouldFilter) iterator.remove()
|
||||
}
|
||||
return filteredTypes
|
||||
}
|
||||
|
||||
private fun isStrictSupertype(subtype: KotlinType, supertype: KotlinType): Boolean {
|
||||
@@ -146,9 +163,9 @@ object TypeIntersector {
|
||||
// example: type parameter without not-null supertype
|
||||
UNKNOWN {
|
||||
override fun combine(nextType: UnwrappedType) =
|
||||
nextType.resultNullability.let {
|
||||
if (it == ACCEPT_NULL) this else it
|
||||
}
|
||||
nextType.resultNullability.let {
|
||||
if (it == ACCEPT_NULL) this else it
|
||||
}
|
||||
},
|
||||
NOT_NULL {
|
||||
override fun combine(nextType: UnwrappedType) = this
|
||||
|
||||
@@ -20,13 +20,15 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.CapturedType
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.CapturedTypeConstructorImpl
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.AbstractNullabilityChecker.hasNotNullSupertype
|
||||
import org.jetbrains.kotlin.types.AbstractNullabilityChecker.hasPathByNotMarkedNullableNodes
|
||||
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext.SupertypesPolicy
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
|
||||
object StrictEqualityTypeChecker {
|
||||
|
||||
@@ -192,3 +194,6 @@ val SimpleType.isSingleClassifierType: Boolean
|
||||
|
||||
val SimpleType.isIntersectionType: Boolean
|
||||
get() = constructor is IntersectionTypeConstructor
|
||||
|
||||
val SimpleType.isIntegerLiteralType: Boolean
|
||||
get() = constructor is IntegerLiteralTypeConstructor
|
||||
|
||||
@@ -180,6 +180,32 @@ object AbstractTypeChecker {
|
||||
return isSubtypeOfForSingleClassifierType(subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())
|
||||
}
|
||||
|
||||
private fun AbstractTypeCheckerContext.checkSubtypeForIntegerLiteralType(subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean? {
|
||||
if (!subType.isIntegerLiteralType() && !superType.isIntegerLiteralType()) return null
|
||||
|
||||
fun typeInIntegerLiteralType(integerLiteralType: SimpleTypeMarker, type: SimpleTypeMarker): Boolean =
|
||||
integerLiteralType.possibleIntegerTypes().any { it.typeConstructor() == type.typeConstructor() }
|
||||
|
||||
when {
|
||||
subType.isIntegerLiteralType() && superType.isIntegerLiteralType() -> {
|
||||
return true
|
||||
}
|
||||
|
||||
subType.isIntegerLiteralType() -> {
|
||||
if (typeInIntegerLiteralType(subType, superType)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
superType.isIntegerLiteralType() -> {
|
||||
if (typeInIntegerLiteralType(superType, subType)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun AbstractTypeCheckerContext.hasNothingSupertype(type: SimpleTypeMarker) = // todo add tests
|
||||
anySupertype(type, { it.typeConstructor().isNothingConstructor() }) {
|
||||
if (it.isClassType()) {
|
||||
@@ -199,6 +225,11 @@ object AbstractTypeChecker {
|
||||
|
||||
if (!AbstractNullabilityChecker.isPossibleSubtype(this, subType, superType)) return false
|
||||
|
||||
checkSubtypeForIntegerLiteralType(subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())?.let {
|
||||
addSubtypeConstraint(subType, superType)
|
||||
return it
|
||||
}
|
||||
|
||||
val superConstructor = superType.typeConstructor()
|
||||
|
||||
if (isEqualTypeConstructors(subType.typeConstructor(), superConstructor) && superConstructor.parametersCount() == 0) return true
|
||||
@@ -397,7 +428,7 @@ object AbstractTypeChecker {
|
||||
}
|
||||
|
||||
// i.e. superType is not a classType
|
||||
if (!constructor.isClassTypeConstructor()) {
|
||||
if (!constructor.isClassTypeConstructor() && !constructor.isIntegerLiteralTypeConstructor()) {
|
||||
return collectAllSupertypesWithGivenTypeConstructor(baseType, constructor)
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ interface TypeSystemContext : TypeSystemOptimizationContext {
|
||||
fun TypeConstructorMarker.supertypes(): Collection<KotlinTypeMarker>
|
||||
fun TypeConstructorMarker.isIntersection(): Boolean
|
||||
fun TypeConstructorMarker.isClassTypeConstructor(): Boolean
|
||||
fun TypeConstructorMarker.isIntegerLiteralTypeConstructor(): Boolean
|
||||
|
||||
fun TypeParameterMarker.getVariance(): TypeVariance
|
||||
fun TypeParameterMarker.upperBoundCount(): Int
|
||||
@@ -105,6 +106,10 @@ interface TypeSystemContext : TypeSystemOptimizationContext {
|
||||
|
||||
fun SimpleTypeMarker.isClassType(): Boolean = typeConstructor().isClassTypeConstructor()
|
||||
|
||||
fun SimpleTypeMarker.isIntegerLiteralType(): Boolean = typeConstructor().isIntegerLiteralTypeConstructor()
|
||||
|
||||
fun SimpleTypeMarker.possibleIntegerTypes(): Collection<KotlinTypeMarker>
|
||||
|
||||
fun TypeConstructorMarker.isCommonFinalClassConstructor(): Boolean
|
||||
|
||||
fun captureFromArguments(
|
||||
|
||||
Reference in New Issue
Block a user