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.KotlinBundle
|
||||||
import org.jetbrains.kotlin.idea.fir.api.*
|
import org.jetbrains.kotlin.idea.fir.api.*
|
||||||
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicabilityRange
|
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.inputProvider
|
||||||
import org.jetbrains.kotlin.idea.fir.api.applicator.with
|
import org.jetbrains.kotlin.idea.fir.api.applicator.with
|
||||||
import org.jetbrains.kotlin.idea.fir.applicators.ApplicabilityRanges
|
import org.jetbrains.kotlin.idea.fir.applicators.ApplicabilityRanges
|
||||||
import org.jetbrains.kotlin.idea.fir.applicators.CallableReturnTypeUpdaterApplicator
|
import org.jetbrains.kotlin.idea.fir.applicators.CallableReturnTypeUpdaterApplicator
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.types.*
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
|
||||||
class HLSpecifyExplicitTypeForCallableDeclarationIntention :
|
class HLSpecifyExplicitTypeForCallableDeclarationIntention :
|
||||||
@@ -31,7 +29,7 @@ class HLSpecifyExplicitTypeForCallableDeclarationIntention :
|
|||||||
|
|
||||||
override val inputProvider = inputProvider<KtCallableDeclaration, CallableReturnTypeUpdaterApplicator.Type> { declaration ->
|
override val inputProvider = inputProvider<KtCallableDeclaration, CallableReturnTypeUpdaterApplicator.Type> { declaration ->
|
||||||
val returnType = declaration.getReturnKtType()
|
val returnType = declaration.getReturnKtType()
|
||||||
val denotableType = returnType.approximateToPublicDenotable() ?: return@inputProvider null
|
val denotableType = returnType.approximateToSuperPublicDenotable() ?: returnType
|
||||||
with(CallableReturnTypeUpdaterApplicator.Type) { createByKtType(denotableType) }
|
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
|
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)
|
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 class KtTypeProvider : KtAnalysisSessionComponent() {
|
||||||
abstract val builtinTypes: KtBuiltinTypes
|
abstract val builtinTypes: KtBuiltinTypes
|
||||||
|
|
||||||
abstract fun approximateToPublicDenotable(type: KtType): KtType?
|
abstract fun approximateToSuperPublicDenotableType(type: KtType): KtType?
|
||||||
|
|
||||||
abstract fun buildSelfClassType(symbol: KtClassOrObjectSymbol): 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.declarations.FirResolvePhase
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents
|
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.ConeClassLikeTypeImpl
|
||||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.ValidityToken
|
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.fir.types.PublicTypeApproximator
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
|
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
|
||||||
|
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||||
|
|
||||||
internal class KtFirTypeProvider(
|
internal class KtFirTypeProvider(
|
||||||
override val analysisSession: KtFirAnalysisSession,
|
override val analysisSession: KtFirAnalysisSession,
|
||||||
@@ -26,14 +28,14 @@ internal class KtFirTypeProvider(
|
|||||||
override val builtinTypes: KtBuiltinTypes =
|
override val builtinTypes: KtBuiltinTypes =
|
||||||
KtFirBuiltInTypes(analysisSession.firResolveState.rootModuleSession.builtinTypes, analysisSession.firSymbolBuilder, token)
|
KtFirBuiltInTypes(analysisSession.firResolveState.rootModuleSession.builtinTypes, analysisSession.firSymbolBuilder, token)
|
||||||
|
|
||||||
override fun approximateToPublicDenotable(type: KtType): KtType? {
|
override fun approximateToSuperPublicDenotableType(type: KtType): KtType? {
|
||||||
require(type is KtFirType)
|
require(type is KtFirType)
|
||||||
val coneType = type.coneType
|
val coneType = type.coneType
|
||||||
val approximatedConeType = PublicTypeApproximator.approximateTypeToPublicDenotable(
|
val approximatedConeType = PublicTypeApproximator.approximateTypeToPublicDenotable(
|
||||||
coneType,
|
coneType,
|
||||||
rootModuleSession.inferenceComponents.ctx,
|
|
||||||
rootModuleSession
|
rootModuleSession
|
||||||
)
|
)
|
||||||
|
|
||||||
return approximatedConeType?.asKtType()
|
return approximatedConeType?.asKtType()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,3 +52,4 @@ internal class KtFirTypeProvider(
|
|||||||
return type.asKtType()
|
return type.asKtType()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-115
@@ -6,128 +6,25 @@
|
|||||||
package org.jetbrains.kotlin.idea.frontend.api.fir.types
|
package org.jetbrains.kotlin.idea.frontend.api.fir.types
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents
|
||||||
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.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
|
||||||
import org.jetbrains.kotlin.types.Variance
|
|
||||||
|
|
||||||
internal object PublicTypeApproximator {
|
internal object PublicTypeApproximator {
|
||||||
fun approximateTypeToPublicDenotable(
|
fun approximateTypeToPublicDenotable(
|
||||||
type: ConeKotlinType,
|
type: ConeKotlinType,
|
||||||
context: ConeInferenceContext,
|
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
): ConeKotlinType? = approximate(type, context, session) as ConeKotlinType?
|
): ConeKotlinType? {
|
||||||
|
val approximator = session.inferenceComponents.approximator
|
||||||
private fun approximate(
|
return approximator.approximateToSuperType(type, PublicApproximatorConfiguration) as ConeKotlinType?
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun approximateClassLikeType(
|
private object PublicApproximatorConfiguration : TypeApproximatorConfiguration.AllFlexibleSameValue() {
|
||||||
typeImpl: ConeClassLikeTypeImpl,
|
override val allFlexible: Boolean get() = false
|
||||||
context: ConeInferenceContext,
|
override val errorType: Boolean get() = true
|
||||||
session: FirSession,
|
override val definitelyNotNullType: Boolean get() = false
|
||||||
): ConeTypeProjection? {
|
override val integerLiteralType: Boolean get() = true
|
||||||
val regularClass = typeImpl.classOrAnonymousClass(session) ?: return null
|
override val intersectionTypesInContravariantPositions: Boolean get() = true
|
||||||
val type = if (needApproximationAsSuperType(regularClass)) {
|
override val localTypes: Boolean get() = true
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user