diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/intentions/declarations/HLSpecifyExplicitTypeForCallableDeclarationIntention.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/intentions/declarations/HLSpecifyExplicitTypeForCallableDeclarationIntention.kt index 4203415e257..6c41a54aabe 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/intentions/declarations/HLSpecifyExplicitTypeForCallableDeclarationIntention.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/intentions/declarations/HLSpecifyExplicitTypeForCallableDeclarationIntention.kt @@ -8,12 +8,10 @@ package org.jetbrains.kotlin.idea.fir.intentions.declarations import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.fir.api.* import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicabilityRange -import org.jetbrains.kotlin.idea.fir.api.applicator.applicabilityTarget import org.jetbrains.kotlin.idea.fir.api.applicator.inputProvider import org.jetbrains.kotlin.idea.fir.api.applicator.with import org.jetbrains.kotlin.idea.fir.applicators.ApplicabilityRanges import org.jetbrains.kotlin.idea.fir.applicators.CallableReturnTypeUpdaterApplicator -import org.jetbrains.kotlin.idea.frontend.api.types.* import org.jetbrains.kotlin.psi.* class HLSpecifyExplicitTypeForCallableDeclarationIntention : @@ -31,7 +29,7 @@ class HLSpecifyExplicitTypeForCallableDeclarationIntention : override val inputProvider = inputProvider { declaration -> val returnType = declaration.getReturnKtType() - val denotableType = returnType.approximateToPublicDenotable() ?: return@inputProvider null + val denotableType = returnType.approximateToSuperPublicDenotable() ?: returnType with(CallableReturnTypeUpdaterApplicator.Type) { createByKtType(denotableType) } } } \ No newline at end of file diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt index 73c559ada86..5f0ee715544 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt @@ -105,7 +105,13 @@ abstract class KtAnalysisSession(final override val token: ValidityToken) : Vali val builtinTypes: KtBuiltinTypes get() = typeProvider.builtinTypes - fun KtType.approximateToPublicDenotable(): KtType? = typeProvider.approximateToPublicDenotable(this) + /** + * Approximates [KtType] with the a supertype which can be rendered in a source code + * + * Return `null` if the type do not need approximation and can be rendered as is + * Otherwise, for type `T` return type `S` such `T <: S` and `T` and every it type argument is [org.jetbrains.kotlin.idea.frontend.api.types.KtDenotableType]` + */ + fun KtType.approximateToSuperPublicDenotable(): KtType? = typeProvider.approximateToSuperPublicDenotableType(this) fun KtClassOrObjectSymbol.buildSelfClassType(): KtType = typeProvider.buildSelfClassType(this) diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtTypeProvider.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtTypeProvider.kt index e90bd35b6f6..1f69c3d56fb 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtTypeProvider.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtTypeProvider.kt @@ -13,7 +13,7 @@ import org.jetbrains.kotlin.idea.frontend.api.types.KtType abstract class KtTypeProvider : KtAnalysisSessionComponent() { abstract val builtinTypes: KtBuiltinTypes - abstract fun approximateToPublicDenotable(type: KtType): KtType? + abstract fun approximateToSuperPublicDenotableType(type: KtType): KtType? abstract fun buildSelfClassType(symbol: KtClassOrObjectSymbol): KtType } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirTypeProvider.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirTypeProvider.kt index 224965245be..c109af8e63c 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirTypeProvider.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirTypeProvider.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.components import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents +import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl import org.jetbrains.kotlin.idea.frontend.api.ValidityToken @@ -18,6 +19,7 @@ import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirType import org.jetbrains.kotlin.idea.frontend.api.fir.types.PublicTypeApproximator import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol import org.jetbrains.kotlin.idea.frontend.api.types.KtType +import org.jetbrains.kotlin.types.TypeApproximatorConfiguration internal class KtFirTypeProvider( override val analysisSession: KtFirAnalysisSession, @@ -26,14 +28,14 @@ internal class KtFirTypeProvider( override val builtinTypes: KtBuiltinTypes = KtFirBuiltInTypes(analysisSession.firResolveState.rootModuleSession.builtinTypes, analysisSession.firSymbolBuilder, token) - override fun approximateToPublicDenotable(type: KtType): KtType? { + override fun approximateToSuperPublicDenotableType(type: KtType): KtType? { require(type is KtFirType) val coneType = type.coneType val approximatedConeType = PublicTypeApproximator.approximateTypeToPublicDenotable( coneType, - rootModuleSession.inferenceComponents.ctx, rootModuleSession ) + return approximatedConeType?.asKtType() } @@ -50,3 +52,4 @@ internal class KtFirTypeProvider( return type.asKtType() } } + diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/types/PublicTypeApproximator.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/types/PublicTypeApproximator.kt index 419793ce5cf..a9df2bd452d 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/types/PublicTypeApproximator.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/types/PublicTypeApproximator.kt @@ -6,128 +6,25 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.types import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.resolve.calls.fullyExpandedClass -import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes -import org.jetbrains.kotlin.fir.resolve.toSymbol -import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl -import org.jetbrains.kotlin.types.AbstractTypeChecker -import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.types.TypeApproximatorConfiguration internal object PublicTypeApproximator { fun approximateTypeToPublicDenotable( type: ConeKotlinType, - context: ConeInferenceContext, session: FirSession, - ): ConeKotlinType? = approximate(type, context, session) as ConeKotlinType? - - private fun approximate( - type: ConeKotlinType, - context: ConeInferenceContext, - session: FirSession, - ): ConeTypeProjection? = when (type) { - is ConeFlexibleType -> approximate(type.upperBound, context, session) - is ConeCapturedType -> type - is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType( - approximate( - type.original, - context, - session, - ) as ConeKotlinType - ) - is ConeIntegerLiteralType -> type - is ConeIntersectionType -> context.commonSuperTypeOrNull(type.intersectedTypes.toList())?.let { approximate(it, context, session) } - is ConeLookupTagBasedType -> when (type) { - is ConeTypeParameterType -> type - is ConeClassErrorType -> null - is ConeClassLikeTypeImpl -> approximateClassLikeType(type, context, session) - else -> error("Unexpected type ${type::class}") - } - is ConeStubType -> null + ): ConeKotlinType? { + val approximator = session.inferenceComponents.approximator + return approximator.approximateToSuperType(type, PublicApproximatorConfiguration) as ConeKotlinType? } - private fun approximateClassLikeType( - typeImpl: ConeClassLikeTypeImpl, - context: ConeInferenceContext, - session: FirSession, - ): ConeTypeProjection? { - val regularClass = typeImpl.classOrAnonymousClass(session) ?: return null - val type = if (needApproximationAsSuperType(regularClass)) { - firstSuperType(regularClass, session) ?: return null - } else { - typeImpl - } - - val typeClassifier = type.classOrAnonymousClass(session) ?: return null - - val typeArguments = approximateTypeParameters(type, typeClassifier, context, session)?.toTypedArray() ?: return null - return ConeClassLikeTypeImpl( - type.lookupTag, - typeArguments, - type.isNullable, - type.attributes - ) - } - - private fun approximateTypeParameters( - type: ConeClassLikeTypeImpl, - typeClassifier: FirClass<*>, - context: ConeInferenceContext, - session: FirSession - ): List? { - val result = mutableListOf() - if (type.typeArguments.size != typeClassifier.typeParameters.size) return null - for ((typeArg, typeParam) in type.typeArguments.zip(typeClassifier.typeParameters)) { - val variance = (typeParam as? FirTypeParameter)?.variance ?: return null - result += approximateTypeProjection(typeArg, context, session, variance) ?: return null - } - return result - } - - private fun firstSuperType(regularClass: FirClass<*>, session: FirSession): ConeClassLikeTypeImpl? { - val superTypes = lookupSuperTypes(regularClass, lookupInterfaces = true, deep = false, session, substituteTypes = true) - return superTypes.first() as? ConeClassLikeTypeImpl - } - - fun ConeClassLikeTypeImpl.classOrAnonymousClass(session: FirSession): FirClass<*>? { - val fir = lookupTag.toSymbol(session)?.fir ?: return null - if (fir is FirAnonymousObject) return fir - else return fir.fullyExpandedClass(session) - } - - private fun needApproximationAsSuperType(fir: FirClass<*>) = when (fir) { - is FirRegularClass -> fir.isLocal - is FirAnonymousObject -> true - else -> false - } - - private fun approximateTypeProjection( - typeProjection: ConeTypeProjection, - context: ConeInferenceContext, - session: FirSession, - variance: Variance, - ): ConeTypeProjection? { - val type = when (typeProjection) { - ConeStarProjection -> return ConeStarProjection - is ConeKotlinTypeProjection -> typeProjection.type - else -> error("Unexpected type ${typeProjection::class}") - } - val newType = when (val new = approximate(type, context, session)) { - ConeStarProjection -> return ConeStarProjection - is ConeKotlinTypeProjection -> new.type - null -> return null - else -> error("Unexpected type ${new::class}") - } - return when (variance) { - Variance.INVARIANT -> when { - with(context) { newType.typeConstructor().isAnyConstructor() } -> ConeStarProjection - AbstractTypeChecker.equalTypes(context, type, newType) -> newType - else -> ConeStarProjection - } - Variance.IN_VARIANCE -> if (AbstractTypeChecker.isSubtypeOf(context, newType, type)) newType else ConeStarProjection - Variance.OUT_VARIANCE -> if (AbstractTypeChecker.isSubtypeOf(context, type, newType)) newType else ConeStarProjection - } + private object PublicApproximatorConfiguration : TypeApproximatorConfiguration.AllFlexibleSameValue() { + override val allFlexible: Boolean get() = false + override val errorType: Boolean get() = true + override val definitelyNotNullType: Boolean get() = false + override val integerLiteralType: Boolean get() = true + override val intersectionTypesInContravariantPositions: Boolean get() = true + override val localTypes: Boolean get() = true } } \ No newline at end of file