[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
@@ -34,6 +34,15 @@ class ErrorTypeConstructor(reason: String) : TypeConstructorMarker
interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
val session: FirSession
override fun TypeConstructorMarker.isIntegerLiteralTypeConstructor(): Boolean {
// TODO()
return false
}
override fun SimpleTypeMarker.possibleIntegerTypes(): Collection<KotlinTypeMarker> {
TODO("not implemented")
}
override fun KotlinTypeMarker.asSimpleType(): SimpleTypeMarker? {
assert(this is ConeKotlinType)
return when (this) {
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.tower.PSICallResolver
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionResultCallInfo
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.ScopeUtils
@@ -510,8 +511,8 @@ class DelegatedPropertyResolver(
var delegateDataFlow = delegateTypeInfo.dataFlowInfo
val delegateTypeConstructor = delegateType.constructor
if (delegateTypeConstructor is IntegerValueTypeConstructor)
delegateType = TypeUtils.getDefaultPrimitiveNumberType(delegateTypeConstructor)
if (delegateTypeConstructor is IntegerLiteralTypeConstructor)
delegateType = delegateTypeConstructor.getApproximatedType()
if (languageVersionSettings.supportsFeature(LanguageFeature.OperatorProvideDelegate)) {
val contextForProvideDelegate = createContextForProvideDelegateMethod(
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil;
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor;
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant;
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor;
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
@@ -431,6 +432,12 @@ public class ArgumentTypeResolver {
constantExpressionEvaluator.updateNumberType(primitiveType, expression, statementFilter, trace);
return primitiveType;
}
if (typeConstructor instanceof IntegerLiteralTypeConstructor) {
IntegerLiteralTypeConstructor constructor = (IntegerLiteralTypeConstructor) typeConstructor;
KotlinType primitiveType = TypeUtils.getPrimitiveNumberType(constructor, expectedType);
constantExpressionEvaluator.updateNumberType(primitiveType, expression, statementFilter, trace);
return primitiveType;
}
}
return null;
}
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver
@@ -634,10 +635,11 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
resultingDescriptor = run {
val candidateDescriptor = resolvedCallAtom.candidateDescriptor
val containsCapturedTypes = resolvedCallAtom.candidateDescriptor.returnType?.contains { it is NewCapturedType } ?: false
val containsIntegerLiteralTypes = resolvedCallAtom.candidateDescriptor.returnType?.contains { it.constructor is IntegerLiteralTypeConstructor } ?: false
when {
candidateDescriptor is FunctionDescriptor ||
(candidateDescriptor is PropertyDescriptor && (candidateDescriptor.typeParameters.isNotEmpty() || containsCapturedTypes)) ->
(candidateDescriptor is PropertyDescriptor && (candidateDescriptor.typeParameters.isNotEmpty() || containsCapturedTypes || containsIntegerLiteralTypes)) ->
// this code is very suspicious. Now it is very useful for BE, because they cannot do nothing with captured types,
// but it seems like temporary solution.
candidateDescriptor.substitute(resolvedCallAtom.substitutor).substituteAndApproximateCapturedTypes(
@@ -650,7 +652,7 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
typeArguments = resolvedCallAtom.substitutor.freshVariables.map {
val substituted = (substitutor ?: FreshVariableNewTypeSubstitutor.Empty).safeSubstitute(it.defaultType)
TypeApproximator().approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: substituted
TypeApproximator().approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation) ?: substituted
}
calculateExpedtedTypeForSamConvertedArgumentMap(substitutor)
@@ -971,7 +971,12 @@ private class ConstantExpressionEvaluatorVisitor(
}
if (TypeUtils.noExpectedType(expectedType) || expectedType.isError) {
return createIntegerValueTypeConstant(value, constantExpressionEvaluator.module, parameters)
return createIntegerValueTypeConstant(
value,
constantExpressionEvaluator.module,
parameters,
languageVersionSettings.supportsFeature(LanguageFeature.NewInference)
)
}
val integerValue = ConstantValueFactory.createIntegerConstantValue(
value, expectedType, parameters.isUnsignedNumberLiteral
@@ -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
}
@@ -2,13 +2,13 @@
// !DIAGNOSTICS: -USELESS_ELVIS
fun test() {
bar(<!NI;TYPE_MISMATCH!>if (true) {
bar(<!NI;TYPE_MISMATCH, NI;TYPE_MISMATCH!>if (true) {
<!OI;CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>
} else {
<!OI;CONSTANT_EXPECTED_TYPE_MISMATCH!>2<!>
}<!>)
bar(<!NI;TYPE_MISMATCH!><!OI;CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!> ?: <!OI;CONSTANT_EXPECTED_TYPE_MISMATCH!>2<!><!>)
bar(<!NI;TYPE_MISMATCH, NI;TYPE_MISMATCH!><!OI;CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!> ?: <!OI;CONSTANT_EXPECTED_TYPE_MISMATCH!>2<!><!>)
}
fun bar(s: String) = s
@@ -222,7 +222,7 @@ fun case_16() {
}
// TESTCASE NUMBER: 17
val case_17 = <!DEBUG_INFO_EXPRESSION_TYPE("{Comparable<{Boolean & Byte & Int & Long & Short}> & java.io.Serializable}")!>if (nullableIntProperty == null) 0 else {
val case_17 = <!DEBUG_INFO_EXPRESSION_TYPE("{Comparable<{Boolean & Int}> & java.io.Serializable}")!>if (nullableIntProperty == null) 0 else {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int & kotlin.Int?")!>nullableIntProperty<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int & kotlin.Int?"), DEBUG_INFO_SMARTCAST!>nullableIntProperty<!>.equals(nullableIntProperty)
}<!>
@@ -24,8 +24,8 @@ fun case_1() {
val x = case_1(Out(10), Inv(0.1))
if (x != null) {
<!DEBUG_INFO_EXPRESSION_TYPE("{Comparable<{Byte & Double & Int & Long & Short}> & Number} & {Comparable<{Byte & Double & Int & Long & Short}> & Number}?")!>x<!>
<!DEBUG_INFO_EXPRESSION_TYPE("{Comparable<{Byte & Double & Int & Long & Short}> & Number} & {Comparable<{Byte & Double & Int & Long & Short}> & Number}?"), DEBUG_INFO_SMARTCAST!>x<!>.equals(x)
<!DEBUG_INFO_EXPRESSION_TYPE("{Comparable<{Double & Int}> & Number} & {Comparable<{Double & Int}> & Number}?")!>x<!>
<!DEBUG_INFO_EXPRESSION_TYPE("{Comparable<{Double & Int}> & Number} & {Comparable<{Double & Int}> & Number}?"), DEBUG_INFO_SMARTCAST!>x<!>.equals(x)
}
}
@@ -636,7 +636,7 @@ fun case_51() {
}
// TESTCASE NUMBER: 52
val case_52 = <!DEBUG_INFO_EXPRESSION_TYPE("{Comparable<{Boolean & Byte & Int & Long & Short}> & java.io.Serializable}")!>if (nullableIntProperty !== <!DEBUG_INFO_CONSTANT!>nullableNothingProperty<!> && <!DEBUG_INFO_CONSTANT!>nullableNothingProperty<!> != nullableIntProperty) 0 else {
val case_52 = <!DEBUG_INFO_EXPRESSION_TYPE("{Comparable<{Boolean & Int}> & java.io.Serializable}")!>if (nullableIntProperty !== <!DEBUG_INFO_CONSTANT!>nullableNothingProperty<!> && <!DEBUG_INFO_CONSTANT!>nullableNothingProperty<!> != nullableIntProperty) 0 else {
<!DEBUG_INFO_CONSTANT, DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int? & kotlin.Nothing?")!>nullableIntProperty<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int? & kotlin.Nothing?")!>nullableIntProperty<!>.equals(<!DEBUG_INFO_CONSTANT!>nullableIntProperty<!>)
}<!>
@@ -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()
@@ -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() }}]"
}
@@ -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;
}
@@ -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 {
@@ -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(
@@ -49,6 +49,7 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
@@ -209,10 +210,10 @@ internal fun KotlinType.toPsiType(lightDeclaration: PsiModifierListOwner?, conte
"kotlin.String" -> PsiType.getJavaLangString(context.manager, context.resolveScope)
else -> {
val typeConstructor = this.constructor
if (typeConstructor is IntegerValueTypeConstructor) {
TypeUtils.getDefaultPrimitiveNumberType(typeConstructor).toPsiType(lightDeclaration, context, boxed)
} else {
null
when (typeConstructor) {
is IntegerValueTypeConstructor -> TypeUtils.getDefaultPrimitiveNumberType(typeConstructor).toPsiType(lightDeclaration, context, boxed)
is IntegerLiteralTypeConstructor -> typeConstructor.getApproximatedType().toPsiType(lightDeclaration, context, boxed)
else -> null
}
}
}