From 7ee65978731597f4b6bb0da96b7cc8ce7e8b780c Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 5 May 2021 13:32:38 +0300 Subject: [PATCH] FIR: make inference context mandatory in withNullability() etc. --- .../kotlin/fir/backend/Fir2IrTypeConverter.kt | 4 ++++ .../generators/CallAndReferenceGenerator.kt | 3 +++ .../jetbrains/kotlin/fir/java/JavaUtils.kt | 17 ++++++++------ .../kotlin/fir/resolve/ResolveUtils.kt | 4 +++- .../kotlin/fir/resolve/TypeExpansionUtils.kt | 7 +++++- .../fir/resolve/substitution/Substitutors.kt | 19 ++++++++++----- .../kotlin/fir/types/ConeInferenceContext.kt | 4 ++-- .../kotlin/fir/types/ConeTypeContext.kt | 3 ++- .../jetbrains/kotlin/fir/types/TypeUtils.kt | 23 +++++++------------ .../kotlin/idea/asJava/firLightUtils.kt | 10 ++++++-- 10 files changed, 59 insertions(+), 35 deletions(-) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt index 0d949e32f9d..91848564cd5 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall import org.jetbrains.kotlin.fir.expressions.classId import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.resolve.fullyExpandedType +import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.typeContext @@ -222,6 +223,9 @@ class Fir2IrTypeConverter( private fun approximateType(type: ConeKotlinType): ConeKotlinType { if (type is ConeClassLikeType && type.typeArguments.isEmpty()) return type val substitutor = object : AbstractConeSubstitutor() { + override val typeInferenceContext: ConeInferenceContext + get() = session.inferenceComponents.ctx + override fun substituteType(type: ConeKotlinType): ConeKotlinType? { return if (type is ConeIntersectionType) { type.alternativeType?.let { substituteOrSelf(it) } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt index d533c669db0..e7ab3fc8b57 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt @@ -665,6 +665,9 @@ class CallAndReferenceGenerator( } private val starProjectionApproximator = object : AbstractConeSubstitutor() { + override val typeInferenceContext: ConeInferenceContext + get() = session.inferenceComponents.ctx + override fun substituteType(type: ConeKotlinType): ConeKotlinType? { if (type !is ConeClassLikeType || type.typeArguments.none { it == ConeStarProjection }) return null val fir = type.lookupTag.toSymbol(session)?.fir as? FirTypeParameterRefsOwner ?: return null diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt index 24aeca32e12..b647f91c528 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.fir.references.impl.FirReferencePlaceholderForResolv import org.jetbrains.kotlin.fir.resolve.bindSymbolToLookupTag import org.jetbrains.kotlin.fir.resolve.defaultType import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedReferenceError +import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredPropertySymbols import org.jetbrains.kotlin.fir.resolve.symbolProvider import org.jetbrains.kotlin.fir.resolve.toSymbol @@ -274,7 +275,7 @@ private fun computeRawProjection( session: FirSession, parameter: FirTypeParameter, attr: TypeComponentPosition, - erasedUpperBound: ConeKotlinType = parameter.getErasedUpperBound() + erasedUpperBound: ConeKotlinType = parameter.getErasedUpperBound(session) ) = when (attr) { // Raw(List) => (List..List<*>) // Raw(Enum) => (Enum>..Enum>) @@ -306,6 +307,7 @@ private fun computeRawProjection( // ErasedUpperBound(T : A) = A // UpperBound(T) is a type A without arguments // ErasedUpperBound(T : F) = UpperBound(F) // UB(T) is another type parameter F private fun FirTypeParameter.getErasedUpperBound( + session: FirSession, // Calculation of `potentiallyRecursiveTypeParameter.upperBounds` may recursively depend on `this.getErasedUpperBound` // E.g. `class A` // To prevent recursive calls return defaultValue() instead @@ -318,10 +320,11 @@ private fun FirTypeParameter.getErasedUpperBound( val firstUpperBound = this.bounds.first().coneType - return getErasedVersionOfFirstUpperBound(firstUpperBound, mutableSetOf(this, potentiallyRecursiveTypeParameter), defaultValue) + return getErasedVersionOfFirstUpperBound(session, firstUpperBound, mutableSetOf(this, potentiallyRecursiveTypeParameter), defaultValue) } private fun getErasedVersionOfFirstUpperBound( + session: FirSession, firstUpperBound: ConeKotlinType, alreadyVisitedParameters: MutableSet, defaultValue: () -> ConeKotlinType @@ -332,18 +335,18 @@ private fun getErasedVersionOfFirstUpperBound( is ConeFlexibleType -> { val lowerBound = - getErasedVersionOfFirstUpperBound(firstUpperBound.lowerBound, alreadyVisitedParameters, defaultValue) + getErasedVersionOfFirstUpperBound(session, firstUpperBound.lowerBound, alreadyVisitedParameters, defaultValue) .lowerBoundIfFlexible() if (firstUpperBound.upperBound is ConeTypeParameterType) { // Avoid exponential complexity ConeFlexibleType( lowerBound, - lowerBound.withNullability(ConeNullability.NULLABLE) + lowerBound.withNullability(ConeNullability.NULLABLE, session.inferenceComponents.ctx) ) } else { ConeFlexibleType( lowerBound, - getErasedVersionOfFirstUpperBound(firstUpperBound.upperBound, alreadyVisitedParameters, defaultValue) + getErasedVersionOfFirstUpperBound(session, firstUpperBound.upperBound, alreadyVisitedParameters, defaultValue) ) } } @@ -352,7 +355,7 @@ private fun getErasedVersionOfFirstUpperBound( if (alreadyVisitedParameters.add(current)) { val nextUpperBound = current.bounds.first().coneType - getErasedVersionOfFirstUpperBound(nextUpperBound, alreadyVisitedParameters, defaultValue) + getErasedVersionOfFirstUpperBound(session, nextUpperBound, alreadyVisitedParameters, defaultValue) } else { defaultValue() } @@ -433,7 +436,7 @@ private fun FirRegularClass.createRawArguments( defaultArgs: List, position: TypeComponentPosition ): List = typeParameters.filterIsInstance().map { typeParameter -> - val erasedUpperBound = typeParameter.getErasedUpperBound { + val erasedUpperBound = typeParameter.getErasedUpperBound(session) { defaultType().withArguments(defaultArgs.toTypedArray()) } computeRawProjection(session, typeParameter, position, erasedUpperBound) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index dd5720fd76e..98ec4b43de3 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -299,7 +299,9 @@ fun FirCheckedSafeCallSubject.propagateTypeFromOriginalReceiver(nullableReceiver val expandedReceiverType = if (receiverType is ConeClassLikeType) receiverType.fullyExpandedType(session) else receiverType - val resolvedTypeRef = typeRef.resolvedTypeFromPrototype(expandedReceiverType.makeConeTypeDefinitelyNotNullOrNotNull()) + val resolvedTypeRef = typeRef.resolvedTypeFromPrototype( + expandedReceiverType.makeConeTypeDefinitelyNotNullOrNotNull(session.inferenceComponents.ctx) + ) replaceTypeRef(resolvedTypeRef) session.lookupTracker?.recordTypeResolveAsLookup(resolvedTypeRef, source, null) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/TypeExpansionUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/TypeExpansionUtils.kt index f4b3e3e5c03..05afa86d6c2 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/TypeExpansionUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/TypeExpansionUtils.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirTypeAlias import org.jetbrains.kotlin.fir.declarations.expandedConeType +import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol import org.jetbrains.kotlin.fir.typeContext @@ -62,7 +63,7 @@ fun ConeClassLikeType.directExpansionType( val resultType = expandedConeType(typeAlias)?.applyNullabilityFrom(useSiteSession, this) ?: return null if (resultType.typeArguments.isEmpty()) return resultType - return mapTypeAliasArguments(typeAlias, this, resultType) as? ConeClassLikeType + return mapTypeAliasArguments(typeAlias, this, resultType, useSiteSession) as? ConeClassLikeType } private fun ConeClassLikeType.applyNullabilityFrom( @@ -77,6 +78,7 @@ private fun mapTypeAliasArguments( typeAlias: FirTypeAlias, abbreviatedType: ConeClassLikeType, resultingType: ConeClassLikeType, + useSiteSession: FirSession, ): ConeKotlinType { if (typeAlias.typeParameters.isNotEmpty() && abbreviatedType.typeArguments.isEmpty()) { return resultingType.lookupTag.constructClassType(emptyArray(), resultingType.isNullable) @@ -84,6 +86,9 @@ private fun mapTypeAliasArguments( val typeAliasMap = typeAlias.typeParameters.map { it.symbol }.zip(abbreviatedType.typeArguments).toMap() val substitutor = object : AbstractConeSubstitutor() { + override val typeInferenceContext: ConeInferenceContext + get() = useSiteSession.inferenceComponents.ctx + override fun substituteType(type: ConeKotlinType): ConeKotlinType? { return null } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt index 235cb82132e..8c39c5fea37 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt @@ -16,6 +16,8 @@ import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker import org.jetbrains.kotlin.types.model.typeConstructor abstract class AbstractConeSubstitutor : ConeSubstitutor() { + abstract val typeInferenceContext: ConeInferenceContext + private fun wrapProjection(old: ConeTypeProjection, newType: ConeKotlinType): ConeTypeProjection { return when (old) { is ConeStarProjection -> old @@ -35,8 +37,8 @@ abstract class AbstractConeSubstitutor : ConeSubstitutor() { fun ConeKotlinType?.updateNullabilityIfNeeded(originalType: ConeKotlinType): ConeKotlinType? { return when { - originalType is ConeDefinitelyNotNullType -> this?.withNullability(ConeNullability.NOT_NULL) - originalType.isMarkedNullable -> this?.withNullability(ConeNullability.NULLABLE) + originalType is ConeDefinitelyNotNullType -> this?.withNullability(ConeNullability.NOT_NULL, typeInferenceContext) + originalType.isMarkedNullable -> this?.withNullability(ConeNullability.NULLABLE, typeInferenceContext) else -> this } } @@ -44,7 +46,7 @@ abstract class AbstractConeSubstitutor : ConeSubstitutor() { override fun substituteOrNull(type: ConeKotlinType): ConeKotlinType? { val newType = substituteType(type) if (newType != null && type is ConeDefinitelyNotNullType) { - return newType.makeConeTypeDefinitelyNotNullOrNotNull() + return newType.makeConeTypeDefinitelyNotNullOrNotNull(typeInferenceContext) } return (newType ?: type.substituteRecursive()) } @@ -82,7 +84,7 @@ abstract class AbstractConeSubstitutor : ConeSubstitutor() { } private fun ConeDefinitelyNotNullType.substituteOriginal(): ConeKotlinType? { - val substituted = substituteOrNull(original)?.withNullability(ConeNullability.NOT_NULL) ?: return null + val substituted = substituteOrNull(original)?.withNullability(ConeNullability.NOT_NULL, typeInferenceContext) ?: return null return ConeDefinitelyNotNullType.create(substituted) ?: substituted } @@ -157,6 +159,9 @@ data class ConeSubstitutorByMap( val substitution: Map, val useSiteSession: FirSession ) : AbstractConeSubstitutor() { + override val typeInferenceContext: ConeInferenceContext + get() = useSiteSession.inferenceComponents.ctx + override fun substituteType(type: ConeKotlinType): ConeKotlinType? { if (type !is ConeTypeParameterType) return null val result = substitution[type.lookupTag.symbol].updateNullabilityIfNeeded(type) ?: return null @@ -171,8 +176,10 @@ data class ConeSubstitutorByMap( fun createTypeSubstitutorByTypeConstructor(map: Map, context: ConeTypeContext): ConeSubstitutor { if (map.isEmpty()) return ConeSubstitutor.Empty - return object : AbstractConeSubstitutor(), - TypeSubstitutorMarker { + return object : AbstractConeSubstitutor(), TypeSubstitutorMarker { + override val typeInferenceContext: ConeInferenceContext + get() = context.session.inferenceComponents.ctx + override fun substituteType(type: ConeKotlinType): ConeKotlinType? { if (type !is ConeLookupTagBasedType && type !is ConeStubType) return null val new = map[type.typeConstructor(context)] ?: return null diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt index 98137da1358..1e1d532a482 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt @@ -228,12 +228,12 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo override fun KotlinTypeMarker.makeDefinitelyNotNullOrNotNull(): KotlinTypeMarker { require(this is ConeKotlinType) - return makeConeTypeDefinitelyNotNullOrNotNull() + return makeConeTypeDefinitelyNotNullOrNotNull(this@ConeInferenceContext) } override fun SimpleTypeMarker.makeSimpleTypeDefinitelyNotNullOrNotNull(): SimpleTypeMarker { require(this is ConeKotlinType) - return makeConeTypeDefinitelyNotNullOrNotNull() as SimpleTypeMarker + return makeConeTypeDefinitelyNotNullOrNotNull(this@ConeInferenceContext) as SimpleTypeMarker } override fun createCapturedType( diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt index 383568ff183..48c37d781f8 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.expressions.FirVarargArgumentsExpression import org.jetbrains.kotlin.fir.expressions.arguments import org.jetbrains.kotlin.fir.resolve.correspondingSupertypesCache import org.jetbrains.kotlin.fir.resolve.fullyExpandedType +import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.resolve.toSymbol @@ -128,7 +129,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty override fun SimpleTypeMarker.withNullability(nullable: Boolean): SimpleTypeMarker { require(this is ConeKotlinType) - return withNullability(ConeNullability.create(nullable), this as? ConeInferenceContext) + return withNullability(ConeNullability.create(nullable), session.inferenceComponents.ctx) } override fun SimpleTypeMarker.typeConstructor(): TypeConstructorMarker { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt index a576785051b..0802b217ab0 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt @@ -56,11 +56,11 @@ fun ConeDefinitelyNotNullType.Companion.create(original: ConeKotlinType): ConeDe } } -fun ConeKotlinType.makeConeTypeDefinitelyNotNullOrNotNull(): ConeKotlinType { +fun ConeKotlinType.makeConeTypeDefinitelyNotNullOrNotNull(typeContext: ConeInferenceContext): ConeKotlinType { if (this is ConeIntersectionType) { - return ConeIntersectionType(intersectedTypes.map { it.makeConeTypeDefinitelyNotNullOrNotNull() }) + return ConeIntersectionType(intersectedTypes.map { it.makeConeTypeDefinitelyNotNullOrNotNull(typeContext) }) } - return ConeDefinitelyNotNullType.create(this) ?: this.withNullability(ConeNullability.NOT_NULL) + return ConeDefinitelyNotNullType.create(this) ?: this.withNullability(ConeNullability.NOT_NULL, typeContext) } fun T.withArguments(arguments: Array): T { @@ -95,7 +95,7 @@ fun T.withAttributes(attributes: ConeAttributes): T { fun T.withNullability( nullability: ConeNullability, - typeContext: ConeInferenceContext? = null, + typeContext: ConeInferenceContext, attributes: ConeAttributes = this.attributes, ): T { if (this.nullability == nullability && this.attributes == attributes) { @@ -123,7 +123,7 @@ fun T.withNullability( is ConeCapturedType -> ConeCapturedType(captureStatus, lowerType, nullability, constructor, attributes) is ConeIntersectionType -> when (nullability) { ConeNullability.NULLABLE -> this.mapTypes { - it.withNullability(nullability) + it.withNullability(nullability, typeContext) } ConeNullability.UNKNOWN -> this // TODO: is that correct? ConeNullability.NOT_NULL -> this @@ -140,7 +140,7 @@ fun T.withNullability( } fun coneFlexibleOrSimpleType( - typeContext: ConeInferenceContext?, + typeContext: ConeInferenceContext, lowerBound: ConeKotlinType, upperBound: ConeKotlinType, ): ConeKotlinType { @@ -151,15 +151,8 @@ fun coneFlexibleOrSimpleType( return coneFlexibleOrSimpleType(typeContext, lowerBound, upperBound.upperBound) } return when { - typeContext != null && AbstractStrictEqualityTypeChecker.strictEqualTypes(typeContext, lowerBound, upperBound) -> { - lowerBound - } - typeContext == null && lowerBound == upperBound -> { - lowerBound - } - else -> { - ConeFlexibleType(lowerBound, upperBound) - } + AbstractStrictEqualityTypeChecker.strictEqualTypes(typeContext, lowerBound, upperBound) -> lowerBound + else -> ConeFlexibleType(lowerBound, upperBound) } } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt index 80ea8f50a50..80a9067be70 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.backend.jvm.jvmTypeMapper import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.isPrimitiveType +import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol @@ -76,8 +77,13 @@ internal fun KtNamedClassOrObjectSymbol.typeForClassSymbol(psiElement: PsiElemen return types.coneType.asPsiType(session, firRef.resolveState, TypeMappingMode.DEFAULT, psiElement) } -private class AnonymousTypesSubstitutor(private val session: FirSession, private val state: FirModuleResolveState) : - AbstractConeSubstitutor() { +private class AnonymousTypesSubstitutor( + private val session: FirSession, + private val state: FirModuleResolveState +) : AbstractConeSubstitutor() { + override val typeInferenceContext: ConeInferenceContext + get() = session.inferenceComponents.ctx + override fun substituteType(type: ConeKotlinType): ConeKotlinType? { if (type !is ConeClassLikeType) return null