From 3909e3c54ca888344d2bae1b5d6bdf6bd5f36471 Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Thu, 4 Feb 2021 05:14:29 +0300 Subject: [PATCH] Decouple TypeCheckerContext and TypeSystemContext --- .../fir/analysis/checkers/FirHelpers.kt | 4 +- .../FirUpperBoundViolatedChecker.kt | 30 +- .../fir/session/ComponentsContainers.kt | 5 +- .../generators/CallAndReferenceGenerator.kt | 2 +- .../kotlin/fir/java/FirJavaElementFinder.kt | 5 +- .../org/jetbrains/kotlin/fir/SessionUtils.kt | 8 +- .../kotlin/fir/resolve/calls/Arguments.kt | 16 +- .../resolve/inference/InferenceComponents.kt | 6 +- .../FirExpressionsResolveTransformer.kt | 3 +- .../scopes/impl/FirTypeIntersectionScope.kt | 7 +- .../kotlin/fir/types/ConeInferenceContext.kt | 12 +- .../kotlin/fir/types/ConeTypeContext.kt | 41 +-- .../types/FirCorrespondingSupertypesCache.kt | 21 +- .../backend/jvm/codegen/ExpressionCodegen.kt | 2 +- .../backend/jvm/codegen/IrTypeMapper.kt | 2 +- .../jvm/lower/CollectionStubMethodLowering.kt | 8 +- .../kotlin/ir/overrides/IrOverridingUtil.kt | 16 +- .../kotlin/ir/types/IrTypeCheckerContext.kt | 32 +- .../kotlin/ir/types/IrTypeCheckerUtils.kt | 4 +- .../kotlin/ir/types/IrTypeSystemContext.kt | 37 +++ .../jetbrains/kotlin/ir/types/IrTypeUtils.kt | 6 +- .../calls/NewCommonSuperTypeCalculator.kt | 4 +- ...ctTypeCheckerContextForConstraintSystem.kt | 152 +++++---- .../components/ConstraintInjector.kt | 10 +- .../multiplatform/ExpectedActualResolver.kt | 17 +- .../kotlin/types/AbstractTypeChecker.kt | 307 ++++++++++-------- .../kotlin/resolve/OverridingUtil.java | 40 +-- .../OverridingUtilTypeSystemContext.kt | 48 +++ .../checker/ClassicTypeCheckerContext.kt | 31 +- .../types/checker/ClassicTypeSystemContext.kt | 6 +- .../KtFirAnalysisSessionComponent.kt | 3 +- .../KotlinIntroduceVariableHandler.kt | 14 +- 32 files changed, 483 insertions(+), 416 deletions(-) create mode 100644 core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtilTypeSystemContext.kt diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt index f2989f19726..7cbb4857ddc 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt @@ -31,7 +31,7 @@ import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol -import org.jetbrains.kotlin.fir.typeCheckerContext +import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtTokens @@ -317,4 +317,4 @@ val FirFunctionCall.isIterator internal fun throwableClassLikeType(session: FirSession) = session.builtinTypes.throwableType.type fun ConeKotlinType.isSubtypeOfThrowable(session: FirSession) = - throwableClassLikeType(session).isSupertypeOf(session.typeCheckerContext, this.fullyExpandedType(session)) + throwableClassLikeType(session).isSupertypeOf(session.typeContext, this.fullyExpandedType(session)) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedChecker.kt index d469fdeaf28..e72a8d6f142 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedChecker.kt @@ -22,7 +22,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.types.AbstractTypeChecker -import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.utils.addToStdlib.min import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -63,18 +62,13 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() { parameterPairs.mapValues { it.value.coneType } ) - val typeCheckerContext = context.session.typeContext.newBaseTypeCheckerContext( - errorTypesEqualToAnything = false, - stubTypesEqualToAnything = false - ) - parameterPairs.forEach { (proto, actual) -> if (actual.source == null) { // inferred types don't report INAPPLICABLE_CANDIDATE for type aliases! return@forEach } - if (!satisfiesBounds(proto, actual.coneType, substitutor, typeCheckerContext)) { + if (!satisfiesBounds(proto, actual.coneType, substitutor, context.session.typeContext)) { reporter.reportOn(actual.source, proto, actual.coneType, context) return } @@ -82,7 +76,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() { // we must analyze nested things like // S, T>() actual.coneType.safeAs()?.let { - val errorOccurred = analyzeTypeParameters(it, context, reporter, typeCheckerContext, actual.source) + val errorOccurred = analyzeTypeParameters(it, context, reporter, context.session.typeContext, actual.source) if (errorOccurred) { return @@ -99,14 +93,14 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() { // typealias A = B> // val a = A() when (calleeFir) { - is FirConstructor -> analyzeConstructorCall(expression, substitutor, typeCheckerContext, reporter, context) + is FirConstructor -> analyzeConstructorCall(expression, substitutor, context.session.typeContext, reporter, context) } } private fun analyzeConstructorCall( functionCall: FirQualifiedAccessExpression, callSiteSubstitutor: ConeSubstitutor, - typeCheckerContext: AbstractTypeCheckerContext, + typeSystemContext: ConeTypeContext, reporter: DiagnosticReporter, context: CheckerContext ) { @@ -157,7 +151,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() { constructorsParameterPairs.forEach { (proto, actual) -> // just in case - var intersection = typeCheckerContext.intersectTypes( + var intersection = typeSystemContext.intersectTypes( proto.fir.bounds.map { it.coneType } ).safeAs() ?: return@forEach @@ -167,7 +161,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() { // substitute Int for G from // the example above val target = callSiteSubstitutor.substituteOrSelf(actual) - val satisfiesBounds = AbstractTypeChecker.isSubtypeOf(typeCheckerContext, target, intersection) + val satisfiesBounds = AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, intersection) if (!satisfiesBounds) { reporter.reportOn(functionCall.source, proto, actual, context) @@ -187,7 +181,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() { type: ConeClassLikeType, context: CheckerContext, reporter: DiagnosticReporter, - typeCheckerContext: AbstractTypeCheckerContext, + typeSystemContext: ConeTypeContext, reportTarget: FirSourceElement? ): Boolean { val prototypeClass = type.lookupTag.toSymbol(context.session) @@ -218,13 +212,13 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() { ) parameterPairs.forEach { (proto, actual) -> - if (!satisfiesBounds(proto, actual.type, substitutor, typeCheckerContext)) { + if (!satisfiesBounds(proto, actual.type, substitutor, typeSystemContext)) { // should report on the parameter instead! reporter.reportOn(reportTarget, proto, actual, context) return true } - val errorOccurred = analyzeTypeParameters(actual, context, reporter, typeCheckerContext, reportTarget) + val errorOccurred = analyzeTypeParameters(actual, context, reporter, typeSystemContext, reportTarget) if (errorOccurred) { return true @@ -242,14 +236,14 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() { prototypeSymbol: FirTypeParameterSymbol, target: ConeKotlinType, substitutor: ConeSubstitutor, - typeCheckerContext: AbstractTypeCheckerContext + typeSystemContext: ConeTypeContext ): Boolean { - var intersection = typeCheckerContext.intersectTypes( + var intersection = typeSystemContext.intersectTypes( prototypeSymbol.fir.bounds.map { it.coneType } ).safeAs() ?: return true intersection = substitutor.substituteOrSelf(intersection) - return AbstractTypeChecker.isSubtypeOf(typeCheckerContext, target, intersection) + return AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, intersection, stubTypesEqualToAnything = false) } private fun DiagnosticReporter.reportOn( diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt index 104321cbf0f..b8d86129a5c 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt @@ -30,6 +30,9 @@ import org.jetbrains.kotlin.fir.types.FirCorrespondingSupertypesCache @OptIn(SessionConfiguration::class) fun FirSession.registerCommonComponents(languageVersionSettings: LanguageVersionSettings) { + register(FirLanguageSettingsComponent::class, FirLanguageSettingsComponent(languageVersionSettings)) + register(InferenceComponents::class, InferenceComponents(this)) + register(FirDeclaredMemberScopeProvider::class, FirDeclaredMemberScopeProvider()) register(FirCorrespondingSupertypesCache::class, FirCorrespondingSupertypesCache(this)) register(FirDefaultParametersResolver::class, FirDefaultParametersResolver()) @@ -38,8 +41,6 @@ fun FirSession.registerCommonComponents(languageVersionSettings: LanguageVersion register(FirRegisteredPluginAnnotations::class, FirRegisteredPluginAnnotations.create(this)) register(FirPredicateBasedProvider::class, FirPredicateBasedProvider.create(this)) register(GeneratedClassIndex::class, GeneratedClassIndex.create()) - register(FirLanguageSettingsComponent::class, FirLanguageSettingsComponent(languageVersionSettings)) - register(InferenceComponents::class, InferenceComponents(this)) } @OptIn(SessionConfiguration::class) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt index 4e98df5a288..9bebfd9667d 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt @@ -636,7 +636,7 @@ class CallAndReferenceGenerator( // If the type of the argument is already an explicitly subtype of the type of the parameter, we don't need SAM conversion. if (argument.typeRef !is FirResolvedTypeRef || AbstractTypeChecker.isSubtypeOf( - session.inferenceComponents.ctx, + session.inferenceComponents.ctx.newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true), argument.typeRef.coneType, parameter.returnTypeRef.coneType, isFromNullabilityConstraint = true diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt index 3dce60664e4..207eee23502 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.transformers.resolveSupertypesInTheAir import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName @@ -241,9 +242,7 @@ private fun ConeClassLikeType.mapToCanonicalNoExpansionString(session: FirSessio } + "[]" } - val context = ConeTypeCheckerContext(isErrorTypeEqualsToAnything = false, isStubTypeEqualsToAnything = true, session = session) - - with(context) { + with(session.typeContext) { val typeConstructor = typeConstructor() typeConstructor.getPrimitiveType()?.let { return JvmPrimitiveType.get(it).wrapperFqName.asString() } typeConstructor.getPrimitiveArrayType()?.let { return JvmPrimitiveType.get(it).javaKeywordName + "[]" } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/SessionUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/SessionUtils.kt index cf587bfbd09..f90d401816d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/SessionUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/SessionUtils.kt @@ -6,21 +6,19 @@ package org.jetbrains.kotlin.fir import org.jetbrains.kotlin.descriptors.Visibility -import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction +import org.jetbrains.kotlin.fir.declarations.visibility import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope import org.jetbrains.kotlin.fir.types.ConeInferenceContext -import org.jetbrains.kotlin.fir.types.ConeTypeCheckerContext val FirSession.typeContext: ConeInferenceContext get() = inferenceComponents.ctx -val FirSession.typeCheckerContext: ConeTypeCheckerContext - get() = inferenceComponents.ctx - /** * Returns the list of functions that overridden by given */ diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt index 172cbb4cae8..77bdd3df6e9 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt @@ -17,7 +17,6 @@ import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolvedTypeDeclarati import org.jetbrains.kotlin.fir.returnExpressions import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.StandardClassIds -import org.jetbrains.kotlin.fir.typeCheckerContext import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.name.ClassId @@ -26,6 +25,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompat import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.model.CaptureStatus +import org.jetbrains.kotlin.types.model.TypeSystemCommonSuperTypesContext import org.jetbrains.kotlin.utils.addToStdlib.runIf fun Candidate.resolveArgumentExpression( @@ -416,7 +416,10 @@ fun FirExpression.isFunctional( val returnTypeCompatible = expectedReturnType is ConeTypeParameterType || AbstractTypeChecker.isSubtypeOf( - session.inferenceComponents.ctx, + session.inferenceComponents.ctx.newBaseTypeCheckerContext( + errorTypesEqualToAnything = false, + stubTypesEqualToAnything = true + ), invokeSymbol.fir.returnTypeRef.coneType, expectedReturnType, isFromNullabilityConstraint = false @@ -433,7 +436,10 @@ fun FirExpression.isFunctional( val expectedParameterType = expectedParameter!!.lowerBoundIfFlexible() expectedParameterType is ConeTypeParameterType || AbstractTypeChecker.isSubtypeOf( - session.inferenceComponents.ctx, + session.inferenceComponents.ctx.newBaseTypeCheckerContext( + errorTypesEqualToAnything = false, + stubTypesEqualToAnything = true + ), invokeParameter.returnTypeRef.coneType, expectedParameterType, isFromNullabilityConstraint = false @@ -488,7 +494,7 @@ internal fun captureFromTypeParameterUpperBoundIfNeeded( val simplifiedArgumentType = argumentType.lowerBoundIfFlexible() as? ConeTypeParameterType ?: return argumentType val typeParameter = simplifiedArgumentType.lookupTag.typeParameterSymbol.fir - val context = session.typeCheckerContext + val context = session.typeContext val chosenSupertype = typeParameter.bounds.map { it.coneType } .singleOrNull { it.hasSupertypeWithGivenClassId(expectedTypeClassId, context) } ?: return argumentType @@ -501,7 +507,7 @@ internal fun captureFromTypeParameterUpperBoundIfNeeded( } } -private fun ConeKotlinType.hasSupertypeWithGivenClassId(classId: ClassId, context: ConeTypeCheckerContext): Boolean { +private fun ConeKotlinType.hasSupertypeWithGivenClassId(classId: ClassId, context: TypeSystemCommonSuperTypesContext): Boolean { return with(context) { anySuperTypeConstructor { it is ConeClassLikeLookupTag && it.classId == classId diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceComponents.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceComponents.kt index ec132d66375..c29ed2205d1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceComponents.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceComponents.kt @@ -7,14 +7,16 @@ package org.jetbrains.kotlin.fir.resolve.inference import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.types.ConeInferenceContext -import org.jetbrains.kotlin.fir.types.ConeTypeCheckerContext import org.jetbrains.kotlin.resolve.calls.inference.components.* import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl import org.jetbrains.kotlin.types.AbstractTypeApproximator @NoMutableState class InferenceComponents(val session: FirSession) : FirSessionComponent { - val ctx: ConeTypeCheckerContext = ConeTypeCheckerContext(isErrorTypeEqualsToAnything = false, isStubTypeEqualsToAnything = true, session) + val ctx: ConeInferenceContext = object : ConeInferenceContext { + override val session: FirSession + get() = this@InferenceComponents.session + } val approximator: AbstractTypeApproximator = object : AbstractTypeApproximator(ctx) {} val trivialConstraintTypeInferenceOracle = TrivialConstraintTypeInferenceOracle.create(ctx) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index 6db37b3e083..61f458b8844 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -496,7 +496,8 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform if (baseType !is ConeClassLikeType) return this val baseFirClass = baseType.lookupTag.toSymbol(session)?.fir ?: return this - val newArguments = if (AbstractTypeChecker.isSubtypeOfClass(session.typeCheckerContext, baseType.lookupTag, type.lookupTag)) { + val newArguments = if (AbstractTypeChecker.isSubtypeOfClass( + session.typeContext.newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true), baseType.lookupTag, type.lookupTag)) { // If actual type of declaration is more specific than bare type then we should just find // corresponding supertype with proper arguments with(session.typeContext) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScope.kt index 675553f33ce..0f76eff3432 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScope.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.impl.* +import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.AbstractTypeChecker @@ -33,7 +34,7 @@ class FirTypeIntersectionScope private constructor( private val absentProperties: MutableSet = mutableSetOf() private val absentClassifiers: MutableSet = mutableSetOf() - private val typeContext = ConeTypeCheckerContext(isErrorTypeEqualsToAnything = false, isStubTypeEqualsToAnything = false, session) + private val typeCheckerContext = session.typeContext.newBaseTypeCheckerContext(false, false) private val overriddenSymbols: MutableMap, Collection>>> = mutableMapOf() @@ -357,7 +358,7 @@ class FirTypeIntersectionScope private constructor( require(bFir is FirProperty) { "b is " + b.javaClass } // TODO: if (!OverridingUtil.isAccessorMoreSpecific(pa.getSetter(), pb.getSetter())) return false return if (aFir.isVar && bFir.isVar) { - AbstractTypeChecker.equalTypes(typeContext as AbstractTypeCheckerContext, aReturnType, bReturnType) + AbstractTypeChecker.equalTypes(typeCheckerContext as AbstractTypeCheckerContext, aReturnType, bReturnType) } else { // both vals or var vs val: val can't be more specific then var !(!aFir.isVar && bFir.isVar) && isTypeMoreSpecific(aReturnType, bReturnType) } @@ -366,7 +367,7 @@ class FirTypeIntersectionScope private constructor( } private fun isTypeMoreSpecific(a: ConeKotlinType, b: ConeKotlinType): Boolean = - AbstractTypeChecker.isSubtypeOf(typeContext as AbstractTypeCheckerContext, a, b) + AbstractTypeChecker.isSubtypeOf(typeCheckerContext as AbstractTypeCheckerContext, a, b) private fun > findMemberWithMaxVisibility(members: Collection>): MemberWithBaseScope { assert(members.isNotEmpty()) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt index 18d9d81ec8b..4c2c0a9c5c3 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt @@ -97,8 +97,8 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo override fun newBaseTypeCheckerContext( errorTypesEqualToAnything: Boolean, stubTypesEqualToAnything: Boolean - ): AbstractTypeCheckerContext = - ConeTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything, session) + ): ConeTypeCheckerContext = + ConeTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything, this) override fun KotlinTypeMarker.canHaveUndefinedNullability(): Boolean { require(this is ConeKotlinType) @@ -483,4 +483,12 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo return session.symbolProvider.getClassLikeSymbolByFqName(classId)?.toLookupTag() ?: error("Can't find KFunction type") } + + override fun createTypeWithAlternativeForIntersectionResult( + firstCandidate: KotlinTypeMarker, + secondCandidate: KotlinTypeMarker + ): KotlinTypeMarker { + // TODO + return firstCandidate + } } 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 91df2893bea..e424d75d3ab 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 @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.AbstractTypeCheckerContext +import org.jetbrains.kotlin.types.AbstractTypeCheckerContext.SupertypesPolicy.* import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext import org.jetbrains.kotlin.types.model.* @@ -540,10 +541,13 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty class ConeTypeCheckerContext( override val isErrorTypeEqualsToAnything: Boolean, override val isStubTypeEqualsToAnything: Boolean, - override val session: FirSession -) : AbstractTypeCheckerContext(), ConeInferenceContext { - override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy { - if (type.argumentsCount() == 0) return SupertypesPolicy.LowerIfFlexible + override val typeSystemContext: ConeInferenceContext +) : AbstractTypeCheckerContext() { + + val session: FirSession = typeSystemContext.session + + override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy = with(typeSystemContext) { + if (type.argumentsCount() == 0) return LowerIfFlexible require(type is ConeKotlinType) val declaration = when (type) { is ConeClassLikeType -> type.lookupTag.toSymbol(session)?.firUnsafe>() @@ -560,7 +564,7 @@ class ConeTypeCheckerContext( } else { ConeSubstitutor.Empty } - return object : SupertypesPolicy.DoCustomTransform() { + return object : DoCustomTransform() { override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker): SimpleTypeMarker { val lowerBound = type.lowerBoundIfFlexible() require(lowerBound is ConeKotlinType) @@ -570,35 +574,10 @@ class ConeTypeCheckerContext( } } - override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean { - return c1 == c2 - } - - override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker { - return super.prepareType(type) - } - override fun refineType(type: KotlinTypeMarker): KotlinTypeMarker { - return prepareType(type) + return typeSystemContext.prepareType(type) } override val KotlinTypeMarker.isAllowedTypeVariable: Boolean get() = this is ConeKotlinType && this is ConeTypeVariableType - - override fun newBaseTypeCheckerContext( - errorTypesEqualToAnything: Boolean, - stubTypesEqualToAnything: Boolean - ): AbstractTypeCheckerContext = - if (this.isErrorTypeEqualsToAnything == errorTypesEqualToAnything && this.isStubTypeEqualsToAnything == stubTypesEqualToAnything) - this - else - ConeTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything, session) - - override fun createTypeWithAlternativeForIntersectionResult( - firstCandidate: KotlinTypeMarker, - secondCandidate: KotlinTypeMarker - ): KotlinTypeMarker { - // TODO - return firstCandidate - } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/FirCorrespondingSupertypesCache.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/FirCorrespondingSupertypesCache.kt index 8422957eeeb..51d12a4428a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/FirCorrespondingSupertypesCache.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/FirCorrespondingSupertypesCache.kt @@ -13,10 +13,12 @@ import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRefsOwner import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol +import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.types.model.CaptureStatus import org.jetbrains.kotlin.types.model.SimpleTypeMarker import org.jetbrains.kotlin.types.model.TypeConstructorMarker +import org.jetbrains.kotlin.types.model.TypeSystemContext @ThreadSafeMutableState class FirCorrespondingSupertypesCache(private val session: FirSession) : FirSessionComponent { @@ -28,9 +30,13 @@ class FirCorrespondingSupertypesCache(private val session: FirSession) : FirSess ): List? { if (type !is ConeClassLikeType || supertypeConstructor !is ConeClassLikeLookupTag) return null - val context = ConeTypeCheckerContext(isErrorTypeEqualsToAnything = false, isStubTypeEqualsToAnything = true, session = session) + val context = session.typeContext.newBaseTypeCheckerContext( + errorTypesEqualToAnything = false, + stubTypesEqualToAnything = true + ) + val lookupTag = type.lookupTag - if (lookupTag == supertypeConstructor) return listOf(captureType(type, context)) + if (lookupTag == supertypeConstructor) return listOf(captureType(type, context.typeSystemContext)) if (lookupTag !in cache) { cache[lookupTag] = computeSupertypesMap(lookupTag, context) } @@ -38,15 +44,15 @@ class FirCorrespondingSupertypesCache(private val session: FirSession) : FirSess val resultTypes = cache[lookupTag]?.getOrDefault(supertypeConstructor, emptyList()) ?: return null if (type.typeArguments.isEmpty()) return resultTypes - val capturedType = captureType(type, context) + val capturedType = captureType(type, context.typeSystemContext) val substitutionSupertypePolicy = context.substitutionSupertypePolicy(capturedType) return resultTypes.map { substitutionSupertypePolicy.transformType(context, it) as ConeClassLikeType } } - private fun captureType(type: ConeClassLikeType, context: ConeTypeCheckerContext): ConeClassLikeType = - (context.captureFromArguments(type, CaptureStatus.FOR_SUBTYPING) ?: type) as ConeClassLikeType + private fun captureType(type: ConeClassLikeType, typeSystemContext: ConeTypeContext): ConeClassLikeType = + (typeSystemContext.captureFromArguments(type, CaptureStatus.FOR_SUBTYPING) ?: type) as ConeClassLikeType private fun computeSupertypesMap( subtypeLookupTag: ConeClassLikeLookupTag, @@ -82,12 +88,13 @@ class FirCorrespondingSupertypesCache(private val session: FirSession) : FirSess context: ConeTypeCheckerContext ): AbstractTypeCheckerContext.SupertypesPolicy { val supertypeLookupTag = (supertype as ConeClassLikeType).lookupTag - val captured = context.captureFromArguments(supertype, CaptureStatus.FOR_SUBTYPING) as ConeClassLikeType? ?: supertype + val captured = + context.typeSystemContext.captureFromArguments(supertype, CaptureStatus.FOR_SUBTYPING) as ConeClassLikeType? ?: supertype resultingMap[supertypeLookupTag] = listOf(captured) return when { - with(context) { captured.argumentsCount() } == 0 -> { + with(context.typeSystemContext) { captured.argumentsCount() } == 0 -> { AbstractTypeCheckerContext.SupertypesPolicy.LowerIfFlexible } else -> { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index 55a879d4acd..1ae7b43c724 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -1374,7 +1374,7 @@ class ExpressionCodegen( val reifiedTypeInliner = ReifiedTypeInliner( mappings, IrInlineIntrinsicsSupport(context, typeMapper), - IrTypeCheckerContext(context.irBuiltIns), + IrTypeSystemContextImpl(context.irBuiltIns), state.languageVersionSettings, state.unifiedNullChecks, ) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt index 43ed5866694..58e3d4985e8 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt @@ -39,7 +39,7 @@ import org.jetbrains.kotlin.ir.types.isKClass as isKClassImpl import org.jetbrains.kotlin.ir.util.isSuspendFunction as isSuspendFunctionImpl class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapperBase(), TypeMappingContext { - internal val typeSystem = IrTypeCheckerContext(context.irBuiltIns) + internal val typeSystem = IrTypeSystemContextImpl(context.irBuiltIns) override val typeContext: TypeSystemCommonBackendContextForTypeMapping = IrTypeCheckerContextForTypeMapping(typeSystem, context) override fun mapClass(classifier: ClassifierDescriptor): Type = diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CollectionStubMethodLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CollectionStubMethodLowering.kt index 9b627b0a39a..2dbd3e9f69e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CollectionStubMethodLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CollectionStubMethodLowering.kt @@ -229,7 +229,13 @@ internal class CollectionStubMethodLowering(val context: JvmBackendContext) : Cl } private fun createTypeChecker(overrideFun: IrSimpleFunction, parentFun: IrSimpleFunction): AbstractTypeCheckerContext = - IrTypeCheckerContextWithAdditionalAxioms(context.irBuiltIns, overrideFun.typeParameters, parentFun.typeParameters) + IrTypeCheckerContext( + IrTypeSystemContextWithAdditionalAxioms( + context.irBuiltIns, + overrideFun.typeParameters, + parentFun.typeParameters + ) + ) private fun areTypeParametersEquivalent( overrideFun: IrSimpleFunction, diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverridingUtil.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverridingUtil.kt index cf1e7c00f3e..42b971c140b 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverridingUtil.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverridingUtil.kt @@ -425,14 +425,14 @@ class IrOverridingUtil( return if (a == null || b == null) true else isVisibilityMoreSpecific(a, b) } - private fun IrTypeCheckerContextWithAdditionalAxioms.isSubtypeOf(a: IrType, b: IrType) = + private fun IrTypeCheckerContext.isSubtypeOf(a: IrType, b: IrType) = AbstractTypeChecker.isSubtypeOf(this as AbstractTypeCheckerContext, a, b) - private fun IrTypeCheckerContextWithAdditionalAxioms.equalTypes(a: IrType, b: IrType) = + private fun IrTypeCheckerContext.equalTypes(a: IrType, b: IrType) = AbstractTypeChecker.equalTypes(this as AbstractTypeCheckerContext, a, b) private fun createTypeChecker(a: List, b: List) = - IrTypeCheckerContextWithAdditionalAxioms(irBuiltIns, a, b) + IrTypeCheckerContext(IrTypeSystemContextWithAdditionalAxioms(irBuiltIns, a, b)) private fun isReturnTypeMoreSpecific( a: IrOverridableMember, @@ -661,10 +661,12 @@ class IrOverridingUtil( } val typeCheckerContext = - IrTypeCheckerContextWithAdditionalAxioms( - irBuiltIns, - superTypeParameters, - subTypeParameters + IrTypeCheckerContext( + IrTypeSystemContextWithAdditionalAxioms( + irBuiltIns, + superTypeParameters, + subTypeParameters + ) ) /* TODO: check the bounds. See OverridingUtil.areTypeParametersEquivalent() diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeCheckerContext.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeCheckerContext.kt index 2fe6f32b8b9..6a1e198e0e9 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeCheckerContext.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeCheckerContext.kt @@ -10,7 +10,9 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.types.model.* -open class IrTypeCheckerContext(override val irBuiltIns: IrBuiltIns) : IrTypeSystemContext, AbstractTypeCheckerContext() { +open class IrTypeCheckerContext(override val typeSystemContext: IrTypeSystemContext): AbstractTypeCheckerContext() { + + val irBuiltIns: IrBuiltIns get() = typeSystemContext.irBuiltIns override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy.DoCustomTransform { require(type is IrSimpleType) @@ -30,32 +32,4 @@ open class IrTypeCheckerContext(override val irBuiltIns: IrBuiltIns) : IrTypeSys override val KotlinTypeMarker.isAllowedTypeVariable: Boolean get() = false - - override fun newBaseTypeCheckerContext( - errorTypesEqualToAnything: Boolean, - stubTypesEqualToAnything: Boolean - ): AbstractTypeCheckerContext = IrTypeCheckerContext(irBuiltIns) - - override fun KotlinTypeMarker.isUninferredParameter(): Boolean = false - override fun KotlinTypeMarker.withNullability(nullable: Boolean): KotlinTypeMarker { - if (this.isSimpleType()) { - return this.asSimpleType()!!.withNullability(nullable) - } else { - error("withNullability for non-simple types is not supported in IR") - } - } - - override fun captureFromExpression(type: KotlinTypeMarker): KotlinTypeMarker? = - error("Captured type is unsupported in IR") - - override fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker = - error("DefinitelyNotNull type is unsupported in IR") - - override fun KotlinTypeMarker.makeDefinitelyNotNullOrNotNull(): KotlinTypeMarker { - error("makeDefinitelyNotNullOrNotNull is not supported in IR") - } - - override fun SimpleTypeMarker.makeSimpleTypeDefinitelyNotNullOrNotNull(): SimpleTypeMarker { - error("makeSimpleTypeDefinitelyNotNullOrNotNull is not yet supported in IR") - } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeCheckerUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeCheckerUtils.kt index 0b442c89a58..8309eef8eac 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeCheckerUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeCheckerUtils.kt @@ -9,11 +9,11 @@ import org.jetbrains.kotlin.ir.declarations.IrTypeParameter import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.types.model.TypeConstructorMarker -open class IrTypeCheckerContextWithAdditionalAxioms( +class IrTypeSystemContextWithAdditionalAxioms( override val irBuiltIns: IrBuiltIns, firstParameters: List, secondParameters: List -) : IrTypeCheckerContext(irBuiltIns) { +) : IrTypeSystemContext { init { assert(firstParameters.size == secondParameters.size) { "different length of type parameter lists: $firstParameters vs $secondParameters" diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt index 7eca8a677a8..02df059bcd5 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.model.* @@ -454,6 +455,39 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon val irClass = (this as IrType).classOrNull?.owner return irClass != null && (irClass.isInterface || irClass.isAnnotationClass) } + + + override fun newBaseTypeCheckerContext( + errorTypesEqualToAnything: Boolean, + stubTypesEqualToAnything: Boolean + ): AbstractTypeCheckerContext = IrTypeCheckerContext(this) + + override fun KotlinTypeMarker.isUninferredParameter(): Boolean = false + override fun KotlinTypeMarker.withNullability(nullable: Boolean): KotlinTypeMarker { + if (this.isSimpleType()) { + return this.asSimpleType()!!.withNullability(nullable) + } else { + error("withNullability for non-simple types is not supported in IR") + } + } + + override fun captureFromExpression(type: KotlinTypeMarker): KotlinTypeMarker? = + error("Captured type is unsupported in IR") + + override fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker = + error("DefinitelyNotNull type is unsupported in IR") + + override fun KotlinTypeMarker.makeDefinitelyNotNullOrNotNull(): KotlinTypeMarker { + error("makeDefinitelyNotNullOrNotNull is not supported in IR") + } + + override fun SimpleTypeMarker.makeSimpleTypeDefinitelyNotNullOrNotNull(): SimpleTypeMarker { + error("makeSimpleTypeDefinitelyNotNullOrNotNull is not yet supported in IR") + } + + override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker { + return type + } } fun extractTypeParameters(parent: IrDeclarationParent): List { @@ -480,3 +514,6 @@ fun extractTypeParameters(parent: IrDeclarationParent): List { } return result } + + +class IrTypeSystemContextImpl(override val irBuiltIns: IrBuiltIns) : IrTypeSystemContext \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeUtils.kt index 93e047ba5b4..13427724dcc 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeUtils.kt @@ -32,7 +32,11 @@ fun IrType.isSubtypeOfClass(superClass: IrClassSymbol): Boolean { } fun IrType.isSubtypeOf(superType: IrType, irBuiltIns: IrBuiltIns): Boolean { - return AbstractTypeChecker.isSubtypeOf(IrTypeCheckerContext(irBuiltIns) as AbstractTypeCheckerContext, this, superType) + return AbstractTypeChecker.isSubtypeOf( + IrTypeCheckerContext(IrTypeSystemContextImpl(irBuiltIns)) as AbstractTypeCheckerContext, + this, + superType + ) } fun IrType.isNullable(): Boolean = diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt index 08b381d22dc..b98a365de9d 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/NewCommonSuperTypeCalculator.kt @@ -267,9 +267,7 @@ object NewCommonSuperTypeCalculator { * but it is too complicated and we will return not so accurate type: CS(List, List, List) */ val correspondingSuperTypes = types.flatMap { - with(AbstractTypeChecker) { - typeCheckerContext.findCorrespondingSupertypes(it, constructor) - } + AbstractTypeChecker.findCorrespondingSupertypes(typeCheckerContext, it, constructor) } val arguments = ArrayList(constructor.parametersCount()) diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/AbstractTypeCheckerContextForConstraintSystem.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/AbstractTypeCheckerContextForConstraintSystem.kt index d1a0df2ab40..b6e7697e17c 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/AbstractTypeCheckerContextForConstraintSystem.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/AbstractTypeCheckerContextForConstraintSystem.kt @@ -10,7 +10,8 @@ import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.types.model.* -abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheckerContext(), TypeSystemInferenceExtensionContext { +abstract class AbstractTypeCheckerContextForConstraintSystem(override val typeSystemContext: TypeSystemInferenceExtensionContext) : + AbstractTypeCheckerContext() { override val KotlinTypeMarker.isAllowedTypeVariable: Boolean get() = false @@ -36,21 +37,22 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck abstract fun addEqualityConstraint(typeVariable: TypeConstructorMarker, type: KotlinTypeMarker) - override fun getLowerCapturedTypePolicy(subType: SimpleTypeMarker, superType: CapturedTypeMarker): LowerCapturedTypePolicy { - return when { - isMyTypeVariable(subType) -> { - val projection = superType.typeConstructorProjection() - val type = projection.getType().asSimpleType() - if (projection.getVariance() == TypeVariance.IN && type != null && isMyTypeVariable(type)) { - LowerCapturedTypePolicy.CHECK_ONLY_LOWER - } else { - LowerCapturedTypePolicy.SKIP_LOWER + override fun getLowerCapturedTypePolicy(subType: SimpleTypeMarker, superType: CapturedTypeMarker): LowerCapturedTypePolicy = + with(typeSystemContext) { + return when { + isMyTypeVariable(subType) -> { + val projection = superType.typeConstructorProjection() + val type = projection.getType().asSimpleType() + if (projection.getVariance() == TypeVariance.IN && type != null && isMyTypeVariable(type)) { + LowerCapturedTypePolicy.CHECK_ONLY_LOWER + } else { + LowerCapturedTypePolicy.SKIP_LOWER + } } + subType.contains { it.anyBound(::isMyTypeVariable) } -> LowerCapturedTypePolicy.CHECK_ONLY_LOWER + else -> LowerCapturedTypePolicy.CHECK_SUBTYPE_AND_LOWER } - subType.contains { it.anyBound(this::isMyTypeVariable) } -> LowerCapturedTypePolicy.CHECK_ONLY_LOWER - else -> LowerCapturedTypePolicy.CHECK_SUBTYPE_AND_LOWER } - } /** * todo: possible we should override this method, because otherwise OR in subtyping transformed to AND in constraint system @@ -70,9 +72,11 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck // we should strip annotation's because we have incorporation operation and they should be not affected val mySubType = - if (hasExact) extractTypeForProjectedType(subType, out = true) ?: subType.removeExactAnnotation() else subType + if (hasExact) extractTypeForProjectedType(subType, out = true) + ?: with(typeSystemContext) { subType.removeExactAnnotation() } else subType val mySuperType = - if (hasExact) extractTypeForProjectedType(superType, out = false) ?: superType.removeExactAnnotation() else superType + if (hasExact) extractTypeForProjectedType(superType, out = false) + ?: with(typeSystemContext) { superType.removeExactAnnotation() } else superType val result = internalAddSubtypeConstraint(mySubType, mySuperType, isFromNullabilityConstraint) if (!hasExact) return result @@ -83,7 +87,7 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck return (result ?: true) && (result2 ?: true) } - private fun extractTypeForProjectedType(type: KotlinTypeMarker, out: Boolean): KotlinTypeMarker? { + private fun extractTypeForProjectedType(type: KotlinTypeMarker, out: Boolean): KotlinTypeMarker? = with(typeSystemContext) { val typeMarker = type.asSimpleType()?.asCapturedType() ?: return null val projection = typeMarker.typeConstructorProjection() @@ -98,10 +102,10 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck } private fun KotlinTypeMarker.isTypeVariableWithExact() = - hasExactAnnotation() && anyBound(this@AbstractTypeCheckerContextForConstraintSystem::isMyTypeVariable) + with(typeSystemContext) { hasExactAnnotation() } && anyBound(this@AbstractTypeCheckerContextForConstraintSystem::isMyTypeVariable) private fun KotlinTypeMarker.isTypeVariableWithNoInfer() = - hasNoInferAnnotation() && anyBound(this@AbstractTypeCheckerContextForConstraintSystem::isMyTypeVariable) + with(typeSystemContext) { hasNoInferAnnotation() } && anyBound(this@AbstractTypeCheckerContextForConstraintSystem::isMyTypeVariable) private fun internalAddSubtypeConstraint( subType: KotlinTypeMarker, @@ -128,32 +132,33 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck } // extract type variable only from type like Captured(out T) - private fun extractTypeVariableForSubtype(subType: KotlinTypeMarker, superType: KotlinTypeMarker): KotlinTypeMarker? { + private fun extractTypeVariableForSubtype(subType: KotlinTypeMarker, superType: KotlinTypeMarker): KotlinTypeMarker? = + with(typeSystemContext) { - val typeMarker = subType.asSimpleType()?.asCapturedType() ?: return null + val typeMarker = subType.asSimpleType()?.asCapturedType() ?: return null - val projection = typeMarker.typeConstructorProjection() - if (projection.isStarProjection()) return null - if (projection.getVariance() == TypeVariance.IN) { - val type = projection.getType().asSimpleType() ?: return null - if (isMyTypeVariable(type)) { - simplifyLowerConstraint(type, superType) - if (isMyTypeVariable(superType.asSimpleType() ?: return null)) { - addLowerConstraint(superType.typeConstructor(), nullableAnyType()) + val projection = typeMarker.typeConstructorProjection() + if (projection.isStarProjection()) return null + if (projection.getVariance() == TypeVariance.IN) { + val type = projection.getType().asSimpleType() ?: return null + if (isMyTypeVariable(type)) { + simplifyLowerConstraint(type, superType) + if (isMyTypeVariable(superType.asSimpleType() ?: return null)) { + addLowerConstraint(superType.typeConstructor(), nullableAnyType()) + } } + return null } - return null - } - return if (projection.getVariance() == TypeVariance.OUT) { - val type = projection.getType() - when { - type is SimpleTypeMarker && isMyTypeVariable(type) -> type.asSimpleType() - type is FlexibleTypeMarker && isMyTypeVariable(type.lowerBound()) -> type.asFlexibleType()?.lowerBound() - else -> null - } - } else null - } + return if (projection.getVariance() == TypeVariance.OUT) { + val type = projection.getType() + when { + type is SimpleTypeMarker && isMyTypeVariable(type) -> type.asSimpleType() + type is FlexibleTypeMarker && isMyTypeVariable(type.lowerBound()) -> type.asFlexibleType()?.lowerBound() + else -> null + } + } else null + } /** * Foo <: T -- leave as is @@ -196,7 +201,7 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck typeVariable: KotlinTypeMarker, subType: KotlinTypeMarker, isFromNullabilityConstraint: Boolean = false - ): Boolean { + ): Boolean = with(typeSystemContext) { val lowerConstraint = when (typeVariable) { is SimpleTypeMarker -> /* @@ -256,7 +261,7 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck return true } - private fun assertFlexibleTypeVariable(typeVariable: FlexibleTypeMarker) { + private fun assertFlexibleTypeVariable(typeVariable: FlexibleTypeMarker) = with(typeSystemContext) { assert(typeVariable.lowerBound().typeConstructor() == typeVariable.upperBound().typeConstructor()) { "Flexible type variable ($typeVariable) should have bounds with the same type constructor, i.e. (T..T?)" } @@ -267,7 +272,7 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck * T? <: Foo <=> T <: Foo && Nothing? <: Foo * T <: Foo -- leave as is */ - private fun simplifyUpperConstraint(typeVariable: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean { + private fun simplifyUpperConstraint(typeVariable: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean = with(typeSystemContext) { val typeVariableLowerBound = typeVariable.lowerBoundIfFlexible() val simplifiedSuperType = if (typeVariableLowerBound.isDefinitelyNotNullType()) { superType.withNullability(true) @@ -279,37 +284,38 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck if (typeVariableLowerBound.isMarkedNullable()) { // here is important that superType is singleClassifierType - return simplifiedSuperType.anyBound(this::isMyTypeVariable) || + return simplifiedSuperType.anyBound(::isMyTypeVariable) || isSubtypeOfByTypeChecker(nullableNothingType(), simplifiedSuperType) } return true } - private fun simplifyConstraintForPossibleIntersectionSubType(subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean? { - @Suppress("NAME_SHADOWING") - val subType = subType.lowerBoundIfFlexible() + private fun simplifyConstraintForPossibleIntersectionSubType(subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean? = + with(typeSystemContext) { + @Suppress("NAME_SHADOWING") + val subType = subType.lowerBoundIfFlexible() - if (!subType.typeConstructor().isIntersection()) return null + if (!subType.typeConstructor().isIntersection()) return null - assert(!subType.isMarkedNullable()) { "Intersection type should not be marked nullable!: $subType" } + assert(!subType.isMarkedNullable()) { "Intersection type should not be marked nullable!: $subType" } - // TODO: may be we lose flexibility here - val subIntersectionTypes = (subType.typeConstructor().supertypes()).map { it.lowerBoundIfFlexible() } + // TODO: may be we lose flexibility here + val subIntersectionTypes = (subType.typeConstructor().supertypes()).map { it.lowerBoundIfFlexible() } - val typeVariables = subIntersectionTypes.filter(this::isMyTypeVariable).takeIf { it.isNotEmpty() } ?: return null - val notTypeVariables = subIntersectionTypes.filterNot(this::isMyTypeVariable) + val typeVariables = subIntersectionTypes.filter(::isMyTypeVariable).takeIf { it.isNotEmpty() } ?: return null + val notTypeVariables = subIntersectionTypes.filterNot(::isMyTypeVariable) - // todo: may be we can do better then that. - if (notTypeVariables.isNotEmpty() && - AbstractTypeChecker.isSubtypeOf( - this as TypeCheckerProviderContext, - intersectTypes(notTypeVariables), - superType - ) - ) { - return true - } + // todo: may be we can do better then that. + if (notTypeVariables.isNotEmpty() && + AbstractTypeChecker.isSubtypeOf( + this as TypeCheckerProviderContext, + intersectTypes(notTypeVariables), + superType + ) + ) { + return true + } // Consider the following example: // fun id(x: T): T = x @@ -326,23 +332,25 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck // here we try to add constraint {Any & T} <: S from `id(a)` // Previously we thought that if `Any` isn't a subtype of S => T <: S, which is wrong, now we use weaker upper constraint // TODO: rethink, maybe we should take nullability into account somewhere else - if (notTypeVariables.any { AbstractNullabilityChecker.isSubtypeOfAny(this as TypeCheckerProviderContext, it) }) { - return typeVariables.all { simplifyUpperConstraint(it, superType.withNullability(true)) } - } + if (notTypeVariables.any { AbstractNullabilityChecker.isSubtypeOfAny(this as TypeCheckerProviderContext, it) }) { + return typeVariables.all { simplifyUpperConstraint(it, superType.withNullability(true)) } + } - return typeVariables.all { simplifyUpperConstraint(it, superType) } - } + return typeVariables.all { simplifyUpperConstraint(it, superType) } + } private fun isSubtypeOfByTypeChecker(subType: KotlinTypeMarker, superType: KotlinTypeMarker) = AbstractTypeChecker.isSubtypeOf(this as AbstractTypeCheckerContext, subType, superType) - private fun assertInputTypes(subType: KotlinTypeMarker, superType: KotlinTypeMarker) { + private fun assertInputTypes(subType: KotlinTypeMarker, superType: KotlinTypeMarker) = with(typeSystemContext) { if (!AbstractTypeChecker.RUN_SLOW_ASSERTIONS) return fun correctSubType(subType: SimpleTypeMarker) = - subType.isSingleClassifierType() || subType.typeConstructor().isIntersection() || isMyTypeVariable(subType) || subType.isError() || subType.isIntegerLiteralType() + subType.isSingleClassifierType() || subType.typeConstructor() + .isIntersection() || isMyTypeVariable(subType) || subType.isError() || subType.isIntegerLiteralType() fun correctSuperType(superType: SimpleTypeMarker) = - superType.isSingleClassifierType() || superType.typeConstructor().isIntersection() || isMyTypeVariable(superType) || superType.isError() || superType.isIntegerLiteralType() + superType.isSingleClassifierType() || superType.typeConstructor() + .isIntersection() || isMyTypeVariable(superType) || superType.isError() || superType.isIntegerLiteralType() assert(subType.bothBounds(::correctSubType)) { "Not singleClassifierType and not intersection subType: $subType" @@ -354,13 +362,13 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck private inline fun KotlinTypeMarker.bothBounds(f: (SimpleTypeMarker) -> Boolean) = when (this) { is SimpleTypeMarker -> f(this) - is FlexibleTypeMarker -> f(lowerBound()) && f(upperBound()) + is FlexibleTypeMarker -> with(typeSystemContext) { f(lowerBound()) && f(upperBound()) } else -> error("sealed") } private inline fun KotlinTypeMarker.anyBound(f: (SimpleTypeMarker) -> Boolean) = when (this) { is SimpleTypeMarker -> f(this) - is FlexibleTypeMarker -> f(lowerBound()) || f(upperBound()) + is FlexibleTypeMarker -> with(typeSystemContext) { f(lowerBound()) || f(upperBound()) } else -> error("sealed") } } diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintInjector.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintInjector.kt index 3905e1461de..61eca16a127 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintInjector.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintInjector.kt @@ -165,7 +165,7 @@ class ConstraintInjector( type.typeDepth() <= maxTypeDepthFromInitialConstraints + ALLOWED_DEPTH_DELTA_FOR_INCORPORATION private inner class TypeCheckerContext(val c: Context, val position: IncorporationConstraintPosition) : - AbstractTypeCheckerContextForConstraintSystem(), ConstraintIncorporator.Context, TypeSystemInferenceExtensionContext by c { + AbstractTypeCheckerContextForConstraintSystem(c), ConstraintIncorporator.Context, TypeSystemInferenceExtensionContext by c { // We use `var` intentionally to avoid extra allocations as this property is quite "hot" private var possibleNewConstraints: MutableList>? = null @@ -198,14 +198,6 @@ class ConstraintInjector( return baseContext.substitutionSupertypePolicy(type) } - override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean { - return baseContext.areEqualTypeConstructors(c1, c2) - } - - override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker { - return baseContext.prepareType(type) - } - override fun refineType(type: KotlinTypeMarker): KotlinTypeMarker { return with(constraintIncorporator.utilContext) { type.refineType() diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectedActualResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectedActualResolver.kt index 494efd77463..95f8fe6a603 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectedActualResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectedActualResolver.kt @@ -23,7 +23,9 @@ import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.TypeConstructorSubstitution import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerContext +import org.jetbrains.kotlin.types.checker.ClassicTypeSystemContext import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker +import org.jetbrains.kotlin.types.model.TypeConstructorMarker import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.keysToMap @@ -326,14 +328,17 @@ object ExpectedActualResolver { if (b == null) return false with(NewKotlinTypeChecker.Default) { - val context = object : ClassicTypeCheckerContext(false) { - override fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean { - return isExpectedClassAndActualTypeAlias(a, b, platformModule) || - isExpectedClassAndActualTypeAlias(b, a, platformModule) || - super.areEqualTypeConstructors(a, b) + val context = object : ClassicTypeSystemContext { + override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean { + require(c1 is TypeConstructor) + require(c2 is TypeConstructor) + return isExpectedClassAndActualTypeAlias(c1, c2, platformModule) || + isExpectedClassAndActualTypeAlias(c2, c1, platformModule) || + super.areEqualTypeConstructors(c1, c2) } } - return context.equalTypes(a.unwrap(), b.unwrap()) + return ClassicTypeCheckerContext(errorTypeEqualsToAnything = false, typeSystemContext = context) + .equalTypes(a.unwrap(), b.unwrap()) } } diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt index 017dd9873ed..3f0e2870800 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt @@ -13,15 +13,12 @@ import org.jetbrains.kotlin.utils.SmartSet import java.util.* -abstract class AbstractTypeCheckerContext : TypeSystemContext { +abstract class AbstractTypeCheckerContext() { + abstract val typeSystemContext: TypeSystemContext abstract fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy - override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker { - return type - } - open fun refineType(type: KotlinTypeMarker): KotlinTypeMarker { return type } @@ -34,7 +31,6 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext { protected var argumentsDepth = 0 - internal inline fun runWithArgumentsSettings(subArgument: KotlinTypeMarker, f: AbstractTypeCheckerContext.() -> T): T { if (argumentsDepth > 100) { error("Arguments depth is too high. Some related argument: $subArgument") @@ -46,7 +42,8 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext { return result } - open fun getLowerCapturedTypePolicy(subType: SimpleTypeMarker, superType: CapturedTypeMarker): LowerCapturedTypePolicy = CHECK_SUBTYPE_AND_LOWER + open fun getLowerCapturedTypePolicy(subType: SimpleTypeMarker, superType: CapturedTypeMarker): LowerCapturedTypePolicy = + CHECK_SUBTYPE_AND_LOWER open fun addSubtypeConstraint( subType: KotlinTypeMarker, @@ -109,7 +106,8 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext { if (!visitedSupertypes.add(current)) continue val policy = supertypesPolicy(current).takeIf { it != SupertypesPolicy.None } ?: continue - for (supertype in current.typeConstructor().supertypes()) { + val supertypes = with(typeSystemContext) { current.typeConstructor().supertypes() } + for (supertype in supertypes) { val newType = policy.transformType(this, supertype) if (predicate(newType)) { clear() @@ -133,18 +131,21 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext { object UpperIfFlexible : SupertypesPolicy() { override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker) = - with(context) { type.upperBoundIfFlexible() } + with(context.typeSystemContext) { type.upperBoundIfFlexible() } } object LowerIfFlexible : SupertypesPolicy() { override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker) = - with(context) { type.lowerBoundIfFlexible() } + with(context.typeSystemContext) { type.lowerBoundIfFlexible() } } abstract class DoCustomTransform : SupertypesPolicy() } abstract val KotlinTypeMarker.isAllowedTypeVariable: Boolean + + @JvmName("isAllowedTypeVariableBridge") + fun isAllowedTypeVariable(type: KotlinTypeMarker): Boolean = type.isAllowedTypeVariable } object AbstractTypeChecker { @@ -166,7 +167,7 @@ object AbstractTypeChecker { superConstructor: TypeConstructorMarker ): Boolean { if (typeConstructor == superConstructor) return true - with(context) { + with(context.typeSystemContext) { for (superType in typeConstructor.supertypes()) { if (isSubtypeOfClass(context, superType.typeConstructor(), superConstructor)) { return true @@ -182,7 +183,7 @@ object AbstractTypeChecker { b: KotlinTypeMarker, stubTypesEqualToAnything: Boolean = true ): Boolean { - return AbstractTypeChecker.equalTypes(context.newBaseTypeCheckerContext(false, stubTypesEqualToAnything), a, b) + return equalTypes(context.newBaseTypeCheckerContext(false, stubTypesEqualToAnything), a, b) } fun isSubtypeOf( @@ -195,55 +196,61 @@ object AbstractTypeChecker { if (!context.customIsSubtypeOf(subType, superType)) return false - return with(context) { - completeIsSubTypeOf(prepareType(refineType(subType)), prepareType(refineType(superType)), isFromNullabilityConstraint) - } + return completeIsSubTypeOf( + context, + context.typeSystemContext.prepareType(context.refineType(subType)), + context.typeSystemContext.prepareType(context.refineType(superType)), + isFromNullabilityConstraint + ) } - fun equalTypes(context: AbstractTypeCheckerContext, a: KotlinTypeMarker, b: KotlinTypeMarker): Boolean = with(context) { - if (a === b) return true + fun equalTypes(context: AbstractTypeCheckerContext, a: KotlinTypeMarker, b: KotlinTypeMarker): Boolean = + with(context.typeSystemContext) { + if (a === b) return true - if (isCommonDenotableType(a) && isCommonDenotableType(b)) { - val refinedA = refineType(a) - val refinedB = refineType(b) - val simpleA = refinedA.lowerBoundIfFlexible() - if (!areEqualTypeConstructors(refinedA.typeConstructor(), refinedB.typeConstructor())) return false - if (simpleA.argumentsCount() == 0) { - if (refinedA.hasFlexibleNullability() || refinedB.hasFlexibleNullability()) return true + if (isCommonDenotableType(a) && isCommonDenotableType(b)) { + val refinedA = context.refineType(a) + val refinedB = context.refineType(b) + val simpleA = refinedA.lowerBoundIfFlexible() + if (!areEqualTypeConstructors(refinedA.typeConstructor(), refinedB.typeConstructor())) return false + if (simpleA.argumentsCount() == 0) { + if (refinedA.hasFlexibleNullability() || refinedB.hasFlexibleNullability()) return true - return simpleA.isMarkedNullable() == refinedB.lowerBoundIfFlexible().isMarkedNullable() + return simpleA.isMarkedNullable() == refinedB.lowerBoundIfFlexible().isMarkedNullable() + } } + + return isSubtypeOf(context, a, b) && isSubtypeOf(context, b, a) } - return isSubtypeOf(context, a, b) && isSubtypeOf(context, b, a) - } - - private fun AbstractTypeCheckerContext.completeIsSubTypeOf( + private fun completeIsSubTypeOf( + context: AbstractTypeCheckerContext, subType: KotlinTypeMarker, superType: KotlinTypeMarker, isFromNullabilityConstraint: Boolean - ): Boolean { - checkSubtypeForSpecialCases(subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())?.let { - addSubtypeConstraint(subType, superType, isFromNullabilityConstraint) + ): Boolean = with(context.typeSystemContext) { + checkSubtypeForSpecialCases(context, subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())?.let { + context.addSubtypeConstraint(subType, superType, isFromNullabilityConstraint) return it } // we should add constraints with flexible types, otherwise we never get flexible type as answer in constraint system - addSubtypeConstraint(subType, superType, isFromNullabilityConstraint)?.let { return it } + context.addSubtypeConstraint(subType, superType, isFromNullabilityConstraint)?.let { return it } - return isSubtypeOfForSingleClassifierType(subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible()) + return isSubtypeOfForSingleClassifierType(context, subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible()) } - private fun AbstractTypeCheckerContext.checkSubtypeForIntegerLiteralType( + private fun checkSubtypeForIntegerLiteralType( + context: AbstractTypeCheckerContext, subType: SimpleTypeMarker, superType: SimpleTypeMarker - ): Boolean? { + ): Boolean? = with(context.typeSystemContext) { if (!subType.isIntegerLiteralType() && !superType.isIntegerLiteralType()) return null fun isTypeInIntegerLiteralType(integerLiteralType: SimpleTypeMarker, type: SimpleTypeMarker, checkSupertypes: Boolean): Boolean = integerLiteralType.possibleIntegerTypes().any { possibleType -> - (possibleType.typeConstructor() == type.typeConstructor()) || (checkSupertypes && isSubtypeOf(this, type, possibleType)) + (possibleType.typeConstructor() == type.typeConstructor()) || (checkSupertypes && isSubtypeOf(context, type, possibleType)) } fun isIntegerLiteralTypeInIntersectionComponents(type: SimpleTypeMarker): Boolean { @@ -276,12 +283,12 @@ object AbstractTypeChecker { return null } - private fun AbstractTypeCheckerContext.hasNothingSupertype(type: SimpleTypeMarker): Boolean { + private fun hasNothingSupertype(context: AbstractTypeCheckerContext, type: SimpleTypeMarker): Boolean = with(context.typeSystemContext) { val typeConstructor = type.typeConstructor() if (typeConstructor.isClassTypeConstructor()) { return typeConstructor.isNothingConstructor() } - return anySupertype(type, { it.typeConstructor().isNothingConstructor() }) { + return context.anySupertype(type, { it.typeConstructor().isNothingConstructor() }) { if (it.isClassType()) { SupertypesPolicy.None } else { @@ -290,20 +297,24 @@ object AbstractTypeChecker { } } - private fun AbstractTypeCheckerContext.isSubtypeOfForSingleClassifierType(subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean { + private fun isSubtypeOfForSingleClassifierType( + context: AbstractTypeCheckerContext, + subType: SimpleTypeMarker, + superType: SimpleTypeMarker + ): Boolean = with(context.typeSystemContext) { if (AbstractTypeChecker.RUN_SLOW_ASSERTIONS) { - assert(subType.isSingleClassifierType() || subType.typeConstructor().isIntersection() || subType.isAllowedTypeVariable) { + assert(subType.isSingleClassifierType() || subType.typeConstructor().isIntersection() || context.isAllowedTypeVariable(subType)) { "Not singleClassifierType and not intersection subType: $subType" } - assert(superType.isSingleClassifierType() || superType.isAllowedTypeVariable) { + assert(superType.isSingleClassifierType() || context .isAllowedTypeVariable(superType)) { "Not singleClassifierType superType: $superType" } } - if (!AbstractNullabilityChecker.isPossibleSubtype(this, subType, superType)) return false + if (!AbstractNullabilityChecker.isPossibleSubtype(context, subType, superType)) return false - checkSubtypeForIntegerLiteralType(subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())?.let { - addSubtypeConstraint(subType, superType) + checkSubtypeForIntegerLiteralType(context, subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())?.let { + context.addSubtypeConstraint(subType, superType) return it } @@ -312,10 +323,10 @@ object AbstractTypeChecker { if (areEqualTypeConstructors(subType.typeConstructor(), superConstructor) && superConstructor.parametersCount() == 0) return true if (superType.typeConstructor().isAnyConstructor()) return true - val supertypesWithSameConstructor = findCorrespondingSupertypes(subType, superConstructor) + val supertypesWithSameConstructor = findCorrespondingSupertypes(context, subType, superConstructor) when (supertypesWithSameConstructor.size) { - 0 -> return hasNothingSupertype(subType) // todo Nothing & Array <: Array - 1 -> return isSubtypeForSameConstructor(supertypesWithSameConstructor.first().asArgumentList(), superType) + 0 -> return hasNothingSupertype(context, subType) // todo Nothing & Array <: Array + 1 -> return context.isSubtypeForSameConstructor(supertypesWithSameConstructor.first().asArgumentList(), superType) else -> { // at least 2 supertypes with same constructors. Such case is rare val newArguments = ArgumentList(superConstructor.parametersCount()) @@ -333,10 +344,10 @@ object AbstractTypeChecker { newArguments.add(intersection) } - if (!anyNonOutParameter && isSubtypeForSameConstructor(newArguments, superType)) return true + if (!anyNonOutParameter && context.isSubtypeForSameConstructor(newArguments, superType)) return true // TODO: rethink this; now components order in intersection type affects semantic due to run subtyping (which can add constraints) only until the first successful candidate - return supertypesWithSameConstructor.any { isSubtypeForSameConstructor(it.asArgumentList(), superType) } + return supertypesWithSameConstructor.any { context.isSubtypeForSameConstructor(it.asArgumentList(), superType) } } } } @@ -344,7 +355,7 @@ object AbstractTypeChecker { fun AbstractTypeCheckerContext.isSubtypeForSameConstructor( capturedSubArguments: TypeArgumentListMarker, superType: SimpleTypeMarker - ): Boolean { + ): Boolean = with(this.typeSystemContext) { // No way to check, as no index sometimes //if (capturedSubArguments === superType.arguments) return true @@ -375,7 +386,7 @@ object AbstractTypeChecker { return true } - private fun AbstractTypeCheckerContext.isCommonDenotableType(type: KotlinTypeMarker): Boolean = + private fun TypeSystemContext.isCommonDenotableType(type: KotlinTypeMarker): Boolean = type.typeConstructor().isDenotable() && !type.isDynamic() && !type.isDefinitelyNotNullType() && type.lowerBoundIfFlexible().typeConstructor() == type.upperBoundIfFlexible().typeConstructor() @@ -391,9 +402,13 @@ object AbstractTypeChecker { return null } - private fun AbstractTypeCheckerContext.checkSubtypeForSpecialCases(subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean? { + private fun checkSubtypeForSpecialCases( + context: AbstractTypeCheckerContext, + subType: SimpleTypeMarker, + superType: SimpleTypeMarker + ): Boolean? = with(context.typeSystemContext) { if (subType.isError() || superType.isError()) { - if (isErrorTypeEqualsToAnything) return true + if (context.isErrorTypeEqualsToAnything) return true if (subType.isMarkedNullable() && !superType.isMarkedNullable()) return false @@ -404,7 +419,7 @@ object AbstractTypeChecker { ) } - if (subType.isStubType() || superType.isStubType()) return isStubTypeEqualsToAnything + if (subType.isStubType() || superType.isStubType()) return context.isStubTypeEqualsToAnything // superType might be a definitely notNull type (see KT-42824) val superOriginalType = superType.asDefinitelyNotNullType()?.original() ?: superType @@ -418,9 +433,9 @@ object AbstractTypeChecker { } else { if (superType.isDefinitelyNotNullType()) lowerType.makeDefinitelyNotNullOrNotNull() else lowerType } - when (getLowerCapturedTypePolicy(subType, superTypeCaptured)) { - CHECK_ONLY_LOWER -> return isSubtypeOf(this, subType, nullableLowerType) - CHECK_SUBTYPE_AND_LOWER -> if (isSubtypeOf(this, subType, nullableLowerType)) return true + when (context.getLowerCapturedTypePolicy(subType, superTypeCaptured)) { + CHECK_ONLY_LOWER -> return isSubtypeOf(context, subType, nullableLowerType) + CHECK_SUBTYPE_AND_LOWER -> if (isSubtypeOf(context, subType, nullableLowerType)) return true SKIP_LOWER -> Unit } } @@ -429,17 +444,18 @@ object AbstractTypeChecker { if (superTypeConstructor.isIntersection()) { assert(!superType.isMarkedNullable()) { "Intersection type should not be marked nullable!: $superType" } - return superTypeConstructor.supertypes().all { isSubtypeOf(this, subType, it) } + return superTypeConstructor.supertypes().all { isSubtypeOf(context, subType, it) } } return null } - private fun AbstractTypeCheckerContext.collectAllSupertypesWithGivenTypeConstructor( + private fun collectAllSupertypesWithGivenTypeConstructor( + context: AbstractTypeCheckerContext, subType: SimpleTypeMarker, superConstructor: TypeConstructorMarker - ): List { + ): List = with(context.typeSystemContext) { subType.fastCorrespondingSupertypes(superConstructor)?.let { return it } @@ -455,7 +471,7 @@ object AbstractTypeChecker { val result: MutableList = SmartList() - anySupertype(subType, { false }) { + context.anySupertype(subType, { false }) { val current = captureFromArguments(it, CaptureStatus.FOR_SUBTYPING) ?: it @@ -468,7 +484,7 @@ object AbstractTypeChecker { SupertypesPolicy.LowerIfFlexible } else -> { - substitutionSupertypePolicy(current) + context.substitutionSupertypePolicy(current) } } } @@ -476,8 +492,12 @@ object AbstractTypeChecker { return result } - private fun AbstractTypeCheckerContext.collectAndFilter(classType: SimpleTypeMarker, constructor: TypeConstructorMarker) = - selectOnlyPureKotlinSupertypes(collectAllSupertypesWithGivenTypeConstructor(classType, constructor)) + private fun collectAndFilter( + context: AbstractTypeCheckerContext, + classType: SimpleTypeMarker, + constructor: TypeConstructorMarker + ) = + selectOnlyPureKotlinSupertypes(context, collectAllSupertypesWithGivenTypeConstructor(context, classType, constructor)) /** @@ -490,7 +510,10 @@ object AbstractTypeChecker { * * More tests: javaAndKotlinSuperType & purelyImplementedCollection folder */ - private fun AbstractTypeCheckerContext.selectOnlyPureKotlinSupertypes(supertypes: List): List { + private fun selectOnlyPureKotlinSupertypes( + context: AbstractTypeCheckerContext, + supertypes: List + ): List = with(context.typeSystemContext) { if (supertypes.size < 2) return supertypes val allPureSupertypes = supertypes.filter { @@ -502,22 +525,23 @@ object AbstractTypeChecker { // nullability was checked earlier via nullabilityChecker // should be used only if you really sure that it is correct - fun AbstractTypeCheckerContext.findCorrespondingSupertypes( + fun findCorrespondingSupertypes( + context: AbstractTypeCheckerContext, subType: SimpleTypeMarker, superConstructor: TypeConstructorMarker - ): List { + ): List = with(context.typeSystemContext) { if (subType.isClassType()) { - return collectAndFilter(subType, superConstructor) + return collectAndFilter(context, subType, superConstructor) } // i.e. superType is not a classType if (!superConstructor.isClassTypeConstructor() && !superConstructor.isIntegerLiteralTypeConstructor()) { - return collectAllSupertypesWithGivenTypeConstructor(subType, superConstructor) + return collectAllSupertypesWithGivenTypeConstructor(context, subType, superConstructor) } // todo add tests val classTypeSupertypes = SmartList() - anySupertype(subType, { false }) { + context.anySupertype(subType, { false }) { if (it.isClassType()) { classTypeSupertypes.add(it) SupertypesPolicy.None @@ -526,7 +550,7 @@ object AbstractTypeChecker { } } - return classTypeSupertypes.flatMap { collectAndFilter(it, superConstructor) } + return classTypeSupertypes.flatMap { collectAndFilter(context, it, superConstructor) } } } @@ -534,7 +558,7 @@ object AbstractTypeChecker { object AbstractNullabilityChecker { // this method checks only nullability fun isPossibleSubtype(context: AbstractTypeCheckerContext, subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean = - context.runIsPossibleSubtype(subType, superType) + runIsPossibleSubtype(context, subType, superType) fun isSubtypeOfAny(context: TypeCheckerProviderContext, type: KotlinTypeMarker): Boolean = AbstractNullabilityChecker.isSubtypeOfAny( @@ -546,82 +570,93 @@ object AbstractNullabilityChecker { ) fun isSubtypeOfAny(context: AbstractTypeCheckerContext, type: KotlinTypeMarker): Boolean = - with(context) { - hasNotNullSupertype(type.lowerBoundIfFlexible(), SupertypesPolicy.LowerIfFlexible) + with(context.typeSystemContext) { + context.hasNotNullSupertype(type.lowerBoundIfFlexible(), SupertypesPolicy.LowerIfFlexible) } - private fun AbstractTypeCheckerContext.runIsPossibleSubtype(subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean { - if (AbstractTypeChecker.RUN_SLOW_ASSERTIONS) { - // it makes for case String? & Any <: String - assert(subType.isSingleClassifierType() || subType.typeConstructor().isIntersection() || subType.isAllowedTypeVariable) { - "Not singleClassifierType and not intersection subType: $subType" - } - assert(superType.isSingleClassifierType() || superType.isAllowedTypeVariable) { - "Not singleClassifierType superType: $superType" + private fun runIsPossibleSubtype(context: AbstractTypeCheckerContext, subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean = + with(context.typeSystemContext) { + if (AbstractTypeChecker.RUN_SLOW_ASSERTIONS) { + // it makes for case String? & Any <: String + assert( + subType.isSingleClassifierType() || subType.typeConstructor().isIntersection() || context.isAllowedTypeVariable( + subType + ) + ) { + "Not singleClassifierType and not intersection subType: $subType" + } + assert(superType.isSingleClassifierType() || context.isAllowedTypeVariable(superType)) { + "Not singleClassifierType superType: $superType" + } } + + // superType is actually nullable + if (superType.isMarkedNullable()) return true + + // i.e. subType is definitely not null + if (subType.isDefinitelyNotNullType()) return true + + // i.e. subType is captured type, projection of which is marked not-null + if (subType is CapturedTypeMarker && subType.isProjectionNotNull()) return true + + // i.e. subType is not-nullable + if (context.hasNotNullSupertype(subType, SupertypesPolicy.LowerIfFlexible)) return true + + // i.e. subType hasn't not-null supertype and isn't definitely not-null, but superType is definitely not-null + if (superType.isDefinitelyNotNullType()) return false + + // i.e subType hasn't not-null supertype, but superType has + if (context.hasNotNullSupertype(superType, SupertypesPolicy.UpperIfFlexible)) return false + + // both superType and subType hasn't not-null supertype and are not definitely not null. + + /** + * If we still don't know, it means, that superType is not classType, for example -- type parameter. + * + * For captured types with lower bound this function can give to you false result. Example: + * class A, A => \exist Q : Number <: Q. A + * isPossibleSubtype(Number, Q) = false. + * Such cases should be taken in to account in [NewKotlinTypeChecker.isSubtypeOf] (same for intersection types) + */ + + // classType cannot has special type in supertype list + if (subType.isClassType()) return false + + return hasPathByNotMarkedNullableNodes(context, subType, superType.typeConstructor()) } - // superType is actually nullable - if (superType.isMarkedNullable()) return true - - // i.e. subType is definitely not null - if (subType.isDefinitelyNotNullType()) return true - - // i.e. subType is captured type, projection of which is marked not-null - if (subType is CapturedTypeMarker && subType.isProjectionNotNull()) return true - - // i.e. subType is not-nullable - if (hasNotNullSupertype(subType, SupertypesPolicy.LowerIfFlexible)) return true - - // i.e. subType hasn't not-null supertype and isn't definitely not-null, but superType is definitely not-null - if (superType.isDefinitelyNotNullType()) return false - - // i.e subType hasn't not-null supertype, but superType has - if (hasNotNullSupertype(superType, SupertypesPolicy.UpperIfFlexible)) return false - - // both superType and subType hasn't not-null supertype and are not definitely not null. - - /** - * If we still don't know, it means, that superType is not classType, for example -- type parameter. - * - * For captured types with lower bound this function can give to you false result. Example: - * class A, A => \exist Q : Number <: Q. A - * isPossibleSubtype(Number, Q) = false. - * Such cases should be taken in to account in [NewKotlinTypeChecker.isSubtypeOf] (same for intersection types) - */ - - // classType cannot has special type in supertype list - if (subType.isClassType()) return false - - return hasPathByNotMarkedNullableNodes(subType, superType.typeConstructor()) - } - fun AbstractTypeCheckerContext.hasNotNullSupertype(type: SimpleTypeMarker, supertypesPolicy: SupertypesPolicy) = - anySupertype(type, { - (it.isClassType() && !it.isMarkedNullable()) || it.isDefinitelyNotNullType() - }) { - if (it.isMarkedNullable()) SupertypesPolicy.None else supertypesPolicy + with(typeSystemContext) { + anySupertype(type, { + (it.isClassType() && !it.isMarkedNullable()) || it.isDefinitelyNotNullType() + }) { + if (it.isMarkedNullable()) SupertypesPolicy.None else supertypesPolicy + } } fun TypeCheckerProviderContext.hasPathByNotMarkedNullableNodes(start: SimpleTypeMarker, end: TypeConstructorMarker) = - newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true) - .hasPathByNotMarkedNullableNodes(start, end) - - fun AbstractTypeCheckerContext.hasPathByNotMarkedNullableNodes(start: SimpleTypeMarker, end: TypeConstructorMarker) = - anySupertype( - start, - { isApplicableAsEndNode(it, end) }, - { if (it.isMarkedNullable()) SupertypesPolicy.None else SupertypesPolicy.LowerIfFlexible } + hasPathByNotMarkedNullableNodes( + newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true), start, end ) - private fun AbstractTypeCheckerContext.isApplicableAsEndNode(type: SimpleTypeMarker, end: TypeConstructorMarker): Boolean { - if (type.isNothing()) return true - if (type.isMarkedNullable()) return false + fun hasPathByNotMarkedNullableNodes(context: AbstractTypeCheckerContext, start: SimpleTypeMarker, end: TypeConstructorMarker) = + with(context.typeSystemContext) { + context.anySupertype( + start, + { isApplicableAsEndNode(context, it, end) }, + { if (it.isMarkedNullable()) SupertypesPolicy.None else SupertypesPolicy.LowerIfFlexible } + ) + } - if (isStubTypeEqualsToAnything && type.isStubType()) return true + private fun isApplicableAsEndNode(context: AbstractTypeCheckerContext, type: SimpleTypeMarker, end: TypeConstructorMarker): Boolean = + with(context.typeSystemContext) { + if (type.isNothing()) return true + if (type.isMarkedNullable()) return false - return areEqualTypeConstructors(type.typeConstructor(), end) - } + if (context.isStubTypeEqualsToAnything && type.isStubType()) return true + + return areEqualTypeConstructors(type.typeConstructor(), end) + } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java index b8323730d34..95df25b7532 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java @@ -393,24 +393,28 @@ public class OverridingUtil { "Should be the same number of type parameters: " + firstParameters + " vs " + secondParameters; NewKotlinTypeCheckerImpl typeChecker = new NewKotlinTypeCheckerImpl(kotlinTypeRefiner); - OverridingUtilTypeCheckerContext context = createTypeCheckerContext(firstParameters, secondParameters); + ClassicTypeCheckerContext context = createTypeCheckerContext(firstParameters, secondParameters); return new Pair(typeChecker, context); } @NotNull - private OverridingUtilTypeCheckerContext createTypeCheckerContext( + private ClassicTypeCheckerContext createTypeCheckerContext( @NotNull List firstParameters, @NotNull List secondParameters ) { - if (firstParameters.isEmpty()) return new OverridingUtilTypeCheckerContext(null); + if (firstParameters.isEmpty()) { + return (ClassicTypeCheckerContext) new OverridingUtilTypeSystemContext(null, equalityAxioms, kotlinTypeRefiner) + .newBaseTypeCheckerContext(true, true); + } Map matchingTypeConstructors = new HashMap(); for (int i = 0; i < firstParameters.size(); i++) { matchingTypeConstructors.put(firstParameters.get(i).getTypeConstructor(), secondParameters.get(i).getTypeConstructor()); } - return new OverridingUtilTypeCheckerContext(matchingTypeConstructors); + return (ClassicTypeCheckerContext) new OverridingUtilTypeSystemContext(matchingTypeConstructors, equalityAxioms, kotlinTypeRefiner) + .newBaseTypeCheckerContext(true, true); } @Nullable @@ -977,34 +981,6 @@ public class OverridingUtil { return maxVisibility; } - private class OverridingUtilTypeCheckerContext extends ClassicTypeCheckerContext { - private final @Nullable Map matchingTypeConstructors; - - public OverridingUtilTypeCheckerContext(@Nullable Map matchingTypeConstructors) { - super( - /* errorTypesEqualsToAnything = */ true, - /* stubTypesEqualsToAnything = */ true, - /* allowedTypeVariable = */ true, - kotlinTypeRefiner - ); - this.matchingTypeConstructors = matchingTypeConstructors; - } - - @Override - public boolean areEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b) { - return super.areEqualTypeConstructors(a, b) || areEqualTypeConstructorsByAxioms(a, b); - } - - private boolean areEqualTypeConstructorsByAxioms(@NotNull TypeConstructor a, @NotNull TypeConstructor b) { - if (equalityAxioms.equals(a, b)) return true; - if (matchingTypeConstructors == null) return false; - - TypeConstructor img1 = matchingTypeConstructors.get(a); - TypeConstructor img2 = matchingTypeConstructors.get(b); - return (img1 != null && img1.equals(b)) || (img2 != null && img2.equals(a)); - } - } - public static class OverrideCompatibilityInfo { public enum Result { OVERRIDABLE, diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtilTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtilTypeSystemContext.kt new file mode 100644 index 00000000000..46f0063ce70 --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtilTypeSystemContext.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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 + +import org.jetbrains.kotlin.types.AbstractTypeCheckerContext +import org.jetbrains.kotlin.types.TypeConstructor +import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerContext +import org.jetbrains.kotlin.types.checker.ClassicTypeSystemContext +import org.jetbrains.kotlin.types.checker.KotlinTypeChecker +import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner +import org.jetbrains.kotlin.types.model.TypeConstructorMarker + +class OverridingUtilTypeSystemContext( + val matchingTypeConstructors: Map?, + private val equalityAxioms: KotlinTypeChecker.TypeConstructorEquality, + val kotlinTypeRefiner: KotlinTypeRefiner +) : ClassicTypeSystemContext { + + override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean { + require(c1 is TypeConstructor) + require(c2 is TypeConstructor) + return super.areEqualTypeConstructors(c1, c2) || areEqualTypeConstructorsByAxioms(c1, c2) + } + + override fun newBaseTypeCheckerContext( + errorTypesEqualToAnything: Boolean, + stubTypesEqualToAnything: Boolean + ): AbstractTypeCheckerContext { + return ClassicTypeCheckerContext( + errorTypesEqualToAnything, + stubTypesEqualToAnything, + allowedTypeVariable = true, + kotlinTypeRefiner, + this + ) + } + + private fun areEqualTypeConstructorsByAxioms(a: TypeConstructor, b: TypeConstructor): Boolean { + if (equalityAxioms.equals(a, b)) return true + if (matchingTypeConstructors == null) return false + val img1 = matchingTypeConstructors[a] + val img2 = matchingTypeConstructors[b] + return img1 != null && img1 == b || img2 != null && img2 == a + } +} \ No newline at end of file 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 47b2463e5d8..cc0abecc465 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeCheckerContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeCheckerContext.kt @@ -16,24 +16,18 @@ package org.jetbrains.kotlin.types.checker -import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.SimpleTypeMarker -import org.jetbrains.kotlin.types.model.TypeConstructorMarker import org.jetbrains.kotlin.types.refinement.TypeRefinement open class ClassicTypeCheckerContext( val errorTypeEqualsToAnything: Boolean, val stubTypeEqualsToAnything: Boolean = true, val allowedTypeVariable: Boolean = true, - val kotlinTypeRefiner: KotlinTypeRefiner = KotlinTypeRefiner.Default -) : ClassicTypeSystemContext, AbstractTypeCheckerContext() { - - override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker { - require(type is KotlinType, type::errorMessage) - return NewKotlinTypeChecker.Default.transformToNewType(type.unwrap()) - } + val kotlinTypeRefiner: KotlinTypeRefiner = KotlinTypeRefiner.Default, + override val typeSystemContext: ClassicTypeSystemContext = SimpleClassicTypeSystemContext +) : AbstractTypeCheckerContext() { @OptIn(TypeRefinement::class) override fun refineType(type: KotlinTypeMarker): KotlinTypeMarker { @@ -47,25 +41,8 @@ open class ClassicTypeCheckerContext( override val isStubTypeEqualsToAnything: Boolean get() = stubTypeEqualsToAnything - override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean { - require(c1 is TypeConstructor, c1::errorMessage) - require(c2 is TypeConstructor, c2::errorMessage) - return areEqualTypeConstructors(c1, c2) - } - - 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 { - return classicSubstitutionSupertypePolicy(type) + return typeSystemContext.classicSubstitutionSupertypePolicy(type) } override val KotlinTypeMarker.isAllowedTypeVariable: Boolean get() = this is UnwrappedType && allowedTypeVariable && constructor is NewTypeVariableConstructor 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 4bc8700e92f..f929d3e2598 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -341,7 +341,7 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy errorTypesEqualToAnything: Boolean, stubTypesEqualToAnything: Boolean ): AbstractTypeCheckerContext { - return ClassicTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything) + return ClassicTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything, typeSystemContext = this) } override fun nullableNothingType(): SimpleTypeMarker { @@ -485,8 +485,8 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy } override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker { - require(type is UnwrappedType, type::errorMessage) - return NewKotlinTypeChecker.Default.transformToNewType(type) + require(type is KotlinType, type::errorMessage) + return NewKotlinTypeChecker.Default.transformToNewType(type.unwrap()) } override fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker { diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirAnalysisSessionComponent.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirAnalysisSessionComponent.kt index ea772b79def..c3e8ab530e8 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirAnalysisSessionComponent.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirAnalysisSessionComponent.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic +import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeTypeCheckerContext import org.jetbrains.kotlin.idea.frontend.api.diagnostics.KtDiagnostic @@ -33,6 +34,6 @@ internal interface KtFirAnalysisSessionComponent { fun createTypeCheckerContext() = ConeTypeCheckerContext( isErrorTypeEqualsToAnything = true, isStubTypeEqualsToAnything = true, - analysisSession.firResolveState.rootModuleSession //TODO use correct session here + analysisSession.firResolveState.rootModuleSession.typeContext //TODO use correct session here ) } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.kt index 0f83ed081d3..579be6e5685 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.kt @@ -52,11 +52,14 @@ import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoAfter import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.source.getPsi +import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerContext +import org.jetbrains.kotlin.types.checker.ClassicTypeSystemContext import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker +import org.jetbrains.kotlin.types.model.TypeConstructorMarker import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.ifEmpty import org.jetbrains.kotlin.utils.sure @@ -73,11 +76,16 @@ object KotlinIntroduceVariableHandler : RefactoringActionHandler { private var KtExpression.isOccurrence: Boolean by NotNullablePsiCopyableUserDataProperty(Key.create("OCCURRENCE"), false) private class TypeCheckerImpl(private val project: Project) : KotlinTypeChecker by KotlinTypeChecker.DEFAULT { - private inner class ContextImpl : ClassicTypeCheckerContext(false) { - override fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean = - compareDescriptors(project, a.declarationDescriptor, b.declarationDescriptor) + private inner class TypeSystemContextImpl : ClassicTypeSystemContext { + override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean { + require(c1 is TypeConstructor) + require(c2 is TypeConstructor) + return compareDescriptors(project, c1.declarationDescriptor, c2.declarationDescriptor) + } } + private inner class ContextImpl : ClassicTypeCheckerContext(false, typeSystemContext = TypeSystemContextImpl()) + override fun equalTypes(a: KotlinType, b: KotlinType): Boolean = with(NewKotlinTypeChecker.Default) { ContextImpl().equalTypes(a.unwrap(), b.unwrap()) }