[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:
@@ -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;
|
||||
}
|
||||
|
||||
+4
-2
@@ -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)
|
||||
|
||||
+6
-1
@@ -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
|
||||
|
||||
+3
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
@@ -114,6 +115,8 @@ object NewCommonSuperTypeCalculator {
|
||||
val explicitSupertypes = uniqueTypes.filterSupertypes()
|
||||
if (explicitSupertypes.size == 1) return explicitSupertypes.single()
|
||||
|
||||
IntegerLiteralTypeConstructor.findCommonSuperType(explicitSupertypes)?.let { return it }
|
||||
|
||||
return findSuperTypeConstructorsAndIntersectResult(explicitSupertypes, depth)
|
||||
}
|
||||
|
||||
|
||||
+2
-12
@@ -14,12 +14,10 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage.Empt
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.forceResolution
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.IntersectionTypeConstructor
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
|
||||
|
||||
class KotlinCallCompleter(
|
||||
private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer,
|
||||
@@ -202,19 +200,11 @@ class KotlinCallCompleter(
|
||||
val variableWithConstraints = csBuilder.currentStorage().notFixedTypeVariables[constructor] ?: return false
|
||||
val constraints = variableWithConstraints.constraints
|
||||
return constraints.isNotEmpty() && constraints.all {
|
||||
!trivialConstraintTypeInferenceOracle.isTrivialConstraint(it) && !it.type.isIntegerValueType() &&
|
||||
!trivialConstraintTypeInferenceOracle.isTrivialConstraint(it) && it.type.constructor !is IntegerLiteralTypeConstructor &&
|
||||
it.kind.isLower() && csBuilder.isProperType(it.type)
|
||||
}
|
||||
}
|
||||
|
||||
private fun UnwrappedType.isIntegerValueType(): Boolean {
|
||||
if (constructor is IntegerValueTypeConstructor) return true
|
||||
if (constructor is IntersectionTypeConstructor)
|
||||
return constructor.supertypes.all { it.isPrimitiveNumberType() }
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun KotlinResolutionCandidate.computeReturnTypeWithSmartCastInfo(
|
||||
returnType: UnwrappedType,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ fun CallableDescriptor.substituteAndApproximateCapturedTypes(substitutor: NewTyp
|
||||
|
||||
override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) =
|
||||
substitutor.safeSubstitute(topLevelType.unwrap()).let { substitutedType ->
|
||||
TypeApproximator().approximateToSuperType(substitutedType, TypeApproximatorConfiguration.CapturedTypesApproximation)
|
||||
TypeApproximator().approximateToSuperType(substitutedType, TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation)
|
||||
?: substitutedType
|
||||
}
|
||||
}
|
||||
|
||||
+4
-39
@@ -21,10 +21,8 @@ import org.jetbrains.kotlin.resolve.calls.inference.components.TypeVariableDirec
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.checkConstraint
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.intersectTypes
|
||||
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
|
||||
|
||||
class ResultTypeResolver(
|
||||
val typeApproximator: TypeApproximator,
|
||||
@@ -88,7 +86,6 @@ class ResultTypeResolver(
|
||||
val lowerConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.LOWER && c.isProperType(it.type) }
|
||||
if (lowerConstraints.isNotEmpty()) {
|
||||
val commonSuperType = NewCommonSuperTypeCalculator.commonSuperType(lowerConstraints.map { it.type })
|
||||
val adjustedCommonSuperType = adjustCommonSupertypeWithKnowledgeOfNumberTypes(commonSuperType)
|
||||
/**
|
||||
*
|
||||
* fun <T> Array<out T>.intersect(other: Iterable<T>) {
|
||||
@@ -108,52 +105,20 @@ class ResultTypeResolver(
|
||||
*/
|
||||
|
||||
return typeApproximator.approximateToSuperType(
|
||||
adjustedCommonSuperType,
|
||||
TypeApproximatorConfiguration.CapturedTypesApproximation
|
||||
)
|
||||
?: adjustedCommonSuperType
|
||||
commonSuperType,
|
||||
TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation
|
||||
) ?: commonSuperType
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun adjustCommonSupertypeWithKnowledgeOfNumberTypes(commonSuperType: UnwrappedType): UnwrappedType {
|
||||
val constructor = commonSuperType.constructor
|
||||
|
||||
return when (constructor) {
|
||||
is IntegerValueTypeConstructor,
|
||||
is IntersectionTypeConstructor -> {
|
||||
val newSupertypes = arrayListOf<UnwrappedType>()
|
||||
val numberSupertypes = arrayListOf<KotlinType>()
|
||||
for (supertype in constructor.supertypes.map { it.unwrap() }) {
|
||||
if (supertype.isPrimitiveNumberType())
|
||||
numberSupertypes.add(supertype)
|
||||
else
|
||||
newSupertypes.add(supertype)
|
||||
}
|
||||
|
||||
|
||||
val representativeNumberType = TypeUtils.getDefaultPrimitiveNumberType(numberSupertypes)
|
||||
if (representativeNumberType != null) {
|
||||
newSupertypes.add(representativeNumberType.unwrap())
|
||||
} else {
|
||||
newSupertypes.addAll(numberSupertypes.map { it.unwrap() })
|
||||
}
|
||||
|
||||
intersectTypes(newSupertypes).makeNullableAsSpecified(commonSuperType.isMarkedNullable)
|
||||
}
|
||||
|
||||
else ->
|
||||
commonSuperType
|
||||
}
|
||||
}
|
||||
|
||||
private fun findSuperType(c: Context, variableWithConstraints: VariableWithConstraints): UnwrappedType? {
|
||||
val upperConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.UPPER && c.isProperType(it.type) }
|
||||
if (upperConstraints.isNotEmpty()) {
|
||||
val upperType = intersectTypes(upperConstraints.map { it.type })
|
||||
|
||||
return typeApproximator.approximateToSubType(upperType, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: upperType
|
||||
return typeApproximator.approximateToSubType(upperType, TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation) ?: upperType
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
+2
-2
@@ -241,10 +241,10 @@ abstract class TypeCheckerContextForConstraintSystem : ClassicTypeCheckerContext
|
||||
|
||||
private fun assertInputTypes(subType: UnwrappedType, superType: UnwrappedType) {
|
||||
fun correctSubType(subType: SimpleType) =
|
||||
subType.isSingleClassifierType || subType.isIntersectionType || isMyTypeVariable(subType) || subType.isError
|
||||
subType.isSingleClassifierType || subType.isIntersectionType || isMyTypeVariable(subType) || subType.isError || subType.isIntegerLiteralType
|
||||
|
||||
fun correctSuperType(superType: SimpleType) =
|
||||
superType.isSingleClassifierType || superType.isIntersectionType || isMyTypeVariable(superType) || superType.isError
|
||||
superType.isSingleClassifierType || superType.isIntersectionType || isMyTypeVariable(superType) || superType.isError || superType.isIntegerLiteralType
|
||||
|
||||
assert(subType.bothBounds(::correctSubType)) {
|
||||
"Not singleClassifierType and not intersection subType: $subType"
|
||||
|
||||
@@ -142,11 +142,11 @@ internal class MemberScopeTowerLevel(
|
||||
Variance.INVARIANT -> null
|
||||
Variance.OUT_VARIANCE -> approximator.approximateToSuperType(
|
||||
topLevelType.unwrap(),
|
||||
TypeApproximatorConfiguration.CapturedTypesApproximation
|
||||
TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation
|
||||
)
|
||||
Variance.IN_VARIANCE -> approximator.approximateToSubType(
|
||||
topLevelType.unwrap(),
|
||||
TypeApproximatorConfiguration.CapturedTypesApproximation
|
||||
TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation
|
||||
)
|
||||
} ?: topLevelType
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration.IntersectionStrategy.*
|
||||
import org.jetbrains.kotlin.types.checker.*
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
@@ -41,6 +42,7 @@ open class TypeApproximatorConfiguration {
|
||||
open val dynamic get() = false // DynamicType
|
||||
open val rawType get() = false // RawTypeImpl
|
||||
open val errorType get() = false
|
||||
open val integerLiteralType: Boolean = false // IntegerLiteralTypeConstructor
|
||||
open val definitelyNotNullType get() = true
|
||||
open val intersection: IntersectionStrategy = TO_COMMON_SUPERTYPE
|
||||
|
||||
@@ -59,12 +61,14 @@ open class TypeApproximatorConfiguration {
|
||||
override val allFlexible get() = true
|
||||
override val intersection get() = ALLOWED
|
||||
override val errorType get() = true
|
||||
override val integerLiteralType: Boolean get() = true
|
||||
}
|
||||
|
||||
object PublicDeclaration : AllFlexibleSameValue() {
|
||||
override val allFlexible get() = true
|
||||
override val errorType get() = true
|
||||
override val definitelyNotNullType get() = false
|
||||
override val integerLiteralType: Boolean get() = true
|
||||
}
|
||||
|
||||
abstract class AbstractCapturedTypesApproximation(val approximatedCapturedStatus: CaptureStatus) :
|
||||
@@ -80,7 +84,9 @@ open class TypeApproximatorConfiguration {
|
||||
|
||||
object IncorporationConfiguration : TypeApproximatorConfiguration.AbstractCapturedTypesApproximation(FOR_INCORPORATION)
|
||||
object SubtypeCapturedTypesApproximation : TypeApproximatorConfiguration.AbstractCapturedTypesApproximation(FOR_SUBTYPING)
|
||||
object CapturedTypesApproximation : TypeApproximatorConfiguration.AbstractCapturedTypesApproximation(FROM_EXPRESSION)
|
||||
object CapturedAndIntegerLiteralsTypesApproximation : TypeApproximatorConfiguration.AbstractCapturedTypesApproximation(FROM_EXPRESSION) {
|
||||
override val integerLiteralType: Boolean get() = true
|
||||
}
|
||||
}
|
||||
|
||||
class TypeApproximator {
|
||||
@@ -314,6 +320,13 @@ class TypeApproximator {
|
||||
return if (conf.typeVariable(typeConstructor)) null else type.defaultResult(toSuper)
|
||||
}
|
||||
|
||||
if (typeConstructor is IntegerLiteralTypeConstructor) {
|
||||
return if (conf.integerLiteralType)
|
||||
typeConstructor.getApproximatedType().unwrap().makeNullableAsSpecified(type.isMarkedNullable)
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
return null // simple classifier type
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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
|
||||
+1
-1
@@ -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)
|
||||
}<!>
|
||||
|
||||
+2
-2
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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()
|
||||
|
||||
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.constants
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import java.lang.IllegalStateException
|
||||
|
||||
class IntegerLiteralTypeConstructor : TypeConstructor {
|
||||
companion object {
|
||||
fun findCommonSuperType(types: Collection<SimpleType>): SimpleType? =
|
||||
findCommonSuperTypeOrIntersectionType(types, Companion.Mode.COMMON_SUPER_TYPE)
|
||||
|
||||
fun findIntersectionType(types: Collection<SimpleType>): SimpleType? =
|
||||
findCommonSuperTypeOrIntersectionType(types, Companion.Mode.INTERSECTION_TYPE)
|
||||
|
||||
private enum class Mode {
|
||||
COMMON_SUPER_TYPE, INTERSECTION_TYPE
|
||||
}
|
||||
|
||||
/**
|
||||
* intersection(ILT(types), PrimitiveType) = commonSuperType(ILT(types), PrimitiveType) =
|
||||
* PrimitiveType in types -> PrimitiveType
|
||||
* PrimitiveType !in types -> null
|
||||
*
|
||||
* intersection(ILT(types_1), ILT(types_2)) = ILT(types_1 union types_2)
|
||||
*
|
||||
* commonSuperType(ILT(types_1), ILT(types_2)) = ILT(types_1 intersect types_2)
|
||||
*/
|
||||
private fun findCommonSuperTypeOrIntersectionType(types: Collection<SimpleType>, mode: Mode): SimpleType? {
|
||||
if (types.isEmpty()) return null
|
||||
return types.reduce { left: SimpleType?, right -> fold(left, right, mode) }
|
||||
}
|
||||
|
||||
private fun fold(left: SimpleType?, right: SimpleType?, mode: Mode): SimpleType? {
|
||||
if (left == null || right == null) return null
|
||||
val leftConstructor = left.constructor
|
||||
val rightConstructor = right.constructor
|
||||
return when {
|
||||
leftConstructor is IntegerLiteralTypeConstructor && rightConstructor is IntegerLiteralTypeConstructor ->
|
||||
fold(leftConstructor, rightConstructor, mode)
|
||||
|
||||
leftConstructor is IntegerLiteralTypeConstructor -> fold(leftConstructor, right)
|
||||
rightConstructor is IntegerLiteralTypeConstructor -> fold(rightConstructor, left)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun fold(left: IntegerLiteralTypeConstructor, right: IntegerLiteralTypeConstructor, mode: Mode): SimpleType? {
|
||||
val possibleTypes = when (mode) {
|
||||
Mode.COMMON_SUPER_TYPE -> left.possibleTypes intersect right.possibleTypes
|
||||
Mode.INTERSECTION_TYPE -> left.possibleTypes union right.possibleTypes
|
||||
}
|
||||
val constructor = IntegerLiteralTypeConstructor(left.value, left.module, possibleTypes)
|
||||
return KotlinTypeFactory.integerLiteralType(Annotations.EMPTY, constructor, false)
|
||||
}
|
||||
|
||||
private fun fold(left: IntegerLiteralTypeConstructor, right: SimpleType): SimpleType? =
|
||||
if (right in left.possibleTypes) right else null
|
||||
|
||||
}
|
||||
|
||||
private val value: Long
|
||||
private val module: ModuleDescriptor
|
||||
val possibleTypes: Set<KotlinType>
|
||||
|
||||
constructor(value: Long, module: ModuleDescriptor, parameters: CompileTimeConstant.Parameters) {
|
||||
this.value = value
|
||||
this.module = module
|
||||
|
||||
val possibleTypes = mutableSetOf<KotlinType>()
|
||||
|
||||
fun checkBoundsAndAddPossibleType(value: Long, kotlinType: KotlinType) {
|
||||
if (value in kotlinType.minValue()..kotlinType.maxValue()) {
|
||||
possibleTypes.add(kotlinType)
|
||||
}
|
||||
}
|
||||
|
||||
fun addSignedPossibleTypes() {
|
||||
checkBoundsAndAddPossibleType(value, builtIns.intType)
|
||||
possibleTypes.add(builtIns.longType)
|
||||
checkBoundsAndAddPossibleType(value, builtIns.byteType)
|
||||
checkBoundsAndAddPossibleType(value, builtIns.shortType)
|
||||
}
|
||||
|
||||
fun addUnsignedPossibleTypes() {
|
||||
checkBoundsAndAddPossibleType(value, module.uIntType)
|
||||
possibleTypes.add(module.uLongType)
|
||||
checkBoundsAndAddPossibleType(value, module.uByteType)
|
||||
checkBoundsAndAddPossibleType(value, module.uShortType)
|
||||
}
|
||||
|
||||
val isUnsigned = parameters.isUnsignedNumberLiteral
|
||||
val isConvertable = parameters.isConvertableConstVal
|
||||
|
||||
if (isUnsigned || isConvertable) {
|
||||
assert(hasUnsignedTypesInModuleDependencies(module)) {
|
||||
"Unsigned types should be on classpath to create an unsigned type constructor"
|
||||
}
|
||||
}
|
||||
|
||||
when {
|
||||
isConvertable -> {
|
||||
addSignedPossibleTypes()
|
||||
addUnsignedPossibleTypes()
|
||||
}
|
||||
|
||||
isUnsigned -> addUnsignedPossibleTypes()
|
||||
|
||||
else -> addSignedPossibleTypes()
|
||||
}
|
||||
|
||||
this.possibleTypes = possibleTypes
|
||||
}
|
||||
|
||||
private constructor(value: Long, module: ModuleDescriptor, possibleTypes: Set<KotlinType>) {
|
||||
this.value = value
|
||||
this.module = module
|
||||
this.possibleTypes = possibleTypes
|
||||
}
|
||||
|
||||
private val type = KotlinTypeFactory.integerLiteralType(Annotations.EMPTY, this, false)
|
||||
|
||||
private fun isContainsOnlyUnsignedTypes(): Boolean = module.allSignedLiteralTypes.all { it !in possibleTypes }
|
||||
|
||||
private val supertypes: List<KotlinType> by lazy {
|
||||
val result = mutableListOf(builtIns.comparable.defaultType.replace(listOf(TypeProjectionImpl(Variance.IN_VARIANCE, type))))
|
||||
if (!isContainsOnlyUnsignedTypes()) {
|
||||
result += builtIns.numberType
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fun getApproximatedType(): KotlinType = when {
|
||||
builtIns.intType in possibleTypes -> builtIns.intType
|
||||
builtIns.longType in possibleTypes -> builtIns.longType
|
||||
builtIns.byteType in possibleTypes -> builtIns.byteType
|
||||
builtIns.shortType in possibleTypes -> builtIns.shortType
|
||||
|
||||
module.uIntType in possibleTypes -> module.uIntType
|
||||
module.uLongType in possibleTypes -> module.uLongType
|
||||
module.uByteType in possibleTypes -> module.uByteType
|
||||
module.uShortType in possibleTypes -> module.uShortType
|
||||
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
|
||||
|
||||
override fun getParameters(): List<TypeParameterDescriptor> = emptyList()
|
||||
|
||||
override fun getSupertypes(): Collection<KotlinType> = supertypes
|
||||
|
||||
override fun isFinal(): Boolean = true
|
||||
|
||||
override fun isDenotable(): Boolean = false
|
||||
|
||||
override fun getDeclarationDescriptor(): ClassifierDescriptor? = null
|
||||
|
||||
override fun getBuiltIns(): KotlinBuiltIns = module.builtIns
|
||||
|
||||
override fun toString(): String {
|
||||
return "IntegerLiteralType${valueToString()}"
|
||||
}
|
||||
|
||||
fun checkConstructor(constructor: TypeConstructor): Boolean = possibleTypes.any { it.constructor == constructor }
|
||||
|
||||
private fun valueToString(): String = "[${possibleTypes.joinToString(",") { it.toString() }}]"
|
||||
}
|
||||
+4
-31
@@ -67,10 +67,10 @@ class IntegerValueTypeConstructor(
|
||||
}
|
||||
|
||||
private fun addUnsignedSuperTypes() {
|
||||
checkBoundsAndAddSuperType(value, unsignedType(KotlinBuiltIns.FQ_NAMES.uInt))
|
||||
checkBoundsAndAddSuperType(value, unsignedType(KotlinBuiltIns.FQ_NAMES.uByte))
|
||||
checkBoundsAndAddSuperType(value, unsignedType(KotlinBuiltIns.FQ_NAMES.uShort))
|
||||
supertypes.add(unsignedType(KotlinBuiltIns.FQ_NAMES.uLong))
|
||||
checkBoundsAndAddSuperType(value, module.unsignedType(KotlinBuiltIns.FQ_NAMES.uInt))
|
||||
checkBoundsAndAddSuperType(value, module.unsignedType(KotlinBuiltIns.FQ_NAMES.uByte))
|
||||
checkBoundsAndAddSuperType(value, module.unsignedType(KotlinBuiltIns.FQ_NAMES.uShort))
|
||||
supertypes.add(module.unsignedType(KotlinBuiltIns.FQ_NAMES.uLong))
|
||||
}
|
||||
|
||||
private fun checkBoundsAndAddSuperType(value: Long, kotlinType: KotlinType) {
|
||||
@@ -79,8 +79,6 @@ class IntegerValueTypeConstructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun unsignedType(classId: ClassId): SimpleType = module.findClassAcrossModuleDependencies(classId)!!.defaultType
|
||||
|
||||
override fun getSupertypes(): Collection<KotlinType> = supertypes
|
||||
|
||||
override fun getParameters(): List<TypeParameterDescriptor> = emptyList()
|
||||
@@ -100,28 +98,3 @@ class IntegerValueTypeConstructor(
|
||||
override fun toString() = "IntegerValueType($value)"
|
||||
}
|
||||
|
||||
private fun KotlinType.minValue(): Long {
|
||||
if (UnsignedTypes.isUnsignedType(this)) return 0
|
||||
return when {
|
||||
KotlinBuiltIns.isByte(this) -> Byte.MIN_VALUE.toLong()
|
||||
KotlinBuiltIns.isShort(this) -> Short.MIN_VALUE.toLong()
|
||||
KotlinBuiltIns.isInt(this) -> Int.MIN_VALUE.toLong()
|
||||
else -> error("Can't get min value for type: $this")
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
private fun KotlinType.maxValue(): Long {
|
||||
return when {
|
||||
KotlinBuiltIns.isByte(this) -> Byte.MAX_VALUE.toLong()
|
||||
KotlinBuiltIns.isShort(this) -> Short.MAX_VALUE.toLong()
|
||||
KotlinBuiltIns.isInt(this) -> Int.MAX_VALUE.toLong()
|
||||
|
||||
KotlinBuiltIns.isUByte(this) -> UByte.MAX_VALUE.toLong()
|
||||
KotlinBuiltIns.isUShort(this) -> UShort.MAX_VALUE.toLong()
|
||||
KotlinBuiltIns.isUInt(this) -> UInt.MAX_VALUE.toLong()
|
||||
|
||||
else -> error("Can't get max value for type: $this")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.constants
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.UnsignedTypes
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
|
||||
internal fun KotlinType.minValue(): Long {
|
||||
if (UnsignedTypes.isUnsignedType(this)) return 0
|
||||
return when {
|
||||
KotlinBuiltIns.isByte(this) -> Byte.MIN_VALUE.toLong()
|
||||
KotlinBuiltIns.isShort(this) -> Short.MIN_VALUE.toLong()
|
||||
KotlinBuiltIns.isInt(this) -> Int.MIN_VALUE.toLong()
|
||||
else -> error("Can't get min value for type: $this")
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
internal fun KotlinType.maxValue(): Long {
|
||||
return when {
|
||||
KotlinBuiltIns.isByte(this) -> Byte.MAX_VALUE.toLong()
|
||||
KotlinBuiltIns.isShort(this) -> Short.MAX_VALUE.toLong()
|
||||
KotlinBuiltIns.isInt(this) -> Int.MAX_VALUE.toLong()
|
||||
|
||||
KotlinBuiltIns.isUByte(this) -> UByte.MAX_VALUE.toLong()
|
||||
KotlinBuiltIns.isUShort(this) -> UShort.MAX_VALUE.toLong()
|
||||
KotlinBuiltIns.isUInt(this) -> UInt.MAX_VALUE.toLong()
|
||||
|
||||
else -> error("Can't get max value for type: $this")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ModuleDescriptor.unsignedType(classId: ClassId): SimpleType = findClassAcrossModuleDependencies(classId)!!.defaultType
|
||||
|
||||
internal val ModuleDescriptor.uIntType: SimpleType
|
||||
get() = unsignedType(KotlinBuiltIns.FQ_NAMES.uInt)
|
||||
|
||||
internal val ModuleDescriptor.uLongType: SimpleType
|
||||
get() = unsignedType(KotlinBuiltIns.FQ_NAMES.uLong)
|
||||
|
||||
internal val ModuleDescriptor.uByteType: SimpleType
|
||||
get() = unsignedType(KotlinBuiltIns.FQ_NAMES.uByte)
|
||||
|
||||
internal val ModuleDescriptor.uShortType: SimpleType
|
||||
get() = unsignedType(KotlinBuiltIns.FQ_NAMES.uShort)
|
||||
|
||||
internal val ModuleDescriptor.allSignedLiteralTypes: Collection<KotlinType>
|
||||
get() = listOf(builtIns.intType, builtIns.longType, builtIns.byteType, builtIns.shortType)
|
||||
|
||||
internal val ModuleDescriptor.allUnsignedLiteralTypes: Collection<KotlinType>
|
||||
get() = if (hasUnsignedTypesInModuleDependencies(this)) {
|
||||
listOf(
|
||||
unsignedType(KotlinBuiltIns.FQ_NAMES.uInt), unsignedType(KotlinBuiltIns.FQ_NAMES.uLong),
|
||||
unsignedType(KotlinBuiltIns.FQ_NAMES.uByte), unsignedType(KotlinBuiltIns.FQ_NAMES.uShort)
|
||||
)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
@@ -20,7 +20,9 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||
|
||||
object KotlinTypeFactory {
|
||||
private fun computeMemberScope(constructor: TypeConstructor, arguments: List<TypeProjection>): MemberScope {
|
||||
@@ -95,6 +97,19 @@ object KotlinTypeFactory {
|
||||
if (lowerBound == upperBound) return lowerBound
|
||||
return FlexibleTypeImpl(lowerBound, upperBound)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun integerLiteralType(
|
||||
annotations: Annotations,
|
||||
constructor: IntegerLiteralTypeConstructor,
|
||||
nullable: Boolean
|
||||
): SimpleType = simpleTypeWithNonTrivialMemberScope(
|
||||
annotations,
|
||||
constructor,
|
||||
emptyList(),
|
||||
nullable,
|
||||
ErrorUtils.createErrorScope("Scope for integer literal type", true)
|
||||
)
|
||||
}
|
||||
|
||||
private class SimpleTypeImpl(
|
||||
@@ -150,4 +165,4 @@ private class NullableSimpleType(delegate: SimpleType) : DelegatingSimpleTypeImp
|
||||
private class NotNullSimpleType(delegate: SimpleType) : DelegatingSimpleTypeImpl(delegate) {
|
||||
override val isMarkedNullable: Boolean
|
||||
get() = false
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor;
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor;
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||
@@ -498,6 +499,30 @@ public class TypeUtils {
|
||||
return getDefaultPrimitiveNumberType(numberValueTypeConstructor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static KotlinType getPrimitiveNumberType(
|
||||
@NotNull IntegerLiteralTypeConstructor literalTypeConstructor,
|
||||
@NotNull KotlinType expectedType
|
||||
) {
|
||||
if (noExpectedType(expectedType) || KotlinTypeKt.isError(expectedType)) {
|
||||
return literalTypeConstructor.getApproximatedType();
|
||||
}
|
||||
|
||||
// If approximated type does not mathc expected type then expected type is very
|
||||
// specific type (e.g. Comparable<Byte>), so only one of possible types could match it
|
||||
KotlinType approximatedType = literalTypeConstructor.getApproximatedType();
|
||||
if (KotlinTypeChecker.DEFAULT.isSubtypeOf(approximatedType, expectedType)) {
|
||||
return approximatedType;
|
||||
}
|
||||
|
||||
for (KotlinType primitiveNumberType : literalTypeConstructor.getPossibleTypes()) {
|
||||
if (KotlinTypeChecker.DEFAULT.isSubtypeOf(primitiveNumberType, expectedType)) {
|
||||
return primitiveNumberType;
|
||||
}
|
||||
}
|
||||
return literalTypeConstructor.getApproximatedType();
|
||||
}
|
||||
|
||||
public static boolean isTypeParameter(@NotNull KotlinType type) {
|
||||
return getTypeParameterDescriptorOrNull(type) != null || type.getConstructor() instanceof NewTypeVariableConstructor;
|
||||
}
|
||||
|
||||
+10
-2
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.types.checker
|
||||
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker.transformToNewType
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
@@ -41,8 +42,15 @@ open class ClassicTypeCheckerContext(val errorTypeEqualsToAnything: Boolean, val
|
||||
return areEqualTypeConstructors(a, b)
|
||||
}
|
||||
|
||||
open fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean {
|
||||
return a == b
|
||||
open fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean = when {
|
||||
/*
|
||||
* For integer literal types we have special rules for constructor's equality,
|
||||
* so we have to check it manually
|
||||
* For example: Int in ILT.possibleTypes -> ILT == Int
|
||||
*/
|
||||
a is IntegerLiteralTypeConstructor -> a.checkConstructor(b)
|
||||
b is IntegerLiteralTypeConstructor -> b.checkConstructor(a)
|
||||
else -> a == b
|
||||
}
|
||||
|
||||
override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy.DoCustomTransform {
|
||||
|
||||
+13
-1
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.CapturedType
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.model.*
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
@@ -20,6 +21,17 @@ interface ClassicTypeSystemContext : TypeSystemContext {
|
||||
return this.isDenotable
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isIntegerLiteralTypeConstructor(): Boolean {
|
||||
require(this is TypeConstructor, this::errorMessage)
|
||||
return this is IntegerLiteralTypeConstructor
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.possibleIntegerTypes(): Collection<KotlinTypeMarker> {
|
||||
val typeConstructor = typeConstructor()
|
||||
require(typeConstructor is IntegerLiteralTypeConstructor, this::errorMessage)
|
||||
return typeConstructor.possibleTypes
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.withNullability(nullable: Boolean): SimpleTypeMarker {
|
||||
require(this is SimpleType, this::errorMessage)
|
||||
return this.makeNullableAsSpecified(nullable)
|
||||
@@ -221,7 +233,7 @@ interface ClassicTypeSystemContext : TypeSystemContext {
|
||||
require(this is SimpleType, this::errorMessage)
|
||||
return !isError &&
|
||||
constructor.declarationDescriptor !is TypeAliasDescriptor &&
|
||||
(constructor.declarationDescriptor != null || this is CapturedType || this is NewCapturedType || this is DefinitelyNotNullType)
|
||||
(constructor.declarationDescriptor != null || this is CapturedType || this is NewCapturedType || this is DefinitelyNotNullType || constructor is IntegerLiteralTypeConstructor)
|
||||
}
|
||||
|
||||
override fun KotlinTypeMarker.isNotNullNothing(): Boolean {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.types.checker
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import java.util.*
|
||||
import kotlin.collections.LinkedHashSet
|
||||
@@ -71,14 +72,14 @@ object TypeIntersector {
|
||||
assert(types.size > 1) {
|
||||
"Size should be at least 2, but it is ${types.size}"
|
||||
}
|
||||
|
||||
val inputTypes = ArrayList<SimpleType>()
|
||||
for (type in types) {
|
||||
if (type.constructor is IntersectionTypeConstructor) {
|
||||
inputTypes.addAll(type.constructor.supertypes.map {
|
||||
it.upperIfFlexible().let { if (type.isMarkedNullable) it.makeNullableAsSpecified(true) else it }
|
||||
})
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
inputTypes.add(type)
|
||||
}
|
||||
}
|
||||
@@ -106,25 +107,41 @@ object TypeIntersector {
|
||||
|
||||
// Any and Nothing should leave
|
||||
// Note that duplicates should be dropped because we have Set here.
|
||||
val filteredSuperAndEqualTypes = ArrayList(inputTypes)
|
||||
val iterator = filteredSuperAndEqualTypes.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val upper = iterator.next()
|
||||
val strictSupertypeOrHasEqual = filteredSuperAndEqualTypes.any { lower ->
|
||||
lower !== upper && (isStrictSupertype(lower, upper) || NewKotlinTypeChecker.equalTypes(lower, upper))
|
||||
}
|
||||
val errorMessage = { "This collections cannot be empty! input types: ${inputTypes.joinToString()}" }
|
||||
|
||||
if (strictSupertypeOrHasEqual) iterator.remove()
|
||||
}
|
||||
val filteredEqualTypes = filterTypes(inputTypes, ::isStrictSupertype)
|
||||
assert(filteredEqualTypes.isNotEmpty(), errorMessage)
|
||||
|
||||
assert(filteredSuperAndEqualTypes.isNotEmpty()) {
|
||||
"This collections cannot be empty! input types: ${inputTypes.joinToString()}"
|
||||
}
|
||||
IntegerLiteralTypeConstructor.findIntersectionType(filteredEqualTypes)?.let { return it }
|
||||
|
||||
val filteredSuperAndEqualTypes = filterTypes(filteredEqualTypes, NewKotlinTypeChecker::equalTypes)
|
||||
assert(filteredSuperAndEqualTypes.isNotEmpty(), errorMessage)
|
||||
|
||||
if (filteredSuperAndEqualTypes.size < 2) return filteredSuperAndEqualTypes.single()
|
||||
|
||||
val constructor = IntersectionTypeConstructor(inputTypes)
|
||||
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(Annotations.EMPTY, constructor, listOf(), false, constructor.createScopeForKotlinType())
|
||||
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
|
||||
Annotations.EMPTY,
|
||||
constructor,
|
||||
listOf(),
|
||||
false,
|
||||
constructor.createScopeForKotlinType()
|
||||
)
|
||||
}
|
||||
|
||||
private fun filterTypes(
|
||||
inputTypes: Collection<SimpleType>,
|
||||
predicate: (lower: SimpleType, upper: SimpleType) -> Boolean
|
||||
): Collection<SimpleType> {
|
||||
val filteredTypes = ArrayList(inputTypes)
|
||||
val iterator = filteredTypes.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val upper = iterator.next()
|
||||
val shouldFilter = filteredTypes.any { lower -> lower !== upper && predicate(lower, upper) }
|
||||
|
||||
if (shouldFilter) iterator.remove()
|
||||
}
|
||||
return filteredTypes
|
||||
}
|
||||
|
||||
private fun isStrictSupertype(subtype: KotlinType, supertype: KotlinType): Boolean {
|
||||
@@ -146,9 +163,9 @@ object TypeIntersector {
|
||||
// example: type parameter without not-null supertype
|
||||
UNKNOWN {
|
||||
override fun combine(nextType: UnwrappedType) =
|
||||
nextType.resultNullability.let {
|
||||
if (it == ACCEPT_NULL) this else it
|
||||
}
|
||||
nextType.resultNullability.let {
|
||||
if (it == ACCEPT_NULL) this else it
|
||||
}
|
||||
},
|
||||
NOT_NULL {
|
||||
override fun combine(nextType: UnwrappedType) = this
|
||||
|
||||
@@ -20,13 +20,15 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.CapturedType
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.CapturedTypeConstructorImpl
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.AbstractNullabilityChecker.hasNotNullSupertype
|
||||
import org.jetbrains.kotlin.types.AbstractNullabilityChecker.hasPathByNotMarkedNullableNodes
|
||||
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext.SupertypesPolicy
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
|
||||
object StrictEqualityTypeChecker {
|
||||
|
||||
@@ -192,3 +194,6 @@ val SimpleType.isSingleClassifierType: Boolean
|
||||
|
||||
val SimpleType.isIntersectionType: Boolean
|
||||
get() = constructor is IntersectionTypeConstructor
|
||||
|
||||
val SimpleType.isIntegerLiteralType: Boolean
|
||||
get() = constructor is IntegerLiteralTypeConstructor
|
||||
|
||||
@@ -180,6 +180,32 @@ object AbstractTypeChecker {
|
||||
return isSubtypeOfForSingleClassifierType(subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())
|
||||
}
|
||||
|
||||
private fun AbstractTypeCheckerContext.checkSubtypeForIntegerLiteralType(subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean? {
|
||||
if (!subType.isIntegerLiteralType() && !superType.isIntegerLiteralType()) return null
|
||||
|
||||
fun typeInIntegerLiteralType(integerLiteralType: SimpleTypeMarker, type: SimpleTypeMarker): Boolean =
|
||||
integerLiteralType.possibleIntegerTypes().any { it.typeConstructor() == type.typeConstructor() }
|
||||
|
||||
when {
|
||||
subType.isIntegerLiteralType() && superType.isIntegerLiteralType() -> {
|
||||
return true
|
||||
}
|
||||
|
||||
subType.isIntegerLiteralType() -> {
|
||||
if (typeInIntegerLiteralType(subType, superType)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
superType.isIntegerLiteralType() -> {
|
||||
if (typeInIntegerLiteralType(superType, subType)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun AbstractTypeCheckerContext.hasNothingSupertype(type: SimpleTypeMarker) = // todo add tests
|
||||
anySupertype(type, { it.typeConstructor().isNothingConstructor() }) {
|
||||
if (it.isClassType()) {
|
||||
@@ -199,6 +225,11 @@ object AbstractTypeChecker {
|
||||
|
||||
if (!AbstractNullabilityChecker.isPossibleSubtype(this, subType, superType)) return false
|
||||
|
||||
checkSubtypeForIntegerLiteralType(subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())?.let {
|
||||
addSubtypeConstraint(subType, superType)
|
||||
return it
|
||||
}
|
||||
|
||||
val superConstructor = superType.typeConstructor()
|
||||
|
||||
if (isEqualTypeConstructors(subType.typeConstructor(), superConstructor) && superConstructor.parametersCount() == 0) return true
|
||||
@@ -397,7 +428,7 @@ object AbstractTypeChecker {
|
||||
}
|
||||
|
||||
// i.e. superType is not a classType
|
||||
if (!constructor.isClassTypeConstructor()) {
|
||||
if (!constructor.isClassTypeConstructor() && !constructor.isIntegerLiteralTypeConstructor()) {
|
||||
return collectAllSupertypesWithGivenTypeConstructor(baseType, constructor)
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ interface TypeSystemContext : TypeSystemOptimizationContext {
|
||||
fun TypeConstructorMarker.supertypes(): Collection<KotlinTypeMarker>
|
||||
fun TypeConstructorMarker.isIntersection(): Boolean
|
||||
fun TypeConstructorMarker.isClassTypeConstructor(): Boolean
|
||||
fun TypeConstructorMarker.isIntegerLiteralTypeConstructor(): Boolean
|
||||
|
||||
fun TypeParameterMarker.getVariance(): TypeVariance
|
||||
fun TypeParameterMarker.upperBoundCount(): Int
|
||||
@@ -105,6 +106,10 @@ interface TypeSystemContext : TypeSystemOptimizationContext {
|
||||
|
||||
fun SimpleTypeMarker.isClassType(): Boolean = typeConstructor().isClassTypeConstructor()
|
||||
|
||||
fun SimpleTypeMarker.isIntegerLiteralType(): Boolean = typeConstructor().isIntegerLiteralTypeConstructor()
|
||||
|
||||
fun SimpleTypeMarker.possibleIntegerTypes(): Collection<KotlinTypeMarker>
|
||||
|
||||
fun TypeConstructorMarker.isCommonFinalClassConstructor(): Boolean
|
||||
|
||||
fun captureFromArguments(
|
||||
|
||||
+5
-4
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user