[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 { interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
val session: FirSession 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? { override fun KotlinTypeMarker.asSimpleType(): SimpleTypeMarker? {
assert(this is ConeKotlinType) assert(this is ConeKotlinType)
return when (this) { 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.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.tower.PSICallResolver import org.jetbrains.kotlin.resolve.calls.tower.PSICallResolver
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionResultCallInfo 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.constants.IntegerValueTypeConstructor
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.ScopeUtils import org.jetbrains.kotlin.resolve.scopes.ScopeUtils
@@ -510,8 +511,8 @@ class DelegatedPropertyResolver(
var delegateDataFlow = delegateTypeInfo.dataFlowInfo var delegateDataFlow = delegateTypeInfo.dataFlowInfo
val delegateTypeConstructor = delegateType.constructor val delegateTypeConstructor = delegateType.constructor
if (delegateTypeConstructor is IntegerValueTypeConstructor) if (delegateTypeConstructor is IntegerLiteralTypeConstructor)
delegateType = TypeUtils.getDefaultPrimitiveNumberType(delegateTypeConstructor) delegateType = delegateTypeConstructor.getApproximatedType()
if (languageVersionSettings.supportsFeature(LanguageFeature.OperatorProvideDelegate)) { if (languageVersionSettings.supportsFeature(LanguageFeature.OperatorProvideDelegate)) {
val contextForProvideDelegate = createContextForProvideDelegateMethod( 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.OverloadResolutionResults;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil;
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; 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.IntegerValueTypeConstant;
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor; import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor;
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator; import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
@@ -431,6 +432,12 @@ public class ArgumentTypeResolver {
constantExpressionEvaluator.updateNumberType(primitiveType, expression, statementFilter, trace); constantExpressionEvaluator.updateNumberType(primitiveType, expression, statementFilter, trace);
return primitiveType; 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; 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.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy 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.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver
@@ -634,10 +635,11 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
resultingDescriptor = run { resultingDescriptor = run {
val candidateDescriptor = resolvedCallAtom.candidateDescriptor val candidateDescriptor = resolvedCallAtom.candidateDescriptor
val containsCapturedTypes = resolvedCallAtom.candidateDescriptor.returnType?.contains { it is NewCapturedType } ?: false val containsCapturedTypes = resolvedCallAtom.candidateDescriptor.returnType?.contains { it is NewCapturedType } ?: false
val containsIntegerLiteralTypes = resolvedCallAtom.candidateDescriptor.returnType?.contains { it.constructor is IntegerLiteralTypeConstructor } ?: false
when { when {
candidateDescriptor is FunctionDescriptor || 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, // 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. // but it seems like temporary solution.
candidateDescriptor.substitute(resolvedCallAtom.substitutor).substituteAndApproximateCapturedTypes( candidateDescriptor.substitute(resolvedCallAtom.substitutor).substituteAndApproximateCapturedTypes(
@@ -650,7 +652,7 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
typeArguments = resolvedCallAtom.substitutor.freshVariables.map { typeArguments = resolvedCallAtom.substitutor.freshVariables.map {
val substituted = (substitutor ?: FreshVariableNewTypeSubstitutor.Empty).safeSubstitute(it.defaultType) val substituted = (substitutor ?: FreshVariableNewTypeSubstitutor.Empty).safeSubstitute(it.defaultType)
TypeApproximator().approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: substituted TypeApproximator().approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation) ?: substituted
} }
calculateExpedtedTypeForSamConvertedArgumentMap(substitutor) calculateExpedtedTypeForSamConvertedArgumentMap(substitutor)
@@ -971,7 +971,12 @@ private class ConstantExpressionEvaluatorVisitor(
} }
if (TypeUtils.noExpectedType(expectedType) || expectedType.isError) { 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( val integerValue = ConstantValueFactory.createIntegerConstantValue(
value, expectedType, parameters.isUnsignedNumberLiteral 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.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.* import org.jetbrains.kotlin.types.checker.*
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
@@ -114,6 +115,8 @@ object NewCommonSuperTypeCalculator {
val explicitSupertypes = uniqueTypes.filterSupertypes() val explicitSupertypes = uniqueTypes.filterSupertypes()
if (explicitSupertypes.size == 1) return explicitSupertypes.single() if (explicitSupertypes.size == 1) return explicitSupertypes.single()
IntegerLiteralTypeConstructor.findCommonSuperType(explicitSupertypes)?.let { return it }
return findSuperTypeConstructorsAndIntersectResult(explicitSupertypes, depth) 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.inference.model.ExpectedTypeConstraintPosition
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tower.forceResolution 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.ErrorUtils
import org.jetbrains.kotlin.types.IntersectionTypeConstructor
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
class KotlinCallCompleter( class KotlinCallCompleter(
private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer, private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer,
@@ -202,19 +200,11 @@ class KotlinCallCompleter(
val variableWithConstraints = csBuilder.currentStorage().notFixedTypeVariables[constructor] ?: return false val variableWithConstraints = csBuilder.currentStorage().notFixedTypeVariables[constructor] ?: return false
val constraints = variableWithConstraints.constraints val constraints = variableWithConstraints.constraints
return constraints.isNotEmpty() && constraints.all { 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) 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( private fun KotlinResolutionCandidate.computeReturnTypeWithSmartCastInfo(
returnType: UnwrappedType, returnType: UnwrappedType,
resolutionCallbacks: KotlinResolutionCallbacks resolutionCallbacks: KotlinResolutionCallbacks
@@ -63,7 +63,7 @@ fun CallableDescriptor.substituteAndApproximateCapturedTypes(substitutor: NewTyp
override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) = override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) =
substitutor.safeSubstitute(topLevelType.unwrap()).let { substitutedType -> substitutor.safeSubstitute(topLevelType.unwrap()).let { substitutedType ->
TypeApproximator().approximateToSuperType(substitutedType, TypeApproximatorConfiguration.CapturedTypesApproximation) TypeApproximator().approximateToSuperType(substitutedType, TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation)
?: substitutedType ?: 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.ConstraintKind
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
import org.jetbrains.kotlin.resolve.calls.inference.model.checkConstraint 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.*
import org.jetbrains.kotlin.types.checker.intersectTypes import org.jetbrains.kotlin.types.checker.intersectTypes
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
class ResultTypeResolver( class ResultTypeResolver(
val typeApproximator: TypeApproximator, val typeApproximator: TypeApproximator,
@@ -88,7 +86,6 @@ class ResultTypeResolver(
val lowerConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.LOWER && c.isProperType(it.type) } val lowerConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.LOWER && c.isProperType(it.type) }
if (lowerConstraints.isNotEmpty()) { if (lowerConstraints.isNotEmpty()) {
val commonSuperType = NewCommonSuperTypeCalculator.commonSuperType(lowerConstraints.map { it.type }) val commonSuperType = NewCommonSuperTypeCalculator.commonSuperType(lowerConstraints.map { it.type })
val adjustedCommonSuperType = adjustCommonSupertypeWithKnowledgeOfNumberTypes(commonSuperType)
/** /**
* *
* fun <T> Array<out T>.intersect(other: Iterable<T>) { * fun <T> Array<out T>.intersect(other: Iterable<T>) {
@@ -108,52 +105,20 @@ class ResultTypeResolver(
*/ */
return typeApproximator.approximateToSuperType( return typeApproximator.approximateToSuperType(
adjustedCommonSuperType, commonSuperType,
TypeApproximatorConfiguration.CapturedTypesApproximation TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation
) ) ?: commonSuperType
?: adjustedCommonSuperType
} }
return null 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? { private fun findSuperType(c: Context, variableWithConstraints: VariableWithConstraints): UnwrappedType? {
val upperConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.UPPER && c.isProperType(it.type) } val upperConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.UPPER && c.isProperType(it.type) }
if (upperConstraints.isNotEmpty()) { if (upperConstraints.isNotEmpty()) {
val upperType = intersectTypes(upperConstraints.map { it.type }) val upperType = intersectTypes(upperConstraints.map { it.type })
return typeApproximator.approximateToSubType(upperType, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: upperType return typeApproximator.approximateToSubType(upperType, TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation) ?: upperType
} }
return null return null
} }
@@ -241,10 +241,10 @@ abstract class TypeCheckerContextForConstraintSystem : ClassicTypeCheckerContext
private fun assertInputTypes(subType: UnwrappedType, superType: UnwrappedType) { private fun assertInputTypes(subType: UnwrappedType, superType: UnwrappedType) {
fun correctSubType(subType: SimpleType) = 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) = 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)) { assert(subType.bothBounds(::correctSubType)) {
"Not singleClassifierType and not intersection subType: $subType" "Not singleClassifierType and not intersection subType: $subType"
@@ -142,11 +142,11 @@ internal class MemberScopeTowerLevel(
Variance.INVARIANT -> null Variance.INVARIANT -> null
Variance.OUT_VARIANCE -> approximator.approximateToSuperType( Variance.OUT_VARIANCE -> approximator.approximateToSuperType(
topLevelType.unwrap(), topLevelType.unwrap(),
TypeApproximatorConfiguration.CapturedTypesApproximation TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation
) )
Variance.IN_VARIANCE -> approximator.approximateToSubType( Variance.IN_VARIANCE -> approximator.approximateToSubType(
topLevelType.unwrap(), topLevelType.unwrap(),
TypeApproximatorConfiguration.CapturedTypesApproximation TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation
) )
} ?: topLevelType } ?: topLevelType
} }
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor 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.TypeApproximatorConfiguration.IntersectionStrategy.*
import org.jetbrains.kotlin.types.checker.* import org.jetbrains.kotlin.types.checker.*
import org.jetbrains.kotlin.types.model.CaptureStatus import org.jetbrains.kotlin.types.model.CaptureStatus
@@ -41,6 +42,7 @@ open class TypeApproximatorConfiguration {
open val dynamic get() = false // DynamicType open val dynamic get() = false // DynamicType
open val rawType get() = false // RawTypeImpl open val rawType get() = false // RawTypeImpl
open val errorType get() = false open val errorType get() = false
open val integerLiteralType: Boolean = false // IntegerLiteralTypeConstructor
open val definitelyNotNullType get() = true open val definitelyNotNullType get() = true
open val intersection: IntersectionStrategy = TO_COMMON_SUPERTYPE open val intersection: IntersectionStrategy = TO_COMMON_SUPERTYPE
@@ -59,12 +61,14 @@ open class TypeApproximatorConfiguration {
override val allFlexible get() = true override val allFlexible get() = true
override val intersection get() = ALLOWED override val intersection get() = ALLOWED
override val errorType get() = true override val errorType get() = true
override val integerLiteralType: Boolean get() = true
} }
object PublicDeclaration : AllFlexibleSameValue() { object PublicDeclaration : AllFlexibleSameValue() {
override val allFlexible get() = true override val allFlexible get() = true
override val errorType get() = true override val errorType get() = true
override val definitelyNotNullType get() = false override val definitelyNotNullType get() = false
override val integerLiteralType: Boolean get() = true
} }
abstract class AbstractCapturedTypesApproximation(val approximatedCapturedStatus: CaptureStatus) : abstract class AbstractCapturedTypesApproximation(val approximatedCapturedStatus: CaptureStatus) :
@@ -80,7 +84,9 @@ open class TypeApproximatorConfiguration {
object IncorporationConfiguration : TypeApproximatorConfiguration.AbstractCapturedTypesApproximation(FOR_INCORPORATION) object IncorporationConfiguration : TypeApproximatorConfiguration.AbstractCapturedTypesApproximation(FOR_INCORPORATION)
object SubtypeCapturedTypesApproximation : TypeApproximatorConfiguration.AbstractCapturedTypesApproximation(FOR_SUBTYPING) 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 { class TypeApproximator {
@@ -314,6 +320,13 @@ class TypeApproximator {
return if (conf.typeVariable(typeConstructor)) null else type.defaultResult(toSuper) 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 return null // simple classifier type
} }
@@ -2,13 +2,13 @@
// !DIAGNOSTICS: -USELESS_ELVIS // !DIAGNOSTICS: -USELESS_ELVIS
fun test() { fun test() {
bar(<!NI;TYPE_MISMATCH!>if (true) { bar(<!NI;TYPE_MISMATCH, NI;TYPE_MISMATCH!>if (true) {
<!OI;CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!> <!OI;CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>
} else { } else {
<!OI;CONSTANT_EXPECTED_TYPE_MISMATCH!>2<!> <!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 fun bar(s: String) = s
@@ -222,7 +222,7 @@ fun case_16() {
} }
// TESTCASE NUMBER: 17 // 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?")!>nullableIntProperty<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int & kotlin.Int?"), DEBUG_INFO_SMARTCAST!>nullableIntProperty<!>.equals(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)) val x = case_1(Out(10), Inv(0.1))
if (x != null) { 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<{Double & Int}> & Number} & {Comparable<{Double & Int}> & 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}?"), DEBUG_INFO_SMARTCAST!>x<!>.equals(x)
} }
} }
@@ -636,7 +636,7 @@ fun case_51() {
} }
// TESTCASE NUMBER: 52 // 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_CONSTANT, DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int? & kotlin.Nothing?")!>nullableIntProperty<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int? & kotlin.Nothing?")!>nullableIntProperty<!>.equals(<!DEBUG_INFO_CONSTANT!>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(); return getPrimitiveClassDescriptor(type).getDefaultType();
} }
@NotNull
public SimpleType getNumberType() {
return getNumber().getDefaultType();
}
@NotNull @NotNull
public SimpleType getByteType() { public SimpleType getByteType() {
return getPrimitiveKotlinType(BYTE); return getPrimitiveKotlinType(BYTE);
@@ -91,9 +91,10 @@ class TypedCompileTimeConstant<out T>(
fun createIntegerValueTypeConstant( fun createIntegerValueTypeConstant(
value: Number, value: Number,
module: ModuleDescriptor, module: ModuleDescriptor,
parameters: CompileTimeConstant.Parameters parameters: CompileTimeConstant.Parameters,
newInferenceEnabled: Boolean
): CompileTimeConstant<*> { ): CompileTimeConstant<*> {
return IntegerValueTypeConstant(value, module, parameters) return IntegerValueTypeConstant(value, module, parameters, newInferenceEnabled)
} }
fun hasUnsignedTypesInModuleDependencies(module: ModuleDescriptor): Boolean { fun hasUnsignedTypesInModuleDependencies(module: ModuleDescriptor): Boolean {
@@ -121,6 +122,7 @@ class IntegerValueTypeConstant(
private val value: Number, private val value: Number,
module: ModuleDescriptor, module: ModuleDescriptor,
override val parameters: CompileTimeConstant.Parameters, override val parameters: CompileTimeConstant.Parameters,
private val newInferenceEnabled: Boolean,
val convertedFromSigned: Boolean = false val convertedFromSigned: Boolean = false
) : CompileTimeConstant<Number> { ) : CompileTimeConstant<Number> {
companion object { companion object {
@@ -136,7 +138,7 @@ class IntegerValueTypeConstant(
isConvertableConstVal = parameters.isConvertableConstVal isConvertableConstVal = parameters.isConvertableConstVal
) )
return IntegerValueTypeConstant(value, module, newParameters, convertedFromSigned = true) return IntegerValueTypeConstant(value, module, newParameters, newInferenceEnabled, convertedFromSigned = true)
} }
fun IntegerValueTypeConstant.convertToSignedConstant(module: ModuleDescriptor): IntegerValueTypeConstant { fun IntegerValueTypeConstant.convertToSignedConstant(module: ModuleDescriptor): IntegerValueTypeConstant {
@@ -150,11 +152,16 @@ class IntegerValueTypeConstant(
isConvertableConstVal = parameters.isConvertableConstVal 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> { override fun toConstantValue(expectedType: KotlinType): ConstantValue<Number> {
val type = getType(expectedType) val type = getType(expectedType)
@@ -178,7 +185,12 @@ class IntegerValueTypeConstant(
ErrorUtils.createErrorScope("Scope for number value type ($typeConstructor)", true) 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() 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() { private fun addUnsignedSuperTypes() {
checkBoundsAndAddSuperType(value, unsignedType(KotlinBuiltIns.FQ_NAMES.uInt)) checkBoundsAndAddSuperType(value, module.unsignedType(KotlinBuiltIns.FQ_NAMES.uInt))
checkBoundsAndAddSuperType(value, unsignedType(KotlinBuiltIns.FQ_NAMES.uByte)) checkBoundsAndAddSuperType(value, module.unsignedType(KotlinBuiltIns.FQ_NAMES.uByte))
checkBoundsAndAddSuperType(value, unsignedType(KotlinBuiltIns.FQ_NAMES.uShort)) checkBoundsAndAddSuperType(value, module.unsignedType(KotlinBuiltIns.FQ_NAMES.uShort))
supertypes.add(unsignedType(KotlinBuiltIns.FQ_NAMES.uLong)) supertypes.add(module.unsignedType(KotlinBuiltIns.FQ_NAMES.uLong))
} }
private fun checkBoundsAndAddSuperType(value: Long, kotlinType: KotlinType) { 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 getSupertypes(): Collection<KotlinType> = supertypes
override fun getParameters(): List<TypeParameterDescriptor> = emptyList() override fun getParameters(): List<TypeParameterDescriptor> = emptyList()
@@ -100,28 +98,3 @@ class IntegerValueTypeConstructor(
override fun toString() = "IntegerValueType($value)" 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.TypeAliasDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations 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.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
object KotlinTypeFactory { object KotlinTypeFactory {
private fun computeMemberScope(constructor: TypeConstructor, arguments: List<TypeProjection>): MemberScope { private fun computeMemberScope(constructor: TypeConstructor, arguments: List<TypeProjection>): MemberScope {
@@ -95,6 +97,19 @@ object KotlinTypeFactory {
if (lowerBound == upperBound) return lowerBound if (lowerBound == upperBound) return lowerBound
return FlexibleTypeImpl(lowerBound, upperBound) 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( private class SimpleTypeImpl(
@@ -150,4 +165,4 @@ private class NullableSimpleType(delegate: SimpleType) : DelegatingSimpleTypeImp
private class NotNullSimpleType(delegate: SimpleType) : DelegatingSimpleTypeImpl(delegate) { private class NotNullSimpleType(delegate: SimpleType) : DelegatingSimpleTypeImpl(delegate) {
override val isMarkedNullable: Boolean override val isMarkedNullable: Boolean
get() = false get() = false
} }
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.FqNameUnsafe; import org.jetbrains.kotlin.name.FqNameUnsafe;
import org.jetbrains.kotlin.resolve.DescriptorUtils; 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.constants.IntegerValueTypeConstructor;
import org.jetbrains.kotlin.resolve.scopes.MemberScope; import org.jetbrains.kotlin.resolve.scopes.MemberScope;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
@@ -498,6 +499,30 @@ public class TypeUtils {
return getDefaultPrimitiveNumberType(numberValueTypeConstructor); 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) { public static boolean isTypeParameter(@NotNull KotlinType type) {
return getTypeParameterDescriptorOrNull(type) != null || type.getConstructor() instanceof NewTypeVariableConstructor; return getTypeParameterDescriptorOrNull(type) != null || type.getConstructor() instanceof NewTypeVariableConstructor;
} }
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.types.checker package org.jetbrains.kotlin.types.checker
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker.transformToNewType import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker.transformToNewType
import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.KotlinTypeMarker
@@ -41,8 +42,15 @@ open class ClassicTypeCheckerContext(val errorTypeEqualsToAnything: Boolean, val
return areEqualTypeConstructors(a, b) return areEqualTypeConstructors(a, b)
} }
open fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean { open fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean = when {
return a == b /*
* 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 { 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.builtins.KotlinBuiltIns.FQ_NAMES
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.calls.inference.CapturedType 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.*
import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.types.model.CaptureStatus import org.jetbrains.kotlin.types.model.CaptureStatus
@@ -20,6 +21,17 @@ interface ClassicTypeSystemContext : TypeSystemContext {
return this.isDenotable 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 { override fun SimpleTypeMarker.withNullability(nullable: Boolean): SimpleTypeMarker {
require(this is SimpleType, this::errorMessage) require(this is SimpleType, this::errorMessage)
return this.makeNullableAsSpecified(nullable) return this.makeNullableAsSpecified(nullable)
@@ -221,7 +233,7 @@ interface ClassicTypeSystemContext : TypeSystemContext {
require(this is SimpleType, this::errorMessage) require(this is SimpleType, this::errorMessage)
return !isError && return !isError &&
constructor.declarationDescriptor !is TypeAliasDescriptor && 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 { override fun KotlinTypeMarker.isNotNullNothing(): Boolean {
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.types.checker package org.jetbrains.kotlin.types.checker
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import java.util.* import java.util.*
import kotlin.collections.LinkedHashSet import kotlin.collections.LinkedHashSet
@@ -71,14 +72,14 @@ object TypeIntersector {
assert(types.size > 1) { assert(types.size > 1) {
"Size should be at least 2, but it is ${types.size}" "Size should be at least 2, but it is ${types.size}"
} }
val inputTypes = ArrayList<SimpleType>() val inputTypes = ArrayList<SimpleType>()
for (type in types) { for (type in types) {
if (type.constructor is IntersectionTypeConstructor) { if (type.constructor is IntersectionTypeConstructor) {
inputTypes.addAll(type.constructor.supertypes.map { inputTypes.addAll(type.constructor.supertypes.map {
it.upperIfFlexible().let { if (type.isMarkedNullable) it.makeNullableAsSpecified(true) else it } it.upperIfFlexible().let { if (type.isMarkedNullable) it.makeNullableAsSpecified(true) else it }
}) })
} } else {
else {
inputTypes.add(type) inputTypes.add(type)
} }
} }
@@ -106,25 +107,41 @@ object TypeIntersector {
// Any and Nothing should leave // Any and Nothing should leave
// Note that duplicates should be dropped because we have Set here. // Note that duplicates should be dropped because we have Set here.
val filteredSuperAndEqualTypes = ArrayList(inputTypes) val errorMessage = { "This collections cannot be empty! input types: ${inputTypes.joinToString()}" }
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))
}
if (strictSupertypeOrHasEqual) iterator.remove() val filteredEqualTypes = filterTypes(inputTypes, ::isStrictSupertype)
} assert(filteredEqualTypes.isNotEmpty(), errorMessage)
assert(filteredSuperAndEqualTypes.isNotEmpty()) { IntegerLiteralTypeConstructor.findIntersectionType(filteredEqualTypes)?.let { return it }
"This collections cannot be empty! input types: ${inputTypes.joinToString()}"
} val filteredSuperAndEqualTypes = filterTypes(filteredEqualTypes, NewKotlinTypeChecker::equalTypes)
assert(filteredSuperAndEqualTypes.isNotEmpty(), errorMessage)
if (filteredSuperAndEqualTypes.size < 2) return filteredSuperAndEqualTypes.single() if (filteredSuperAndEqualTypes.size < 2) return filteredSuperAndEqualTypes.single()
val constructor = IntersectionTypeConstructor(inputTypes) 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 { private fun isStrictSupertype(subtype: KotlinType, supertype: KotlinType): Boolean {
@@ -146,9 +163,9 @@ object TypeIntersector {
// example: type parameter without not-null supertype // example: type parameter without not-null supertype
UNKNOWN { UNKNOWN {
override fun combine(nextType: UnwrappedType) = override fun combine(nextType: UnwrappedType) =
nextType.resultNullability.let { nextType.resultNullability.let {
if (it == ACCEPT_NULL) this else it if (it == ACCEPT_NULL) this else it
} }
}, },
NOT_NULL { NOT_NULL {
override fun combine(nextType: UnwrappedType) = this 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.descriptors.TypeAliasDescriptor
import org.jetbrains.kotlin.resolve.calls.inference.CapturedType import org.jetbrains.kotlin.resolve.calls.inference.CapturedType
import org.jetbrains.kotlin.resolve.calls.inference.CapturedTypeConstructorImpl 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.resolve.constants.IntegerValueTypeConstructor
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.AbstractNullabilityChecker.hasNotNullSupertype import org.jetbrains.kotlin.types.AbstractNullabilityChecker.hasNotNullSupertype
import org.jetbrains.kotlin.types.AbstractNullabilityChecker.hasPathByNotMarkedNullableNodes import org.jetbrains.kotlin.types.AbstractNullabilityChecker.hasPathByNotMarkedNullableNodes
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext.SupertypesPolicy import org.jetbrains.kotlin.types.AbstractTypeCheckerContext.SupertypesPolicy
import org.jetbrains.kotlin.types.model.CaptureStatus 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 { object StrictEqualityTypeChecker {
@@ -192,3 +194,6 @@ val SimpleType.isSingleClassifierType: Boolean
val SimpleType.isIntersectionType: Boolean val SimpleType.isIntersectionType: Boolean
get() = constructor is IntersectionTypeConstructor get() = constructor is IntersectionTypeConstructor
val SimpleType.isIntegerLiteralType: Boolean
get() = constructor is IntegerLiteralTypeConstructor
@@ -180,6 +180,32 @@ object AbstractTypeChecker {
return isSubtypeOfForSingleClassifierType(subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible()) 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 private fun AbstractTypeCheckerContext.hasNothingSupertype(type: SimpleTypeMarker) = // todo add tests
anySupertype(type, { it.typeConstructor().isNothingConstructor() }) { anySupertype(type, { it.typeConstructor().isNothingConstructor() }) {
if (it.isClassType()) { if (it.isClassType()) {
@@ -199,6 +225,11 @@ object AbstractTypeChecker {
if (!AbstractNullabilityChecker.isPossibleSubtype(this, subType, superType)) return false if (!AbstractNullabilityChecker.isPossibleSubtype(this, subType, superType)) return false
checkSubtypeForIntegerLiteralType(subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())?.let {
addSubtypeConstraint(subType, superType)
return it
}
val superConstructor = superType.typeConstructor() val superConstructor = superType.typeConstructor()
if (isEqualTypeConstructors(subType.typeConstructor(), superConstructor) && superConstructor.parametersCount() == 0) return true if (isEqualTypeConstructors(subType.typeConstructor(), superConstructor) && superConstructor.parametersCount() == 0) return true
@@ -397,7 +428,7 @@ object AbstractTypeChecker {
} }
// i.e. superType is not a classType // i.e. superType is not a classType
if (!constructor.isClassTypeConstructor()) { if (!constructor.isClassTypeConstructor() && !constructor.isIntegerLiteralTypeConstructor()) {
return collectAllSupertypesWithGivenTypeConstructor(baseType, constructor) return collectAllSupertypesWithGivenTypeConstructor(baseType, constructor)
} }
@@ -81,6 +81,7 @@ interface TypeSystemContext : TypeSystemOptimizationContext {
fun TypeConstructorMarker.supertypes(): Collection<KotlinTypeMarker> fun TypeConstructorMarker.supertypes(): Collection<KotlinTypeMarker>
fun TypeConstructorMarker.isIntersection(): Boolean fun TypeConstructorMarker.isIntersection(): Boolean
fun TypeConstructorMarker.isClassTypeConstructor(): Boolean fun TypeConstructorMarker.isClassTypeConstructor(): Boolean
fun TypeConstructorMarker.isIntegerLiteralTypeConstructor(): Boolean
fun TypeParameterMarker.getVariance(): TypeVariance fun TypeParameterMarker.getVariance(): TypeVariance
fun TypeParameterMarker.upperBoundCount(): Int fun TypeParameterMarker.upperBoundCount(): Int
@@ -105,6 +106,10 @@ interface TypeSystemContext : TypeSystemOptimizationContext {
fun SimpleTypeMarker.isClassType(): Boolean = typeConstructor().isClassTypeConstructor() fun SimpleTypeMarker.isClassType(): Boolean = typeConstructor().isClassTypeConstructor()
fun SimpleTypeMarker.isIntegerLiteralType(): Boolean = typeConstructor().isIntegerLiteralTypeConstructor()
fun SimpleTypeMarker.possibleIntegerTypes(): Collection<KotlinTypeMarker>
fun TypeConstructorMarker.isCommonFinalClassConstructor(): Boolean fun TypeConstructorMarker.isCommonFinalClassConstructor(): Boolean
fun captureFromArguments( fun captureFromArguments(
@@ -49,6 +49,7 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch 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.constants.IntegerValueTypeConstructor
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor 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) "kotlin.String" -> PsiType.getJavaLangString(context.manager, context.resolveScope)
else -> { else -> {
val typeConstructor = this.constructor val typeConstructor = this.constructor
if (typeConstructor is IntegerValueTypeConstructor) { when (typeConstructor) {
TypeUtils.getDefaultPrimitiveNumberType(typeConstructor).toPsiType(lightDeclaration, context, boxed) is IntegerValueTypeConstructor -> TypeUtils.getDefaultPrimitiveNumberType(typeConstructor).toPsiType(lightDeclaration, context, boxed)
} else { is IntegerLiteralTypeConstructor -> typeConstructor.getApproximatedType().toPsiType(lightDeclaration, context, boxed)
null else -> null
} }
} }
} }