Decouple TypeCheckerContext and TypeSystemContext

This commit is contained in:
Simon Ogorodnik
2021-02-04 05:14:29 +03:00
committed by TeamCityServer
parent 53a7dc1126
commit 3909e3c54c
32 changed files with 483 additions and 416 deletions
@@ -31,7 +31,7 @@ import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol 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.fir.types.*
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
@@ -317,4 +317,4 @@ val FirFunctionCall.isIterator
internal fun throwableClassLikeType(session: FirSession) = session.builtinTypes.throwableType.type internal fun throwableClassLikeType(session: FirSession) = session.builtinTypes.throwableType.type
fun ConeKotlinType.isSubtypeOfThrowable(session: FirSession) = fun ConeKotlinType.isSubtypeOfThrowable(session: FirSession) =
throwableClassLikeType(session).isSupertypeOf(session.typeCheckerContext, this.fullyExpandedType(session)) throwableClassLikeType(session).isSupertypeOf(session.typeContext, this.fullyExpandedType(session))
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.types.AbstractTypeChecker 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.min
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -63,18 +62,13 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
parameterPairs.mapValues { it.value.coneType } parameterPairs.mapValues { it.value.coneType }
) )
val typeCheckerContext = context.session.typeContext.newBaseTypeCheckerContext(
errorTypesEqualToAnything = false,
stubTypesEqualToAnything = false
)
parameterPairs.forEach { (proto, actual) -> parameterPairs.forEach { (proto, actual) ->
if (actual.source == null) { if (actual.source == null) {
// inferred types don't report INAPPLICABLE_CANDIDATE for type aliases! // inferred types don't report INAPPLICABLE_CANDIDATE for type aliases!
return@forEach 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) reporter.reportOn(actual.source, proto, actual.coneType, context)
return return
} }
@@ -82,7 +76,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
// we must analyze nested things like // we must analyze nested things like
// S<S<K, L>, T<K, L>>() // S<S<K, L>, T<K, L>>()
actual.coneType.safeAs<ConeClassLikeType>()?.let { actual.coneType.safeAs<ConeClassLikeType>()?.let {
val errorOccurred = analyzeTypeParameters(it, context, reporter, typeCheckerContext, actual.source) val errorOccurred = analyzeTypeParameters(it, context, reporter, context.session.typeContext, actual.source)
if (errorOccurred) { if (errorOccurred) {
return return
@@ -99,14 +93,14 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
// typealias A<G> = B<List<G>> // typealias A<G> = B<List<G>>
// val a = A<Int>() // val a = A<Int>()
when (calleeFir) { when (calleeFir) {
is FirConstructor -> analyzeConstructorCall(expression, substitutor, typeCheckerContext, reporter, context) is FirConstructor -> analyzeConstructorCall(expression, substitutor, context.session.typeContext, reporter, context)
} }
} }
private fun analyzeConstructorCall( private fun analyzeConstructorCall(
functionCall: FirQualifiedAccessExpression, functionCall: FirQualifiedAccessExpression,
callSiteSubstitutor: ConeSubstitutor, callSiteSubstitutor: ConeSubstitutor,
typeCheckerContext: AbstractTypeCheckerContext, typeSystemContext: ConeTypeContext,
reporter: DiagnosticReporter, reporter: DiagnosticReporter,
context: CheckerContext context: CheckerContext
) { ) {
@@ -157,7 +151,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
constructorsParameterPairs.forEach { (proto, actual) -> constructorsParameterPairs.forEach { (proto, actual) ->
// just in case // just in case
var intersection = typeCheckerContext.intersectTypes( var intersection = typeSystemContext.intersectTypes(
proto.fir.bounds.map { it.coneType } proto.fir.bounds.map { it.coneType }
).safeAs<ConeKotlinType>() ?: return@forEach ).safeAs<ConeKotlinType>() ?: return@forEach
@@ -167,7 +161,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
// substitute Int for G from // substitute Int for G from
// the example above // the example above
val target = callSiteSubstitutor.substituteOrSelf(actual) val target = callSiteSubstitutor.substituteOrSelf(actual)
val satisfiesBounds = AbstractTypeChecker.isSubtypeOf(typeCheckerContext, target, intersection) val satisfiesBounds = AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, intersection)
if (!satisfiesBounds) { if (!satisfiesBounds) {
reporter.reportOn(functionCall.source, proto, actual, context) reporter.reportOn(functionCall.source, proto, actual, context)
@@ -187,7 +181,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
type: ConeClassLikeType, type: ConeClassLikeType,
context: CheckerContext, context: CheckerContext,
reporter: DiagnosticReporter, reporter: DiagnosticReporter,
typeCheckerContext: AbstractTypeCheckerContext, typeSystemContext: ConeTypeContext,
reportTarget: FirSourceElement? reportTarget: FirSourceElement?
): Boolean { ): Boolean {
val prototypeClass = type.lookupTag.toSymbol(context.session) val prototypeClass = type.lookupTag.toSymbol(context.session)
@@ -218,13 +212,13 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
) )
parameterPairs.forEach { (proto, actual) -> parameterPairs.forEach { (proto, actual) ->
if (!satisfiesBounds(proto, actual.type, substitutor, typeCheckerContext)) { if (!satisfiesBounds(proto, actual.type, substitutor, typeSystemContext)) {
// should report on the parameter instead! // should report on the parameter instead!
reporter.reportOn(reportTarget, proto, actual, context) reporter.reportOn(reportTarget, proto, actual, context)
return true return true
} }
val errorOccurred = analyzeTypeParameters(actual, context, reporter, typeCheckerContext, reportTarget) val errorOccurred = analyzeTypeParameters(actual, context, reporter, typeSystemContext, reportTarget)
if (errorOccurred) { if (errorOccurred) {
return true return true
@@ -242,14 +236,14 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
prototypeSymbol: FirTypeParameterSymbol, prototypeSymbol: FirTypeParameterSymbol,
target: ConeKotlinType, target: ConeKotlinType,
substitutor: ConeSubstitutor, substitutor: ConeSubstitutor,
typeCheckerContext: AbstractTypeCheckerContext typeSystemContext: ConeTypeContext
): Boolean { ): Boolean {
var intersection = typeCheckerContext.intersectTypes( var intersection = typeSystemContext.intersectTypes(
prototypeSymbol.fir.bounds.map { it.coneType } prototypeSymbol.fir.bounds.map { it.coneType }
).safeAs<ConeKotlinType>() ?: return true ).safeAs<ConeKotlinType>() ?: return true
intersection = substitutor.substituteOrSelf(intersection) intersection = substitutor.substituteOrSelf(intersection)
return AbstractTypeChecker.isSubtypeOf(typeCheckerContext, target, intersection) return AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, intersection, stubTypesEqualToAnything = false)
} }
private fun DiagnosticReporter.reportOn( private fun DiagnosticReporter.reportOn(
@@ -30,6 +30,9 @@ import org.jetbrains.kotlin.fir.types.FirCorrespondingSupertypesCache
@OptIn(SessionConfiguration::class) @OptIn(SessionConfiguration::class)
fun FirSession.registerCommonComponents(languageVersionSettings: LanguageVersionSettings) { fun FirSession.registerCommonComponents(languageVersionSettings: LanguageVersionSettings) {
register(FirLanguageSettingsComponent::class, FirLanguageSettingsComponent(languageVersionSettings))
register(InferenceComponents::class, InferenceComponents(this))
register(FirDeclaredMemberScopeProvider::class, FirDeclaredMemberScopeProvider()) register(FirDeclaredMemberScopeProvider::class, FirDeclaredMemberScopeProvider())
register(FirCorrespondingSupertypesCache::class, FirCorrespondingSupertypesCache(this)) register(FirCorrespondingSupertypesCache::class, FirCorrespondingSupertypesCache(this))
register(FirDefaultParametersResolver::class, FirDefaultParametersResolver()) register(FirDefaultParametersResolver::class, FirDefaultParametersResolver())
@@ -38,8 +41,6 @@ fun FirSession.registerCommonComponents(languageVersionSettings: LanguageVersion
register(FirRegisteredPluginAnnotations::class, FirRegisteredPluginAnnotations.create(this)) register(FirRegisteredPluginAnnotations::class, FirRegisteredPluginAnnotations.create(this))
register(FirPredicateBasedProvider::class, FirPredicateBasedProvider.create(this)) register(FirPredicateBasedProvider::class, FirPredicateBasedProvider.create(this))
register(GeneratedClassIndex::class, GeneratedClassIndex.create()) register(GeneratedClassIndex::class, GeneratedClassIndex.create())
register(FirLanguageSettingsComponent::class, FirLanguageSettingsComponent(languageVersionSettings))
register(InferenceComponents::class, InferenceComponents(this))
} }
@OptIn(SessionConfiguration::class) @OptIn(SessionConfiguration::class)
@@ -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 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 || if (argument.typeRef !is FirResolvedTypeRef ||
AbstractTypeChecker.isSubtypeOf( AbstractTypeChecker.isSubtypeOf(
session.inferenceComponents.ctx, session.inferenceComponents.ctx.newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true),
argument.typeRef.coneType, argument.typeRef.coneType,
parameter.returnTypeRef.coneType, parameter.returnTypeRef.coneType,
isFromNullabilityConstraint = true isFromNullabilityConstraint = true
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.resolveSupertypesInTheAir import org.jetbrains.kotlin.fir.resolve.transformers.resolveSupertypesInTheAir
import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName 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(session.typeContext) {
with(context) {
val typeConstructor = typeConstructor() val typeConstructor = typeConstructor()
typeConstructor.getPrimitiveType()?.let { return JvmPrimitiveType.get(it).wrapperFqName.asString() } typeConstructor.getPrimitiveType()?.let { return JvmPrimitiveType.get(it).wrapperFqName.asString() }
typeConstructor.getPrimitiveArrayType()?.let { return JvmPrimitiveType.get(it).javaKeywordName + "[]" } typeConstructor.getPrimitiveArrayType()?.let { return JvmPrimitiveType.get(it).javaKeywordName + "[]" }
@@ -6,21 +6,19 @@
package org.jetbrains.kotlin.fir package org.jetbrains.kotlin.fir
import org.jetbrains.kotlin.descriptors.Visibility 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.ScopeSession
import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents
import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
import org.jetbrains.kotlin.fir.types.ConeInferenceContext import org.jetbrains.kotlin.fir.types.ConeInferenceContext
import org.jetbrains.kotlin.fir.types.ConeTypeCheckerContext
val FirSession.typeContext: ConeInferenceContext val FirSession.typeContext: ConeInferenceContext
get() = inferenceComponents.ctx get() = inferenceComponents.ctx
val FirSession.typeCheckerContext: ConeTypeCheckerContext
get() = inferenceComponents.ctx
/** /**
* Returns the list of functions that overridden by given * Returns the list of functions that overridden by given
*/ */
@@ -17,7 +17,6 @@ import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolvedTypeDeclarati
import org.jetbrains.kotlin.fir.returnExpressions import org.jetbrains.kotlin.fir.returnExpressions
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.typeCheckerContext
import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.ClassId 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.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.model.CaptureStatus import org.jetbrains.kotlin.types.model.CaptureStatus
import org.jetbrains.kotlin.types.model.TypeSystemCommonSuperTypesContext
import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.jetbrains.kotlin.utils.addToStdlib.runIf
fun Candidate.resolveArgumentExpression( fun Candidate.resolveArgumentExpression(
@@ -416,7 +416,10 @@ fun FirExpression.isFunctional(
val returnTypeCompatible = val returnTypeCompatible =
expectedReturnType is ConeTypeParameterType || expectedReturnType is ConeTypeParameterType ||
AbstractTypeChecker.isSubtypeOf( AbstractTypeChecker.isSubtypeOf(
session.inferenceComponents.ctx, session.inferenceComponents.ctx.newBaseTypeCheckerContext(
errorTypesEqualToAnything = false,
stubTypesEqualToAnything = true
),
invokeSymbol.fir.returnTypeRef.coneType, invokeSymbol.fir.returnTypeRef.coneType,
expectedReturnType, expectedReturnType,
isFromNullabilityConstraint = false isFromNullabilityConstraint = false
@@ -433,7 +436,10 @@ fun FirExpression.isFunctional(
val expectedParameterType = expectedParameter!!.lowerBoundIfFlexible() val expectedParameterType = expectedParameter!!.lowerBoundIfFlexible()
expectedParameterType is ConeTypeParameterType || expectedParameterType is ConeTypeParameterType ||
AbstractTypeChecker.isSubtypeOf( AbstractTypeChecker.isSubtypeOf(
session.inferenceComponents.ctx, session.inferenceComponents.ctx.newBaseTypeCheckerContext(
errorTypesEqualToAnything = false,
stubTypesEqualToAnything = true
),
invokeParameter.returnTypeRef.coneType, invokeParameter.returnTypeRef.coneType,
expectedParameterType, expectedParameterType,
isFromNullabilityConstraint = false isFromNullabilityConstraint = false
@@ -488,7 +494,7 @@ internal fun captureFromTypeParameterUpperBoundIfNeeded(
val simplifiedArgumentType = argumentType.lowerBoundIfFlexible() as? ConeTypeParameterType ?: return argumentType val simplifiedArgumentType = argumentType.lowerBoundIfFlexible() as? ConeTypeParameterType ?: return argumentType
val typeParameter = simplifiedArgumentType.lookupTag.typeParameterSymbol.fir val typeParameter = simplifiedArgumentType.lookupTag.typeParameterSymbol.fir
val context = session.typeCheckerContext val context = session.typeContext
val chosenSupertype = typeParameter.bounds.map { it.coneType } val chosenSupertype = typeParameter.bounds.map { it.coneType }
.singleOrNull { it.hasSupertypeWithGivenClassId(expectedTypeClassId, context) } ?: return argumentType .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) { return with(context) {
anySuperTypeConstructor { anySuperTypeConstructor {
it is ConeClassLikeLookupTag && it.classId == classId it is ConeClassLikeLookupTag && it.classId == classId
@@ -7,14 +7,16 @@ package org.jetbrains.kotlin.fir.resolve.inference
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.types.ConeInferenceContext 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.components.*
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
import org.jetbrains.kotlin.types.AbstractTypeApproximator import org.jetbrains.kotlin.types.AbstractTypeApproximator
@NoMutableState @NoMutableState
class InferenceComponents(val session: FirSession) : FirSessionComponent { 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 approximator: AbstractTypeApproximator = object : AbstractTypeApproximator(ctx) {}
val trivialConstraintTypeInferenceOracle = TrivialConstraintTypeInferenceOracle.create(ctx) val trivialConstraintTypeInferenceOracle = TrivialConstraintTypeInferenceOracle.create(ctx)
@@ -496,7 +496,8 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
if (baseType !is ConeClassLikeType) return this if (baseType !is ConeClassLikeType) return this
val baseFirClass = baseType.lookupTag.toSymbol(session)?.fir ?: 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 // If actual type of declaration is more specific than bare type then we should just find
// corresponding supertype with proper arguments // corresponding supertype with proper arguments
with(session.typeContext) { with(session.typeContext) {
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.AbstractTypeChecker
@@ -33,7 +34,7 @@ class FirTypeIntersectionScope private constructor(
private val absentProperties: MutableSet<Name> = mutableSetOf() private val absentProperties: MutableSet<Name> = mutableSetOf()
private val absentClassifiers: MutableSet<Name> = mutableSetOf() private val absentClassifiers: MutableSet<Name> = mutableSetOf()
private val typeContext = ConeTypeCheckerContext(isErrorTypeEqualsToAnything = false, isStubTypeEqualsToAnything = false, session) private val typeCheckerContext = session.typeContext.newBaseTypeCheckerContext(false, false)
private val overriddenSymbols: MutableMap<FirCallableSymbol<*>, Collection<MemberWithBaseScope<out FirCallableSymbol<*>>>> = private val overriddenSymbols: MutableMap<FirCallableSymbol<*>, Collection<MemberWithBaseScope<out FirCallableSymbol<*>>>> =
mutableMapOf() mutableMapOf()
@@ -357,7 +358,7 @@ class FirTypeIntersectionScope private constructor(
require(bFir is FirProperty) { "b is " + b.javaClass } require(bFir is FirProperty) { "b is " + b.javaClass }
// TODO: if (!OverridingUtil.isAccessorMoreSpecific(pa.getSetter(), pb.getSetter())) return false // TODO: if (!OverridingUtil.isAccessorMoreSpecific(pa.getSetter(), pb.getSetter())) return false
return if (aFir.isVar && bFir.isVar) { 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 } else { // both vals or var vs val: val can't be more specific then var
!(!aFir.isVar && bFir.isVar) && isTypeMoreSpecific(aReturnType, bReturnType) !(!aFir.isVar && bFir.isVar) && isTypeMoreSpecific(aReturnType, bReturnType)
} }
@@ -366,7 +367,7 @@ class FirTypeIntersectionScope private constructor(
} }
private fun isTypeMoreSpecific(a: ConeKotlinType, b: ConeKotlinType): Boolean = private fun isTypeMoreSpecific(a: ConeKotlinType, b: ConeKotlinType): Boolean =
AbstractTypeChecker.isSubtypeOf(typeContext as AbstractTypeCheckerContext, a, b) AbstractTypeChecker.isSubtypeOf(typeCheckerContext as AbstractTypeCheckerContext, a, b)
private fun <D : FirCallableSymbol<*>> findMemberWithMaxVisibility(members: Collection<MemberWithBaseScope<D>>): MemberWithBaseScope<D> { private fun <D : FirCallableSymbol<*>> findMemberWithMaxVisibility(members: Collection<MemberWithBaseScope<D>>): MemberWithBaseScope<D> {
assert(members.isNotEmpty()) assert(members.isNotEmpty())
@@ -97,8 +97,8 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo
override fun newBaseTypeCheckerContext( override fun newBaseTypeCheckerContext(
errorTypesEqualToAnything: Boolean, errorTypesEqualToAnything: Boolean,
stubTypesEqualToAnything: Boolean stubTypesEqualToAnything: Boolean
): AbstractTypeCheckerContext = ): ConeTypeCheckerContext =
ConeTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything, session) ConeTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything, this)
override fun KotlinTypeMarker.canHaveUndefinedNullability(): Boolean { override fun KotlinTypeMarker.canHaveUndefinedNullability(): Boolean {
require(this is ConeKotlinType) require(this is ConeKotlinType)
@@ -483,4 +483,12 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo
return session.symbolProvider.getClassLikeSymbolByFqName(classId)?.toLookupTag() return session.symbolProvider.getClassLikeSymbolByFqName(classId)?.toLookupTag()
?: error("Can't find KFunction type") ?: error("Can't find KFunction type")
} }
override fun createTypeWithAlternativeForIntersectionResult(
firstCandidate: KotlinTypeMarker,
secondCandidate: KotlinTypeMarker
): KotlinTypeMarker {
// TODO
return firstCandidate
}
} }
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext.SupertypesPolicy.*
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.types.model.*
@@ -540,10 +541,13 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
class ConeTypeCheckerContext( class ConeTypeCheckerContext(
override val isErrorTypeEqualsToAnything: Boolean, override val isErrorTypeEqualsToAnything: Boolean,
override val isStubTypeEqualsToAnything: Boolean, override val isStubTypeEqualsToAnything: Boolean,
override val session: FirSession override val typeSystemContext: ConeInferenceContext
) : AbstractTypeCheckerContext(), ConeInferenceContext { ) : AbstractTypeCheckerContext() {
override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy {
if (type.argumentsCount() == 0) return SupertypesPolicy.LowerIfFlexible val session: FirSession = typeSystemContext.session
override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy = with(typeSystemContext) {
if (type.argumentsCount() == 0) return LowerIfFlexible
require(type is ConeKotlinType) require(type is ConeKotlinType)
val declaration = when (type) { val declaration = when (type) {
is ConeClassLikeType -> type.lookupTag.toSymbol(session)?.firUnsafe<FirClassLikeDeclaration<*>>() is ConeClassLikeType -> type.lookupTag.toSymbol(session)?.firUnsafe<FirClassLikeDeclaration<*>>()
@@ -560,7 +564,7 @@ class ConeTypeCheckerContext(
} else { } else {
ConeSubstitutor.Empty ConeSubstitutor.Empty
} }
return object : SupertypesPolicy.DoCustomTransform() { return object : DoCustomTransform() {
override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker): SimpleTypeMarker { override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker): SimpleTypeMarker {
val lowerBound = type.lowerBoundIfFlexible() val lowerBound = type.lowerBoundIfFlexible()
require(lowerBound is ConeKotlinType) 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<ConeInferenceContext>.prepareType(type)
}
override fun refineType(type: KotlinTypeMarker): KotlinTypeMarker { override fun refineType(type: KotlinTypeMarker): KotlinTypeMarker {
return prepareType(type) return typeSystemContext.prepareType(type)
} }
override val KotlinTypeMarker.isAllowedTypeVariable: Boolean override val KotlinTypeMarker.isAllowedTypeVariable: Boolean
get() = this is ConeKotlinType && this is ConeTypeVariableType 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
}
} }
@@ -13,10 +13,12 @@ import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRefsOwner
import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol 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.AbstractTypeCheckerContext
import org.jetbrains.kotlin.types.model.CaptureStatus import org.jetbrains.kotlin.types.model.CaptureStatus
import org.jetbrains.kotlin.types.model.SimpleTypeMarker import org.jetbrains.kotlin.types.model.SimpleTypeMarker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.model.TypeSystemContext
@ThreadSafeMutableState @ThreadSafeMutableState
class FirCorrespondingSupertypesCache(private val session: FirSession) : FirSessionComponent { class FirCorrespondingSupertypesCache(private val session: FirSession) : FirSessionComponent {
@@ -28,9 +30,13 @@ class FirCorrespondingSupertypesCache(private val session: FirSession) : FirSess
): List<ConeClassLikeType>? { ): List<ConeClassLikeType>? {
if (type !is ConeClassLikeType || supertypeConstructor !is ConeClassLikeLookupTag) return null 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 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) { if (lookupTag !in cache) {
cache[lookupTag] = computeSupertypesMap(lookupTag, context) 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 val resultTypes = cache[lookupTag]?.getOrDefault(supertypeConstructor, emptyList()) ?: return null
if (type.typeArguments.isEmpty()) return resultTypes if (type.typeArguments.isEmpty()) return resultTypes
val capturedType = captureType(type, context) val capturedType = captureType(type, context.typeSystemContext)
val substitutionSupertypePolicy = context.substitutionSupertypePolicy(capturedType) val substitutionSupertypePolicy = context.substitutionSupertypePolicy(capturedType)
return resultTypes.map { return resultTypes.map {
substitutionSupertypePolicy.transformType(context, it) as ConeClassLikeType substitutionSupertypePolicy.transformType(context, it) as ConeClassLikeType
} }
} }
private fun captureType(type: ConeClassLikeType, context: ConeTypeCheckerContext): ConeClassLikeType = private fun captureType(type: ConeClassLikeType, typeSystemContext: ConeTypeContext): ConeClassLikeType =
(context.captureFromArguments(type, CaptureStatus.FOR_SUBTYPING) ?: type) as ConeClassLikeType (typeSystemContext.captureFromArguments(type, CaptureStatus.FOR_SUBTYPING) ?: type) as ConeClassLikeType
private fun computeSupertypesMap( private fun computeSupertypesMap(
subtypeLookupTag: ConeClassLikeLookupTag, subtypeLookupTag: ConeClassLikeLookupTag,
@@ -82,12 +88,13 @@ class FirCorrespondingSupertypesCache(private val session: FirSession) : FirSess
context: ConeTypeCheckerContext context: ConeTypeCheckerContext
): AbstractTypeCheckerContext.SupertypesPolicy { ): AbstractTypeCheckerContext.SupertypesPolicy {
val supertypeLookupTag = (supertype as ConeClassLikeType).lookupTag 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) resultingMap[supertypeLookupTag] = listOf(captured)
return when { return when {
with(context) { captured.argumentsCount() } == 0 -> { with(context.typeSystemContext) { captured.argumentsCount() } == 0 -> {
AbstractTypeCheckerContext.SupertypesPolicy.LowerIfFlexible AbstractTypeCheckerContext.SupertypesPolicy.LowerIfFlexible
} }
else -> { else -> {
@@ -1374,7 +1374,7 @@ class ExpressionCodegen(
val reifiedTypeInliner = ReifiedTypeInliner( val reifiedTypeInliner = ReifiedTypeInliner(
mappings, mappings,
IrInlineIntrinsicsSupport(context, typeMapper), IrInlineIntrinsicsSupport(context, typeMapper),
IrTypeCheckerContext(context.irBuiltIns), IrTypeSystemContextImpl(context.irBuiltIns),
state.languageVersionSettings, state.languageVersionSettings,
state.unifiedNullChecks, state.unifiedNullChecks,
) )
@@ -39,7 +39,7 @@ import org.jetbrains.kotlin.ir.types.isKClass as isKClassImpl
import org.jetbrains.kotlin.ir.util.isSuspendFunction as isSuspendFunctionImpl import org.jetbrains.kotlin.ir.util.isSuspendFunction as isSuspendFunctionImpl
class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapperBase(), TypeMappingContext<JvmSignatureWriter> { class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapperBase(), TypeMappingContext<JvmSignatureWriter> {
internal val typeSystem = IrTypeCheckerContext(context.irBuiltIns) internal val typeSystem = IrTypeSystemContextImpl(context.irBuiltIns)
override val typeContext: TypeSystemCommonBackendContextForTypeMapping = IrTypeCheckerContextForTypeMapping(typeSystem, context) override val typeContext: TypeSystemCommonBackendContextForTypeMapping = IrTypeCheckerContextForTypeMapping(typeSystem, context)
override fun mapClass(classifier: ClassifierDescriptor): Type = override fun mapClass(classifier: ClassifierDescriptor): Type =
@@ -229,7 +229,13 @@ internal class CollectionStubMethodLowering(val context: JvmBackendContext) : Cl
} }
private fun createTypeChecker(overrideFun: IrSimpleFunction, parentFun: IrSimpleFunction): AbstractTypeCheckerContext = 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( private fun areTypeParametersEquivalent(
overrideFun: IrSimpleFunction, overrideFun: IrSimpleFunction,
@@ -425,14 +425,14 @@ class IrOverridingUtil(
return if (a == null || b == null) true else isVisibilityMoreSpecific(a, b) 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) 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) AbstractTypeChecker.equalTypes(this as AbstractTypeCheckerContext, a, b)
private fun createTypeChecker(a: List<IrTypeParameter>, b: List<IrTypeParameter>) = private fun createTypeChecker(a: List<IrTypeParameter>, b: List<IrTypeParameter>) =
IrTypeCheckerContextWithAdditionalAxioms(irBuiltIns, a, b) IrTypeCheckerContext(IrTypeSystemContextWithAdditionalAxioms(irBuiltIns, a, b))
private fun isReturnTypeMoreSpecific( private fun isReturnTypeMoreSpecific(
a: IrOverridableMember, a: IrOverridableMember,
@@ -661,10 +661,12 @@ class IrOverridingUtil(
} }
val typeCheckerContext = val typeCheckerContext =
IrTypeCheckerContextWithAdditionalAxioms( IrTypeCheckerContext(
irBuiltIns, IrTypeSystemContextWithAdditionalAxioms(
superTypeParameters, irBuiltIns,
subTypeParameters superTypeParameters,
subTypeParameters
)
) )
/* TODO: check the bounds. See OverridingUtil.areTypeParametersEquivalent() /* TODO: check the bounds. See OverridingUtil.areTypeParametersEquivalent()
@@ -10,7 +10,9 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
import org.jetbrains.kotlin.types.model.* 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 { override fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy.DoCustomTransform {
require(type is IrSimpleType) require(type is IrSimpleType)
@@ -30,32 +32,4 @@ open class IrTypeCheckerContext(override val irBuiltIns: IrBuiltIns) : IrTypeSys
override val KotlinTypeMarker.isAllowedTypeVariable: Boolean override val KotlinTypeMarker.isAllowedTypeVariable: Boolean
get() = false 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")
}
} }
@@ -9,11 +9,11 @@ import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.types.model.TypeConstructorMarker import org.jetbrains.kotlin.types.model.TypeConstructorMarker
open class IrTypeCheckerContextWithAdditionalAxioms( class IrTypeSystemContextWithAdditionalAxioms(
override val irBuiltIns: IrBuiltIns, override val irBuiltIns: IrBuiltIns,
firstParameters: List<IrTypeParameter>, firstParameters: List<IrTypeParameter>,
secondParameters: List<IrTypeParameter> secondParameters: List<IrTypeParameter>
) : IrTypeCheckerContext(irBuiltIns) { ) : IrTypeSystemContext {
init { init {
assert(firstParameters.size == secondParameters.size) { assert(firstParameters.size == secondParameters.size) {
"different length of type parameter lists: $firstParameters vs $secondParameters" "different length of type parameter lists: $firstParameters vs $secondParameters"
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.types.model.*
@@ -454,6 +455,39 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
val irClass = (this as IrType).classOrNull?.owner val irClass = (this as IrType).classOrNull?.owner
return irClass != null && (irClass.isInterface || irClass.isAnnotationClass) 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<IrTypeParameter> { fun extractTypeParameters(parent: IrDeclarationParent): List<IrTypeParameter> {
@@ -480,3 +514,6 @@ fun extractTypeParameters(parent: IrDeclarationParent): List<IrTypeParameter> {
} }
return result return result
} }
class IrTypeSystemContextImpl(override val irBuiltIns: IrBuiltIns) : IrTypeSystemContext
@@ -32,7 +32,11 @@ fun IrType.isSubtypeOfClass(superClass: IrClassSymbol): Boolean {
} }
fun IrType.isSubtypeOf(superType: IrType, irBuiltIns: IrBuiltIns): 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 = fun IrType.isNullable(): Boolean =
@@ -267,9 +267,7 @@ object NewCommonSuperTypeCalculator {
* but it is too complicated and we will return not so accurate type: CS(List<Int>, List<Double>, List<String>) * but it is too complicated and we will return not so accurate type: CS(List<Int>, List<Double>, List<String>)
*/ */
val correspondingSuperTypes = types.flatMap { val correspondingSuperTypes = types.flatMap {
with(AbstractTypeChecker) { AbstractTypeChecker.findCorrespondingSupertypes(typeCheckerContext, it, constructor)
typeCheckerContext.findCorrespondingSupertypes(it, constructor)
}
} }
val arguments = ArrayList<TypeArgumentMarker>(constructor.parametersCount()) val arguments = ArrayList<TypeArgumentMarker>(constructor.parametersCount())
@@ -10,7 +10,8 @@ import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.types.model.*
abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheckerContext(), TypeSystemInferenceExtensionContext { abstract class AbstractTypeCheckerContextForConstraintSystem(override val typeSystemContext: TypeSystemInferenceExtensionContext) :
AbstractTypeCheckerContext() {
override val KotlinTypeMarker.isAllowedTypeVariable: Boolean override val KotlinTypeMarker.isAllowedTypeVariable: Boolean
get() = false get() = false
@@ -36,21 +37,22 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck
abstract fun addEqualityConstraint(typeVariable: TypeConstructorMarker, type: KotlinTypeMarker) abstract fun addEqualityConstraint(typeVariable: TypeConstructorMarker, type: KotlinTypeMarker)
override fun getLowerCapturedTypePolicy(subType: SimpleTypeMarker, superType: CapturedTypeMarker): LowerCapturedTypePolicy { override fun getLowerCapturedTypePolicy(subType: SimpleTypeMarker, superType: CapturedTypeMarker): LowerCapturedTypePolicy =
return when { with(typeSystemContext) {
isMyTypeVariable(subType) -> { return when {
val projection = superType.typeConstructorProjection() isMyTypeVariable(subType) -> {
val type = projection.getType().asSimpleType() val projection = superType.typeConstructorProjection()
if (projection.getVariance() == TypeVariance.IN && type != null && isMyTypeVariable(type)) { val type = projection.getType().asSimpleType()
LowerCapturedTypePolicy.CHECK_ONLY_LOWER if (projection.getVariance() == TypeVariance.IN && type != null && isMyTypeVariable(type)) {
} else { LowerCapturedTypePolicy.CHECK_ONLY_LOWER
LowerCapturedTypePolicy.SKIP_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 * 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 // we should strip annotation's because we have incorporation operation and they should be not affected
val mySubType = 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 = 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) val result = internalAddSubtypeConstraint(mySubType, mySuperType, isFromNullabilityConstraint)
if (!hasExact) return result if (!hasExact) return result
@@ -83,7 +87,7 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck
return (result ?: true) && (result2 ?: true) 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 typeMarker = type.asSimpleType()?.asCapturedType() ?: return null
val projection = typeMarker.typeConstructorProjection() val projection = typeMarker.typeConstructorProjection()
@@ -98,10 +102,10 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck
} }
private fun KotlinTypeMarker.isTypeVariableWithExact() = private fun KotlinTypeMarker.isTypeVariableWithExact() =
hasExactAnnotation() && anyBound(this@AbstractTypeCheckerContextForConstraintSystem::isMyTypeVariable) with(typeSystemContext) { hasExactAnnotation() } && anyBound(this@AbstractTypeCheckerContextForConstraintSystem::isMyTypeVariable)
private fun KotlinTypeMarker.isTypeVariableWithNoInfer() = private fun KotlinTypeMarker.isTypeVariableWithNoInfer() =
hasNoInferAnnotation() && anyBound(this@AbstractTypeCheckerContextForConstraintSystem::isMyTypeVariable) with(typeSystemContext) { hasNoInferAnnotation() } && anyBound(this@AbstractTypeCheckerContextForConstraintSystem::isMyTypeVariable)
private fun internalAddSubtypeConstraint( private fun internalAddSubtypeConstraint(
subType: KotlinTypeMarker, subType: KotlinTypeMarker,
@@ -128,32 +132,33 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck
} }
// extract type variable only from type like Captured(out T) // 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() val projection = typeMarker.typeConstructorProjection()
if (projection.isStarProjection()) return null if (projection.isStarProjection()) return null
if (projection.getVariance() == TypeVariance.IN) { if (projection.getVariance() == TypeVariance.IN) {
val type = projection.getType().asSimpleType() ?: return null val type = projection.getType().asSimpleType() ?: return null
if (isMyTypeVariable(type)) { if (isMyTypeVariable(type)) {
simplifyLowerConstraint(type, superType) simplifyLowerConstraint(type, superType)
if (isMyTypeVariable(superType.asSimpleType() ?: return null)) { if (isMyTypeVariable(superType.asSimpleType() ?: return null)) {
addLowerConstraint(superType.typeConstructor(), nullableAnyType()) addLowerConstraint(superType.typeConstructor(), nullableAnyType())
}
} }
return null
} }
return null
}
return if (projection.getVariance() == TypeVariance.OUT) { return if (projection.getVariance() == TypeVariance.OUT) {
val type = projection.getType() val type = projection.getType()
when { when {
type is SimpleTypeMarker && isMyTypeVariable(type) -> type.asSimpleType() type is SimpleTypeMarker && isMyTypeVariable(type) -> type.asSimpleType()
type is FlexibleTypeMarker && isMyTypeVariable(type.lowerBound()) -> type.asFlexibleType()?.lowerBound() type is FlexibleTypeMarker && isMyTypeVariable(type.lowerBound()) -> type.asFlexibleType()?.lowerBound()
else -> null else -> null
} }
} else null } else null
} }
/** /**
* Foo <: T -- leave as is * Foo <: T -- leave as is
@@ -196,7 +201,7 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck
typeVariable: KotlinTypeMarker, typeVariable: KotlinTypeMarker,
subType: KotlinTypeMarker, subType: KotlinTypeMarker,
isFromNullabilityConstraint: Boolean = false isFromNullabilityConstraint: Boolean = false
): Boolean { ): Boolean = with(typeSystemContext) {
val lowerConstraint = when (typeVariable) { val lowerConstraint = when (typeVariable) {
is SimpleTypeMarker -> is SimpleTypeMarker ->
/* /*
@@ -256,7 +261,7 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck
return true return true
} }
private fun assertFlexibleTypeVariable(typeVariable: FlexibleTypeMarker) { private fun assertFlexibleTypeVariable(typeVariable: FlexibleTypeMarker) = with(typeSystemContext) {
assert(typeVariable.lowerBound().typeConstructor() == typeVariable.upperBound().typeConstructor()) { assert(typeVariable.lowerBound().typeConstructor() == typeVariable.upperBound().typeConstructor()) {
"Flexible type variable ($typeVariable) should have bounds with the same type constructor, i.e. (T..T?)" "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 <=> T <: Foo && Nothing? <: Foo
* T <: Foo -- leave as is * 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 typeVariableLowerBound = typeVariable.lowerBoundIfFlexible()
val simplifiedSuperType = if (typeVariableLowerBound.isDefinitelyNotNullType()) { val simplifiedSuperType = if (typeVariableLowerBound.isDefinitelyNotNullType()) {
superType.withNullability(true) superType.withNullability(true)
@@ -279,37 +284,38 @@ abstract class AbstractTypeCheckerContextForConstraintSystem : AbstractTypeCheck
if (typeVariableLowerBound.isMarkedNullable()) { if (typeVariableLowerBound.isMarkedNullable()) {
// here is important that superType is singleClassifierType // here is important that superType is singleClassifierType
return simplifiedSuperType.anyBound(this::isMyTypeVariable) || return simplifiedSuperType.anyBound(::isMyTypeVariable) ||
isSubtypeOfByTypeChecker(nullableNothingType(), simplifiedSuperType) isSubtypeOfByTypeChecker(nullableNothingType(), simplifiedSuperType)
} }
return true return true
} }
private fun simplifyConstraintForPossibleIntersectionSubType(subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean? { private fun simplifyConstraintForPossibleIntersectionSubType(subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean? =
@Suppress("NAME_SHADOWING") with(typeSystemContext) {
val subType = subType.lowerBoundIfFlexible() @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 // TODO: may be we lose flexibility here
val subIntersectionTypes = (subType.typeConstructor().supertypes()).map { it.lowerBoundIfFlexible() } val subIntersectionTypes = (subType.typeConstructor().supertypes()).map { it.lowerBoundIfFlexible() }
val typeVariables = subIntersectionTypes.filter(this::isMyTypeVariable).takeIf { it.isNotEmpty() } ?: return null val typeVariables = subIntersectionTypes.filter(::isMyTypeVariable).takeIf { it.isNotEmpty() } ?: return null
val notTypeVariables = subIntersectionTypes.filterNot(this::isMyTypeVariable) val notTypeVariables = subIntersectionTypes.filterNot(::isMyTypeVariable)
// todo: may be we can do better then that. // todo: may be we can do better then that.
if (notTypeVariables.isNotEmpty() && if (notTypeVariables.isNotEmpty() &&
AbstractTypeChecker.isSubtypeOf( AbstractTypeChecker.isSubtypeOf(
this as TypeCheckerProviderContext, this as TypeCheckerProviderContext,
intersectTypes(notTypeVariables), intersectTypes(notTypeVariables),
superType superType
) )
) { ) {
return true return true
} }
// Consider the following example: // Consider the following example:
// fun <T> id(x: T): T = x // fun <T> 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)` // 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 // 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 // TODO: rethink, maybe we should take nullability into account somewhere else
if (notTypeVariables.any { AbstractNullabilityChecker.isSubtypeOfAny(this as TypeCheckerProviderContext, it) }) { if (notTypeVariables.any { AbstractNullabilityChecker.isSubtypeOfAny(this as TypeCheckerProviderContext, it) }) {
return typeVariables.all { simplifyUpperConstraint(it, superType.withNullability(true)) } 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) = private fun isSubtypeOfByTypeChecker(subType: KotlinTypeMarker, superType: KotlinTypeMarker) =
AbstractTypeChecker.isSubtypeOf(this as AbstractTypeCheckerContext, subType, superType) 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 if (!AbstractTypeChecker.RUN_SLOW_ASSERTIONS) return
fun correctSubType(subType: SimpleTypeMarker) = 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) = 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)) { assert(subType.bothBounds(::correctSubType)) {
"Not singleClassifierType and not intersection subType: $subType" "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) { private inline fun KotlinTypeMarker.bothBounds(f: (SimpleTypeMarker) -> Boolean) = when (this) {
is SimpleTypeMarker -> f(this) is SimpleTypeMarker -> f(this)
is FlexibleTypeMarker -> f(lowerBound()) && f(upperBound()) is FlexibleTypeMarker -> with(typeSystemContext) { f(lowerBound()) && f(upperBound()) }
else -> error("sealed") else -> error("sealed")
} }
private inline fun KotlinTypeMarker.anyBound(f: (SimpleTypeMarker) -> Boolean) = when (this) { private inline fun KotlinTypeMarker.anyBound(f: (SimpleTypeMarker) -> Boolean) = when (this) {
is SimpleTypeMarker -> f(this) is SimpleTypeMarker -> f(this)
is FlexibleTypeMarker -> f(lowerBound()) || f(upperBound()) is FlexibleTypeMarker -> with(typeSystemContext) { f(lowerBound()) || f(upperBound()) }
else -> error("sealed") else -> error("sealed")
} }
} }
@@ -165,7 +165,7 @@ class ConstraintInjector(
type.typeDepth() <= maxTypeDepthFromInitialConstraints + ALLOWED_DEPTH_DELTA_FOR_INCORPORATION type.typeDepth() <= maxTypeDepthFromInitialConstraints + ALLOWED_DEPTH_DELTA_FOR_INCORPORATION
private inner class TypeCheckerContext(val c: Context, val position: IncorporationConstraintPosition) : 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" // We use `var` intentionally to avoid extra allocations as this property is quite "hot"
private var possibleNewConstraints: MutableList<Pair<TypeVariableMarker, Constraint>>? = null private var possibleNewConstraints: MutableList<Pair<TypeVariableMarker, Constraint>>? = null
@@ -198,14 +198,6 @@ class ConstraintInjector(
return baseContext.substitutionSupertypePolicy(type) 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 { override fun refineType(type: KotlinTypeMarker): KotlinTypeMarker {
return with(constraintIncorporator.utilContext) { return with(constraintIncorporator.utilContext) {
type.refineType() type.refineType()
@@ -23,7 +23,9 @@ import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.TypeConstructorSubstitution import org.jetbrains.kotlin.types.TypeConstructorSubstitution
import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerContext 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.checker.NewKotlinTypeChecker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.keysToMap import org.jetbrains.kotlin.utils.keysToMap
@@ -326,14 +328,17 @@ object ExpectedActualResolver {
if (b == null) return false if (b == null) return false
with(NewKotlinTypeChecker.Default) { with(NewKotlinTypeChecker.Default) {
val context = object : ClassicTypeCheckerContext(false) { val context = object : ClassicTypeSystemContext {
override fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean { override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean {
return isExpectedClassAndActualTypeAlias(a, b, platformModule) || require(c1 is TypeConstructor)
isExpectedClassAndActualTypeAlias(b, a, platformModule) || require(c2 is TypeConstructor)
super.areEqualTypeConstructors(a, b) 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())
} }
} }
@@ -13,15 +13,12 @@ import org.jetbrains.kotlin.utils.SmartSet
import java.util.* import java.util.*
abstract class AbstractTypeCheckerContext : TypeSystemContext { abstract class AbstractTypeCheckerContext() {
abstract val typeSystemContext: TypeSystemContext
abstract fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy abstract fun substitutionSupertypePolicy(type: SimpleTypeMarker): SupertypesPolicy
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
return type
}
open fun refineType(type: KotlinTypeMarker): KotlinTypeMarker { open fun refineType(type: KotlinTypeMarker): KotlinTypeMarker {
return type return type
} }
@@ -34,7 +31,6 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext {
protected var argumentsDepth = 0 protected var argumentsDepth = 0
internal inline fun <T> runWithArgumentsSettings(subArgument: KotlinTypeMarker, f: AbstractTypeCheckerContext.() -> T): T { internal inline fun <T> runWithArgumentsSettings(subArgument: KotlinTypeMarker, f: AbstractTypeCheckerContext.() -> T): T {
if (argumentsDepth > 100) { if (argumentsDepth > 100) {
error("Arguments depth is too high. Some related argument: $subArgument") error("Arguments depth is too high. Some related argument: $subArgument")
@@ -46,7 +42,8 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext {
return result 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( open fun addSubtypeConstraint(
subType: KotlinTypeMarker, subType: KotlinTypeMarker,
@@ -109,7 +106,8 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext {
if (!visitedSupertypes.add(current)) continue if (!visitedSupertypes.add(current)) continue
val policy = supertypesPolicy(current).takeIf { it != SupertypesPolicy.None } ?: 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) val newType = policy.transformType(this, supertype)
if (predicate(newType)) { if (predicate(newType)) {
clear() clear()
@@ -133,18 +131,21 @@ abstract class AbstractTypeCheckerContext : TypeSystemContext {
object UpperIfFlexible : SupertypesPolicy() { object UpperIfFlexible : SupertypesPolicy() {
override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker) = override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker) =
with(context) { type.upperBoundIfFlexible() } with(context.typeSystemContext) { type.upperBoundIfFlexible() }
} }
object LowerIfFlexible : SupertypesPolicy() { object LowerIfFlexible : SupertypesPolicy() {
override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker) = override fun transformType(context: AbstractTypeCheckerContext, type: KotlinTypeMarker) =
with(context) { type.lowerBoundIfFlexible() } with(context.typeSystemContext) { type.lowerBoundIfFlexible() }
} }
abstract class DoCustomTransform : SupertypesPolicy() abstract class DoCustomTransform : SupertypesPolicy()
} }
abstract val KotlinTypeMarker.isAllowedTypeVariable: Boolean abstract val KotlinTypeMarker.isAllowedTypeVariable: Boolean
@JvmName("isAllowedTypeVariableBridge")
fun isAllowedTypeVariable(type: KotlinTypeMarker): Boolean = type.isAllowedTypeVariable
} }
object AbstractTypeChecker { object AbstractTypeChecker {
@@ -166,7 +167,7 @@ object AbstractTypeChecker {
superConstructor: TypeConstructorMarker superConstructor: TypeConstructorMarker
): Boolean { ): Boolean {
if (typeConstructor == superConstructor) return true if (typeConstructor == superConstructor) return true
with(context) { with(context.typeSystemContext) {
for (superType in typeConstructor.supertypes()) { for (superType in typeConstructor.supertypes()) {
if (isSubtypeOfClass(context, superType.typeConstructor(), superConstructor)) { if (isSubtypeOfClass(context, superType.typeConstructor(), superConstructor)) {
return true return true
@@ -182,7 +183,7 @@ object AbstractTypeChecker {
b: KotlinTypeMarker, b: KotlinTypeMarker,
stubTypesEqualToAnything: Boolean = true stubTypesEqualToAnything: Boolean = true
): Boolean { ): Boolean {
return AbstractTypeChecker.equalTypes(context.newBaseTypeCheckerContext(false, stubTypesEqualToAnything), a, b) return equalTypes(context.newBaseTypeCheckerContext(false, stubTypesEqualToAnything), a, b)
} }
fun isSubtypeOf( fun isSubtypeOf(
@@ -195,55 +196,61 @@ object AbstractTypeChecker {
if (!context.customIsSubtypeOf(subType, superType)) return false if (!context.customIsSubtypeOf(subType, superType)) return false
return with(context) { return completeIsSubTypeOf(
completeIsSubTypeOf(prepareType(refineType(subType)), prepareType(refineType(superType)), isFromNullabilityConstraint) 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) { fun equalTypes(context: AbstractTypeCheckerContext, a: KotlinTypeMarker, b: KotlinTypeMarker): Boolean =
if (a === b) return true with(context.typeSystemContext) {
if (a === b) return true
if (isCommonDenotableType(a) && isCommonDenotableType(b)) { if (isCommonDenotableType(a) && isCommonDenotableType(b)) {
val refinedA = refineType(a) val refinedA = context.refineType(a)
val refinedB = refineType(b) val refinedB = context.refineType(b)
val simpleA = refinedA.lowerBoundIfFlexible() val simpleA = refinedA.lowerBoundIfFlexible()
if (!areEqualTypeConstructors(refinedA.typeConstructor(), refinedB.typeConstructor())) return false if (!areEqualTypeConstructors(refinedA.typeConstructor(), refinedB.typeConstructor())) return false
if (simpleA.argumentsCount() == 0) { if (simpleA.argumentsCount() == 0) {
if (refinedA.hasFlexibleNullability() || refinedB.hasFlexibleNullability()) return true 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 completeIsSubTypeOf(
private fun AbstractTypeCheckerContext.completeIsSubTypeOf( context: AbstractTypeCheckerContext,
subType: KotlinTypeMarker, subType: KotlinTypeMarker,
superType: KotlinTypeMarker, superType: KotlinTypeMarker,
isFromNullabilityConstraint: Boolean isFromNullabilityConstraint: Boolean
): Boolean { ): Boolean = with(context.typeSystemContext) {
checkSubtypeForSpecialCases(subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())?.let { checkSubtypeForSpecialCases(context, subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())?.let {
addSubtypeConstraint(subType, superType, isFromNullabilityConstraint) context.addSubtypeConstraint(subType, superType, isFromNullabilityConstraint)
return it return it
} }
// we should add constraints with flexible types, otherwise we never get flexible type as answer in constraint system // 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, subType: SimpleTypeMarker,
superType: SimpleTypeMarker superType: SimpleTypeMarker
): Boolean? { ): Boolean? = with(context.typeSystemContext) {
if (!subType.isIntegerLiteralType() && !superType.isIntegerLiteralType()) return null if (!subType.isIntegerLiteralType() && !superType.isIntegerLiteralType()) return null
fun isTypeInIntegerLiteralType(integerLiteralType: SimpleTypeMarker, type: SimpleTypeMarker, checkSupertypes: Boolean): Boolean = fun isTypeInIntegerLiteralType(integerLiteralType: SimpleTypeMarker, type: SimpleTypeMarker, checkSupertypes: Boolean): Boolean =
integerLiteralType.possibleIntegerTypes().any { possibleType -> 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 { fun isIntegerLiteralTypeInIntersectionComponents(type: SimpleTypeMarker): Boolean {
@@ -276,12 +283,12 @@ object AbstractTypeChecker {
return null return null
} }
private fun AbstractTypeCheckerContext.hasNothingSupertype(type: SimpleTypeMarker): Boolean { private fun hasNothingSupertype(context: AbstractTypeCheckerContext, type: SimpleTypeMarker): Boolean = with(context.typeSystemContext) {
val typeConstructor = type.typeConstructor() val typeConstructor = type.typeConstructor()
if (typeConstructor.isClassTypeConstructor()) { if (typeConstructor.isClassTypeConstructor()) {
return typeConstructor.isNothingConstructor() return typeConstructor.isNothingConstructor()
} }
return anySupertype(type, { it.typeConstructor().isNothingConstructor() }) { return context.anySupertype(type, { it.typeConstructor().isNothingConstructor() }) {
if (it.isClassType()) { if (it.isClassType()) {
SupertypesPolicy.None SupertypesPolicy.None
} else { } 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) { 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" "Not singleClassifierType and not intersection subType: $subType"
} }
assert(superType.isSingleClassifierType() || superType.isAllowedTypeVariable) { assert(superType.isSingleClassifierType() || context .isAllowedTypeVariable(superType)) {
"Not singleClassifierType superType: $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 { checkSubtypeForIntegerLiteralType(context, subType.lowerBoundIfFlexible(), superType.upperBoundIfFlexible())?.let {
addSubtypeConstraint(subType, superType) context.addSubtypeConstraint(subType, superType)
return it return it
} }
@@ -312,10 +323,10 @@ object AbstractTypeChecker {
if (areEqualTypeConstructors(subType.typeConstructor(), superConstructor) && superConstructor.parametersCount() == 0) return true if (areEqualTypeConstructors(subType.typeConstructor(), superConstructor) && superConstructor.parametersCount() == 0) return true
if (superType.typeConstructor().isAnyConstructor()) return true if (superType.typeConstructor().isAnyConstructor()) return true
val supertypesWithSameConstructor = findCorrespondingSupertypes(subType, superConstructor) val supertypesWithSameConstructor = findCorrespondingSupertypes(context, subType, superConstructor)
when (supertypesWithSameConstructor.size) { when (supertypesWithSameConstructor.size) {
0 -> return hasNothingSupertype(subType) // todo Nothing & Array<Number> <: Array<String> 0 -> return hasNothingSupertype(context, subType) // todo Nothing & Array<Number> <: Array<String>
1 -> return isSubtypeForSameConstructor(supertypesWithSameConstructor.first().asArgumentList(), superType) 1 -> return context.isSubtypeForSameConstructor(supertypesWithSameConstructor.first().asArgumentList(), superType)
else -> { // at least 2 supertypes with same constructors. Such case is rare else -> { // at least 2 supertypes with same constructors. Such case is rare
val newArguments = ArgumentList(superConstructor.parametersCount()) val newArguments = ArgumentList(superConstructor.parametersCount())
@@ -333,10 +344,10 @@ object AbstractTypeChecker {
newArguments.add(intersection) 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 // 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( fun AbstractTypeCheckerContext.isSubtypeForSameConstructor(
capturedSubArguments: TypeArgumentListMarker, capturedSubArguments: TypeArgumentListMarker,
superType: SimpleTypeMarker superType: SimpleTypeMarker
): Boolean { ): Boolean = with(this.typeSystemContext) {
// No way to check, as no index sometimes // No way to check, as no index sometimes
//if (capturedSubArguments === superType.arguments) return true //if (capturedSubArguments === superType.arguments) return true
@@ -375,7 +386,7 @@ object AbstractTypeChecker {
return true return true
} }
private fun AbstractTypeCheckerContext.isCommonDenotableType(type: KotlinTypeMarker): Boolean = private fun TypeSystemContext.isCommonDenotableType(type: KotlinTypeMarker): Boolean =
type.typeConstructor().isDenotable() && type.typeConstructor().isDenotable() &&
!type.isDynamic() && !type.isDefinitelyNotNullType() && !type.isDynamic() && !type.isDefinitelyNotNullType() &&
type.lowerBoundIfFlexible().typeConstructor() == type.upperBoundIfFlexible().typeConstructor() type.lowerBoundIfFlexible().typeConstructor() == type.upperBoundIfFlexible().typeConstructor()
@@ -391,9 +402,13 @@ object AbstractTypeChecker {
return null 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 (subType.isError() || superType.isError()) {
if (isErrorTypeEqualsToAnything) return true if (context.isErrorTypeEqualsToAnything) return true
if (subType.isMarkedNullable() && !superType.isMarkedNullable()) return false 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) // superType might be a definitely notNull type (see KT-42824)
val superOriginalType = superType.asDefinitelyNotNullType()?.original() ?: superType val superOriginalType = superType.asDefinitelyNotNullType()?.original() ?: superType
@@ -418,9 +433,9 @@ object AbstractTypeChecker {
} else { } else {
if (superType.isDefinitelyNotNullType()) lowerType.makeDefinitelyNotNullOrNotNull() else lowerType if (superType.isDefinitelyNotNullType()) lowerType.makeDefinitelyNotNullOrNotNull() else lowerType
} }
when (getLowerCapturedTypePolicy(subType, superTypeCaptured)) { when (context.getLowerCapturedTypePolicy(subType, superTypeCaptured)) {
CHECK_ONLY_LOWER -> return isSubtypeOf(this, subType, nullableLowerType) CHECK_ONLY_LOWER -> return isSubtypeOf(context, subType, nullableLowerType)
CHECK_SUBTYPE_AND_LOWER -> if (isSubtypeOf(this, subType, nullableLowerType)) return true CHECK_SUBTYPE_AND_LOWER -> if (isSubtypeOf(context, subType, nullableLowerType)) return true
SKIP_LOWER -> Unit SKIP_LOWER -> Unit
} }
} }
@@ -429,17 +444,18 @@ object AbstractTypeChecker {
if (superTypeConstructor.isIntersection()) { if (superTypeConstructor.isIntersection()) {
assert(!superType.isMarkedNullable()) { "Intersection type should not be marked nullable!: $superType" } 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 return null
} }
private fun AbstractTypeCheckerContext.collectAllSupertypesWithGivenTypeConstructor( private fun collectAllSupertypesWithGivenTypeConstructor(
context: AbstractTypeCheckerContext,
subType: SimpleTypeMarker, subType: SimpleTypeMarker,
superConstructor: TypeConstructorMarker superConstructor: TypeConstructorMarker
): List<SimpleTypeMarker> { ): List<SimpleTypeMarker> = with(context.typeSystemContext) {
subType.fastCorrespondingSupertypes(superConstructor)?.let { subType.fastCorrespondingSupertypes(superConstructor)?.let {
return it return it
} }
@@ -455,7 +471,7 @@ object AbstractTypeChecker {
val result: MutableList<SimpleTypeMarker> = SmartList() val result: MutableList<SimpleTypeMarker> = SmartList()
anySupertype(subType, { false }) { context.anySupertype(subType, { false }) {
val current = captureFromArguments(it, CaptureStatus.FOR_SUBTYPING) ?: it val current = captureFromArguments(it, CaptureStatus.FOR_SUBTYPING) ?: it
@@ -468,7 +484,7 @@ object AbstractTypeChecker {
SupertypesPolicy.LowerIfFlexible SupertypesPolicy.LowerIfFlexible
} }
else -> { else -> {
substitutionSupertypePolicy(current) context.substitutionSupertypePolicy(current)
} }
} }
} }
@@ -476,8 +492,12 @@ object AbstractTypeChecker {
return result return result
} }
private fun AbstractTypeCheckerContext.collectAndFilter(classType: SimpleTypeMarker, constructor: TypeConstructorMarker) = private fun collectAndFilter(
selectOnlyPureKotlinSupertypes(collectAllSupertypesWithGivenTypeConstructor(classType, constructor)) context: AbstractTypeCheckerContext,
classType: SimpleTypeMarker,
constructor: TypeConstructorMarker
) =
selectOnlyPureKotlinSupertypes(context, collectAllSupertypesWithGivenTypeConstructor(context, classType, constructor))
/** /**
@@ -490,7 +510,10 @@ object AbstractTypeChecker {
* *
* More tests: javaAndKotlinSuperType & purelyImplementedCollection folder * More tests: javaAndKotlinSuperType & purelyImplementedCollection folder
*/ */
private fun AbstractTypeCheckerContext.selectOnlyPureKotlinSupertypes(supertypes: List<SimpleTypeMarker>): List<SimpleTypeMarker> { private fun selectOnlyPureKotlinSupertypes(
context: AbstractTypeCheckerContext,
supertypes: List<SimpleTypeMarker>
): List<SimpleTypeMarker> = with(context.typeSystemContext) {
if (supertypes.size < 2) return supertypes if (supertypes.size < 2) return supertypes
val allPureSupertypes = supertypes.filter { val allPureSupertypes = supertypes.filter {
@@ -502,22 +525,23 @@ object AbstractTypeChecker {
// nullability was checked earlier via nullabilityChecker // nullability was checked earlier via nullabilityChecker
// should be used only if you really sure that it is correct // should be used only if you really sure that it is correct
fun AbstractTypeCheckerContext.findCorrespondingSupertypes( fun findCorrespondingSupertypes(
context: AbstractTypeCheckerContext,
subType: SimpleTypeMarker, subType: SimpleTypeMarker,
superConstructor: TypeConstructorMarker superConstructor: TypeConstructorMarker
): List<SimpleTypeMarker> { ): List<SimpleTypeMarker> = with(context.typeSystemContext) {
if (subType.isClassType()) { if (subType.isClassType()) {
return collectAndFilter(subType, superConstructor) return collectAndFilter(context, subType, superConstructor)
} }
// i.e. superType is not a classType // i.e. superType is not a classType
if (!superConstructor.isClassTypeConstructor() && !superConstructor.isIntegerLiteralTypeConstructor()) { if (!superConstructor.isClassTypeConstructor() && !superConstructor.isIntegerLiteralTypeConstructor()) {
return collectAllSupertypesWithGivenTypeConstructor(subType, superConstructor) return collectAllSupertypesWithGivenTypeConstructor(context, subType, superConstructor)
} }
// todo add tests // todo add tests
val classTypeSupertypes = SmartList<SimpleTypeMarker>() val classTypeSupertypes = SmartList<SimpleTypeMarker>()
anySupertype(subType, { false }) { context.anySupertype(subType, { false }) {
if (it.isClassType()) { if (it.isClassType()) {
classTypeSupertypes.add(it) classTypeSupertypes.add(it)
SupertypesPolicy.None 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 { object AbstractNullabilityChecker {
// this method checks only nullability // this method checks only nullability
fun isPossibleSubtype(context: AbstractTypeCheckerContext, subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean = fun isPossibleSubtype(context: AbstractTypeCheckerContext, subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean =
context.runIsPossibleSubtype(subType, superType) runIsPossibleSubtype(context, subType, superType)
fun isSubtypeOfAny(context: TypeCheckerProviderContext, type: KotlinTypeMarker): Boolean = fun isSubtypeOfAny(context: TypeCheckerProviderContext, type: KotlinTypeMarker): Boolean =
AbstractNullabilityChecker.isSubtypeOfAny( AbstractNullabilityChecker.isSubtypeOfAny(
@@ -546,82 +570,93 @@ object AbstractNullabilityChecker {
) )
fun isSubtypeOfAny(context: AbstractTypeCheckerContext, type: KotlinTypeMarker): Boolean = fun isSubtypeOfAny(context: AbstractTypeCheckerContext, type: KotlinTypeMarker): Boolean =
with(context) { with(context.typeSystemContext) {
hasNotNullSupertype(type.lowerBoundIfFlexible(), SupertypesPolicy.LowerIfFlexible) context.hasNotNullSupertype(type.lowerBoundIfFlexible(), SupertypesPolicy.LowerIfFlexible)
} }
private fun AbstractTypeCheckerContext.runIsPossibleSubtype(subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean { private fun runIsPossibleSubtype(context: AbstractTypeCheckerContext, subType: SimpleTypeMarker, superType: SimpleTypeMarker): Boolean =
if (AbstractTypeChecker.RUN_SLOW_ASSERTIONS) { with(context.typeSystemContext) {
// it makes for case String? & Any <: String if (AbstractTypeChecker.RUN_SLOW_ASSERTIONS) {
assert(subType.isSingleClassifierType() || subType.typeConstructor().isIntersection() || subType.isAllowedTypeVariable) { // it makes for case String? & Any <: String
"Not singleClassifierType and not intersection subType: $subType" assert(
} subType.isSingleClassifierType() || subType.typeConstructor().isIntersection() || context.isAllowedTypeVariable(
assert(superType.isSingleClassifierType() || superType.isAllowedTypeVariable) { subType
"Not singleClassifierType superType: $superType" )
) {
"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<T>, A<in Number> => \exist Q : Number <: Q. A<Q>
* 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<T>, A<in Number> => \exist Q : Number <: Q. A<Q>
* 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) = fun AbstractTypeCheckerContext.hasNotNullSupertype(type: SimpleTypeMarker, supertypesPolicy: SupertypesPolicy) =
anySupertype(type, { with(typeSystemContext) {
(it.isClassType() && !it.isMarkedNullable()) || it.isDefinitelyNotNullType() anySupertype(type, {
}) { (it.isClassType() && !it.isMarkedNullable()) || it.isDefinitelyNotNullType()
if (it.isMarkedNullable()) SupertypesPolicy.None else supertypesPolicy }) {
if (it.isMarkedNullable()) SupertypesPolicy.None else supertypesPolicy
}
} }
fun TypeCheckerProviderContext.hasPathByNotMarkedNullableNodes(start: SimpleTypeMarker, end: TypeConstructorMarker) = fun TypeCheckerProviderContext.hasPathByNotMarkedNullableNodes(start: SimpleTypeMarker, end: TypeConstructorMarker) =
newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true) hasPathByNotMarkedNullableNodes(
.hasPathByNotMarkedNullableNodes(start, end) newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true), start, end
fun AbstractTypeCheckerContext.hasPathByNotMarkedNullableNodes(start: SimpleTypeMarker, end: TypeConstructorMarker) =
anySupertype(
start,
{ isApplicableAsEndNode(it, end) },
{ if (it.isMarkedNullable()) SupertypesPolicy.None else SupertypesPolicy.LowerIfFlexible }
) )
private fun AbstractTypeCheckerContext.isApplicableAsEndNode(type: SimpleTypeMarker, end: TypeConstructorMarker): Boolean { fun hasPathByNotMarkedNullableNodes(context: AbstractTypeCheckerContext, start: SimpleTypeMarker, end: TypeConstructorMarker) =
if (type.isNothing()) return true with(context.typeSystemContext) {
if (type.isMarkedNullable()) return false 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)
}
} }
@@ -393,24 +393,28 @@ public class OverridingUtil {
"Should be the same number of type parameters: " + firstParameters + " vs " + secondParameters; "Should be the same number of type parameters: " + firstParameters + " vs " + secondParameters;
NewKotlinTypeCheckerImpl typeChecker = new NewKotlinTypeCheckerImpl(kotlinTypeRefiner); NewKotlinTypeCheckerImpl typeChecker = new NewKotlinTypeCheckerImpl(kotlinTypeRefiner);
OverridingUtilTypeCheckerContext context = createTypeCheckerContext(firstParameters, secondParameters); ClassicTypeCheckerContext context = createTypeCheckerContext(firstParameters, secondParameters);
return new Pair<NewKotlinTypeCheckerImpl, ClassicTypeCheckerContext>(typeChecker, context); return new Pair<NewKotlinTypeCheckerImpl, ClassicTypeCheckerContext>(typeChecker, context);
} }
@NotNull @NotNull
private OverridingUtilTypeCheckerContext createTypeCheckerContext( private ClassicTypeCheckerContext createTypeCheckerContext(
@NotNull List<TypeParameterDescriptor> firstParameters, @NotNull List<TypeParameterDescriptor> firstParameters,
@NotNull List<TypeParameterDescriptor> secondParameters @NotNull List<TypeParameterDescriptor> secondParameters
) { ) {
if (firstParameters.isEmpty()) return new OverridingUtilTypeCheckerContext(null); if (firstParameters.isEmpty()) {
return (ClassicTypeCheckerContext) new OverridingUtilTypeSystemContext(null, equalityAxioms, kotlinTypeRefiner)
.newBaseTypeCheckerContext(true, true);
}
Map<TypeConstructor, TypeConstructor> matchingTypeConstructors = new HashMap<TypeConstructor, TypeConstructor>(); Map<TypeConstructor, TypeConstructor> matchingTypeConstructors = new HashMap<TypeConstructor, TypeConstructor>();
for (int i = 0; i < firstParameters.size(); i++) { for (int i = 0; i < firstParameters.size(); i++) {
matchingTypeConstructors.put(firstParameters.get(i).getTypeConstructor(), secondParameters.get(i).getTypeConstructor()); 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 @Nullable
@@ -977,34 +981,6 @@ public class OverridingUtil {
return maxVisibility; return maxVisibility;
} }
private class OverridingUtilTypeCheckerContext extends ClassicTypeCheckerContext {
private final @Nullable Map<TypeConstructor, TypeConstructor> matchingTypeConstructors;
public OverridingUtilTypeCheckerContext(@Nullable Map<TypeConstructor, TypeConstructor> 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 static class OverrideCompatibilityInfo {
public enum Result { public enum Result {
OVERRIDABLE, OVERRIDABLE,
@@ -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<TypeConstructor, TypeConstructor>?,
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
}
}
@@ -16,24 +16,18 @@
package org.jetbrains.kotlin.types.checker package org.jetbrains.kotlin.types.checker
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.SimpleTypeMarker import org.jetbrains.kotlin.types.model.SimpleTypeMarker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.refinement.TypeRefinement import org.jetbrains.kotlin.types.refinement.TypeRefinement
open class ClassicTypeCheckerContext( open class ClassicTypeCheckerContext(
val errorTypeEqualsToAnything: Boolean, val errorTypeEqualsToAnything: Boolean,
val stubTypeEqualsToAnything: Boolean = true, val stubTypeEqualsToAnything: Boolean = true,
val allowedTypeVariable: Boolean = true, val allowedTypeVariable: Boolean = true,
val kotlinTypeRefiner: KotlinTypeRefiner = KotlinTypeRefiner.Default val kotlinTypeRefiner: KotlinTypeRefiner = KotlinTypeRefiner.Default,
) : ClassicTypeSystemContext, AbstractTypeCheckerContext() { override val typeSystemContext: ClassicTypeSystemContext = SimpleClassicTypeSystemContext
) : AbstractTypeCheckerContext() {
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
require(type is KotlinType, type::errorMessage)
return NewKotlinTypeChecker.Default.transformToNewType(type.unwrap())
}
@OptIn(TypeRefinement::class) @OptIn(TypeRefinement::class)
override fun refineType(type: KotlinTypeMarker): KotlinTypeMarker { override fun refineType(type: KotlinTypeMarker): KotlinTypeMarker {
@@ -47,25 +41,8 @@ open class ClassicTypeCheckerContext(
override val isStubTypeEqualsToAnything: Boolean override val isStubTypeEqualsToAnything: Boolean
get() = stubTypeEqualsToAnything 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 { 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 override val KotlinTypeMarker.isAllowedTypeVariable: Boolean get() = this is UnwrappedType && allowedTypeVariable && constructor is NewTypeVariableConstructor
@@ -341,7 +341,7 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy
errorTypesEqualToAnything: Boolean, errorTypesEqualToAnything: Boolean,
stubTypesEqualToAnything: Boolean stubTypesEqualToAnything: Boolean
): AbstractTypeCheckerContext { ): AbstractTypeCheckerContext {
return ClassicTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything) return ClassicTypeCheckerContext(errorTypesEqualToAnything, stubTypesEqualToAnything, typeSystemContext = this)
} }
override fun nullableNothingType(): SimpleTypeMarker { override fun nullableNothingType(): SimpleTypeMarker {
@@ -485,8 +485,8 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy
} }
override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker { override fun prepareType(type: KotlinTypeMarker): KotlinTypeMarker {
require(type is UnwrappedType, type::errorMessage) require(type is KotlinType, type::errorMessage)
return NewKotlinTypeChecker.Default.transformToNewType(type) return NewKotlinTypeChecker.Default.transformToNewType(type.unwrap())
} }
override fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker { override fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker {
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic 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.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeTypeCheckerContext import org.jetbrains.kotlin.fir.types.ConeTypeCheckerContext
import org.jetbrains.kotlin.idea.frontend.api.diagnostics.KtDiagnostic import org.jetbrains.kotlin.idea.frontend.api.diagnostics.KtDiagnostic
@@ -33,6 +34,6 @@ internal interface KtFirAnalysisSessionComponent {
fun createTypeCheckerContext() = ConeTypeCheckerContext( fun createTypeCheckerContext() = ConeTypeCheckerContext(
isErrorTypeEqualsToAnything = true, isErrorTypeEqualsToAnything = true,
isStubTypeEqualsToAnything = true, isStubTypeEqualsToAnything = true,
analysisSession.firResolveState.rootModuleSession //TODO use correct session here analysisSession.firResolveState.rootModuleSession.typeContext //TODO use correct session here
) )
} }
@@ -52,11 +52,14 @@ import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoAfter
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerContext 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.KotlinTypeChecker
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker 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.addIfNotNull
import org.jetbrains.kotlin.utils.ifEmpty import org.jetbrains.kotlin.utils.ifEmpty
import org.jetbrains.kotlin.utils.sure 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 var KtExpression.isOccurrence: Boolean by NotNullablePsiCopyableUserDataProperty(Key.create("OCCURRENCE"), false)
private class TypeCheckerImpl(private val project: Project) : KotlinTypeChecker by KotlinTypeChecker.DEFAULT { private class TypeCheckerImpl(private val project: Project) : KotlinTypeChecker by KotlinTypeChecker.DEFAULT {
private inner class ContextImpl : ClassicTypeCheckerContext(false) { private inner class TypeSystemContextImpl : ClassicTypeSystemContext {
override fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean = override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean {
compareDescriptors(project, a.declarationDescriptor, b.declarationDescriptor) 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) { override fun equalTypes(a: KotlinType, b: KotlinType): Boolean = with(NewKotlinTypeChecker.Default) {
ContextImpl().equalTypes(a.unwrap(), b.unwrap()) ContextImpl().equalTypes(a.unwrap(), b.unwrap())
} }