diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt index f413e1905f7..8d5846f060e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt @@ -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 { + TODO("not implemented") + } + override fun KotlinTypeMarker.asSimpleType(): SimpleTypeMarker? { assert(this is ConeKotlinType) return when (this) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.kt index 09991039a85..64db37949b8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.kt @@ -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( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java index f48f7db6aac..175c057fd0f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java @@ -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; } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt index d47939eab21..cf8fa43cf2b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt @@ -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( 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( 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) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt index d1a20a7e046..3b1fda59549 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt @@ -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 diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt index 976aadbd11f..2d20545fb47 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt @@ -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) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt index cdc5af79c7e..6548ddc9b2e 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt @@ -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 diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceUtils.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceUtils.kt index 0c5baeca6d7..e84bf68fc13 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceUtils.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceUtils.kt @@ -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 } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt index d0c5ba94164..62972a7f284 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt @@ -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 Array.intersect(other: Iterable) { @@ -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() - val numberSupertypes = arrayListOf() - 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 } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeCheckerContextForConstraintSystem.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeCheckerContextForConstraintSystem.kt index 29030b62832..888dc27319e 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeCheckerContextForConstraintSystem.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/TypeCheckerContextForConstraintSystem.kt @@ -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" diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt index bcaa8db7879..029b9180d0f 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt @@ -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 } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt b/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt index 7dd176f86c7..e5cda6677f6 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt @@ -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 } diff --git a/compiler/testData/diagnostics/tests/resolve/specialConstructions/constantsInIf.kt b/compiler/testData/diagnostics/tests/resolve/specialConstructions/constantsInIf.kt index 4c04b0a633b..a25eabd0684 100644 --- a/compiler/testData/diagnostics/tests/resolve/specialConstructions/constantsInIf.kt +++ b/compiler/testData/diagnostics/tests/resolve/specialConstructions/constantsInIf.kt @@ -2,13 +2,13 @@ // !DIAGNOSTICS: -USELESS_ELVIS fun test() { - bar(if (true) { + bar(if (true) { 1 } else { 2 }) - bar(1 ?: 2) + bar(1 ?: 2) } fun bar(s: String) = s \ No newline at end of file diff --git a/compiler/tests-spec/testData/diagnostics/linked/type-inference/smart-casts/smart-casts-sources/p-4/pos/1.1.kt b/compiler/tests-spec/testData/diagnostics/linked/type-inference/smart-casts/smart-casts-sources/p-4/pos/1.1.kt index a54cd4ca25f..7f90e659cfa 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/type-inference/smart-casts/smart-casts-sources/p-4/pos/1.1.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/type-inference/smart-casts/smart-casts-sources/p-4/pos/1.1.kt @@ -222,7 +222,7 @@ fun case_16() { } // TESTCASE NUMBER: 17 -val case_17 = & java.io.Serializable}")!>if (nullableIntProperty == null) 0 else { +val case_17 = & java.io.Serializable}")!>if (nullableIntProperty == null) 0 else { nullableIntProperty nullableIntProperty.equals(nullableIntProperty) } diff --git a/compiler/tests-spec/testData/diagnostics/linked/type-inference/smart-casts/smart-casts-sources/p-4/pos/1.11.kt b/compiler/tests-spec/testData/diagnostics/linked/type-inference/smart-casts/smart-casts-sources/p-4/pos/1.11.kt index 804c7ed623e..7bfbc5199bd 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/type-inference/smart-casts/smart-casts-sources/p-4/pos/1.11.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/type-inference/smart-casts/smart-casts-sources/p-4/pos/1.11.kt @@ -24,8 +24,8 @@ fun case_1() { val x = case_1(Out(10), Inv(0.1)) if (x != null) { - & Number} & {Comparable<{Byte & Double & Int & Long & Short}> & Number}?")!>x - & Number} & {Comparable<{Byte & Double & Int & Long & Short}> & Number}?"), DEBUG_INFO_SMARTCAST!>x.equals(x) + & Number} & {Comparable<{Double & Int}> & Number}?")!>x + & Number} & {Comparable<{Double & Int}> & Number}?"), DEBUG_INFO_SMARTCAST!>x.equals(x) } } diff --git a/compiler/tests-spec/testData/diagnostics/linked/type-inference/smart-casts/smart-casts-sources/p-4/pos/1.6.kt b/compiler/tests-spec/testData/diagnostics/linked/type-inference/smart-casts/smart-casts-sources/p-4/pos/1.6.kt index 1dc2b45dcac..57b696792c2 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/type-inference/smart-casts/smart-casts-sources/p-4/pos/1.6.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/type-inference/smart-casts/smart-casts-sources/p-4/pos/1.6.kt @@ -636,7 +636,7 @@ fun case_51() { } // TESTCASE NUMBER: 52 -val case_52 = & java.io.Serializable}")!>if (nullableIntProperty !== nullableNothingProperty && nullableNothingProperty != nullableIntProperty) 0 else { +val case_52 = & java.io.Serializable}")!>if (nullableIntProperty !== nullableNothingProperty && nullableNothingProperty != nullableIntProperty) 0 else { nullableIntProperty nullableIntProperty.equals(nullableIntProperty) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index 2a115dca751..f4924eb8e5e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -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); diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstant.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstant.kt index bc8ad78b081..c1058a4238d 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstant.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/CompileTimeConstant.kt @@ -91,9 +91,10 @@ class TypedCompileTimeConstant( 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 { 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 { 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() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerLiteralTypeConstructor.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerLiteralTypeConstructor.kt new file mode 100644 index 00000000000..5430dde9293 --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerLiteralTypeConstructor.kt @@ -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? = + findCommonSuperTypeOrIntersectionType(types, Companion.Mode.COMMON_SUPER_TYPE) + + fun findIntersectionType(types: Collection): 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, 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 + + constructor(value: Long, module: ModuleDescriptor, parameters: CompileTimeConstant.Parameters) { + this.value = value + this.module = module + + val possibleTypes = mutableSetOf() + + 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) { + 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 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 = emptyList() + + override fun getSupertypes(): Collection = 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() }}]" +} \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueTypeConstructor.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueTypeConstructor.kt index e028373bbcf..8add786a3ae 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueTypeConstructor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/IntegerValueTypeConstructor.kt @@ -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 = supertypes override fun getParameters(): List = 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") - } -} - diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/PrimitiveTypeUtil.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/PrimitiveTypeUtil.kt new file mode 100644 index 00000000000..52dc570e477 --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/PrimitiveTypeUtil.kt @@ -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 + get() = listOf(builtIns.intType, builtIns.longType, builtIns.byteType, builtIns.shortType) + +internal val ModuleDescriptor.allUnsignedLiteralTypes: Collection + 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() + } \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/KotlinTypeFactory.kt b/core/descriptors/src/org/jetbrains/kotlin/types/KotlinTypeFactory.kt index e1eed94718f..18f20bd57c0 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/KotlinTypeFactory.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/KotlinTypeFactory.kt @@ -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): 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 -} +} \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java index bcd26cc525e..ab62cbb379b 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java @@ -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), 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; } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeCheckerContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeCheckerContext.kt index 769cbf73e67..357a6635fb1 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeCheckerContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeCheckerContext.kt @@ -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 { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt index 89e530ba668..7a97acf3995 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -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 { + 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 { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/IntersectionType.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/IntersectionType.kt index 0195eb45f01..22c5f5340e6 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/IntersectionType.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/IntersectionType.kt @@ -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() 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, + predicate: (lower: SimpleType, upper: SimpleType) -> Boolean + ): Collection { + 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 diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt index f5fffed6092..107a3d31048 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt @@ -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 diff --git a/core/type-system/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt b/core/type-system/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt index 622862ce8d0..58dac4c1b07 100644 --- a/core/type-system/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt +++ b/core/type-system/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt @@ -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) } diff --git a/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt b/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt index 291be31f87c..ad0a07c9a98 100644 --- a/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt +++ b/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt @@ -81,6 +81,7 @@ interface TypeSystemContext : TypeSystemOptimizationContext { fun TypeConstructorMarker.supertypes(): Collection 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 + fun TypeConstructorMarker.isCommonFinalClassConstructor(): Boolean fun captureFromArguments( diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt index 6c7fe2c582e..94c9d4e897c 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt @@ -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 } } }