FIR IDE: use correct denotable type approximator
This commit is contained in:
+1
-3
@@ -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<KtCallableDeclaration, CallableReturnTypeUpdaterApplicator.Type> { declaration ->
|
||||
val returnType = declaration.getReturnKtType()
|
||||
val denotableType = returnType.approximateToPublicDenotable() ?: return@inputProvider null
|
||||
val denotableType = returnType.approximateToSuperPublicDenotable() ?: returnType
|
||||
with(CallableReturnTypeUpdaterApplicator.Type) { createByKtType(denotableType) }
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -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)
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
+5
-2
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-115
@@ -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<ConeTypeProjection>? {
|
||||
val result = mutableListOf<ConeTypeProjection>()
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user