FIR IDE: introduce KtFunctionalType

This commit is contained in:
Ilya Kirillov
2021-02-02 12:47:50 +01:00
parent 0551834164
commit a10f54befa
9 changed files with 77 additions and 23 deletions
@@ -19,6 +19,8 @@ import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.symbols.*
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtNamedSymbol
import org.jetbrains.kotlin.idea.frontend.api.types.KtFunctionalType
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtTypeArgumentList
@@ -109,7 +111,7 @@ private class FunctionLookupElementFactory {
private fun KtAnalysisSession.insertLambdaBraces(symbol: KtFunctionSymbol): Boolean {
val singleParam = symbol.valueParameters.singleOrNull()
return singleParam != null && !singleParam.hasDefaultValue && singleParam.annotatedType.type.isBuiltInFunctionalType()
return singleParam != null && !singleParam.hasDefaultValue && singleParam.annotatedType.type is KtFunctionalType
}
private fun KtAnalysisSession.createInsertHandler(symbol: KtFunctionSymbol): InsertHandler<LookupElement> {
@@ -77,8 +77,6 @@ abstract class KtAnalysisSession(final override val token: ValidityToken) : Vali
fun PsiElement.getExpectedType(): KtType? = expressionTypeProvider.getExpectedType(this)
fun KtType.isBuiltInFunctionalType(): Boolean = typeProvider.isBuiltinFunctionalType(this)
val builtinTypes: KtBuiltinTypes get() = typeProvider.builtinTypes
fun KtClassOrObjectSymbol.buildSelfClassType(): KtType = typeProvider.buildSelfClassType(this)
@@ -5,14 +5,12 @@
package org.jetbrains.kotlin.idea.frontend.api.components
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.idea.frontend.api.ValidityTokenOwner
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
abstract class KtTypeProvider : KtAnalysisSessionComponent() {
//TODO get rid of it
abstract fun isBuiltinFunctionalType(type: KtType): Boolean
abstract val builtinTypes: KtBuiltinTypes
abstract fun buildSelfClassType(symbol: KtClassOrObjectSymbol): KtType
@@ -33,12 +33,22 @@ sealed class KtDenotableType : KtType {
abstract fun asString(): String
}
abstract class KtClassType : KtDenotableType(), KtTypeWithNullability {
sealed class KtClassType : KtDenotableType(), KtTypeWithNullability {
abstract val classId: ClassId
abstract val classSymbol: KtClassLikeSymbol
abstract val typeArguments: List<KtTypeArgument>
}
abstract class KtFunctionalType : KtClassType() {
abstract val isSuspend: Boolean
abstract val arity: Int
abstract val receiverType: KtType?
abstract val parameterTypes: List<KtType>
abstract val returnType: KtType
}
abstract class KtUsualClassType : KtClassType()
abstract class KtErrorType : KtType {
abstract val error: String
}
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.api.withFirDeclaration
import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirClassOrObjectSymbol
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirClassType
import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirType
import org.jetbrains.kotlin.idea.frontend.api.symbols.*
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.*
@@ -161,7 +160,7 @@ internal fun KtType.mapSupertype(
annotations: List<KtAnnotationCall>
): PsiClassType? {
if (this !is KtClassType) return null
require(this is KtFirClassType)
require(this is KtFirType)
val contextSymbol = classSymbol
require(contextSymbol is KtFirSymbol<*>)
@@ -9,10 +9,12 @@ import com.google.common.collect.MapMaker
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
import org.jetbrains.kotlin.fir.resolve.inference.isFunctionalType
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
@@ -47,6 +49,8 @@ internal class KtSymbolByFirBuilder private constructor(
private val resolveState by weakRef(resolveState)
private val firProvider get() = resolveState.rootModuleSession.symbolProvider
val rootSession: FirSession = resolveState.rootModuleSession
constructor(
resolveState: FirModuleResolveState,
@@ -205,7 +209,10 @@ internal class KtSymbolByFirBuilder private constructor(
fun buildKtType(coneType: ConeKotlinType): KtType = typesCache.cache(coneType) {
when (coneType) {
is ConeClassLikeTypeImpl -> KtFirClassType(coneType, token, this)
is ConeClassLikeTypeImpl -> {
if (coneType.isFunctionalType(rootSession)) KtFirFunctionalType(coneType, token, this)
else KtFirUsualClassType(coneType, token, this)
}
is ConeTypeParameterType -> KtFirTypeParameterType(coneType, token, this)
is ConeClassErrorType -> KtFirErrorType(coneType, token)
is ConeFlexibleType -> KtFirFlexibleType(coneType, token, this)
@@ -11,7 +11,8 @@ import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef
import org.jetbrains.kotlin.idea.frontend.api.ValidityToken
import org.jetbrains.kotlin.idea.frontend.api.components.KtBuiltinTypes
import org.jetbrains.kotlin.idea.frontend.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirClassType
import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirUsualClassType
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.ValidityAwareCachedValue
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.cached
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
@@ -39,7 +40,7 @@ internal class KtFirBuiltInTypes(builtinTypes: BuiltinTypes, builder: KtSymbolBy
override val NULLABLE_ANY: KtType by cachedBuiltin(builtinTypes.nullableAnyType)
override val NULLABLE_NOTHING: KtType by cachedBuiltin(builtinTypes.nullableNothingType)
private fun cachedBuiltin(builtinTypeRef: FirImplicitBuiltinTypeRef) = cached {
KtFirClassType(builtinTypeRef.type as ConeClassLikeTypeImpl, token, builder) // TODO builder leaking
private fun cachedBuiltin(builtinTypeRef: FirImplicitBuiltinTypeRef): ValidityAwareCachedValue<KtFirUsualClassType> = cached {
KtFirUsualClassType(builtinTypeRef.type as ConeClassLikeTypeImpl, token, builder) // TODO builder leaking
}
}
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.idea.frontend.api.fir.components
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.idea.frontend.api.ValidityToken
@@ -23,11 +22,6 @@ internal class KtFirTypeProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtTypeProvider(), KtFirAnalysisSessionComponent {
override fun isBuiltinFunctionalType(type: KtType): Boolean = withValidityAssertion {
check(type is KtFirType)
type.coneType.isBuiltinFunctionalType(analysisSession.firResolveState.rootModuleSession) //TODO use correct session here
}
override val builtinTypes: KtBuiltinTypes =
KtFirBuiltInTypes(analysisSession.firResolveState.rootModuleSession.builtinTypes, analysisSession.firSymbolBuilder, token)
@@ -5,8 +5,7 @@
package org.jetbrains.kotlin.idea.frontend.api.fir.types
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
import org.jetbrains.kotlin.fir.resolve.inference.isSuspendFunctionType
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.idea.frontend.api.*
@@ -26,11 +25,11 @@ internal interface KtFirType : KtType, ValidityTokenOwner {
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
}
internal class KtFirClassType(
internal class KtFirUsualClassType(
coneType: ConeClassLikeTypeImpl,
override val token: ValidityToken,
private val firBuilder: KtSymbolByFirBuilder,
) : KtClassType(), KtFirType {
) : KtUsualClassType(), KtFirType {
override val coneType by weakRef(coneType)
override val classId: ClassId get() = withValidityAssertion { coneType.lookupTag.classId }
@@ -50,6 +49,52 @@ internal class KtFirClassType(
}
}
internal class KtFirFunctionalType(
coneType: ConeClassLikeTypeImpl,
override val token: ValidityToken,
private val firBuilder: KtSymbolByFirBuilder,
) : KtFunctionalType(), KtFirType {
override val coneType by weakRef(coneType)
override val classId: ClassId get() = withValidityAssertion { coneType.lookupTag.classId }
override val classSymbol: KtClassLikeSymbol by cached {
firBuilder.buildClassLikeSymbolByLookupTag(coneType.lookupTag) ?: error("Class ${coneType.lookupTag} was not found")
}
override val typeArguments: List<KtTypeArgument> by cached {
coneType.typeArguments.map { typeArgument ->
firBuilder.buildTypeArgument(typeArgument)
}
}
override val nullability: KtTypeNullability get() = withValidityAssertion { KtTypeNullability.create(coneType.isNullable) }
override val isSuspend: Boolean get() = withValidityAssertion { coneType.isSuspendFunctionType(firBuilder.rootSession) }
override val arity: Int
get() = withValidityAssertion {
if (coneType.isExtensionFunctionType) coneType.typeArguments.size - 2
else coneType.typeArguments.size - 1
}
override val receiverType: KtType?
get() = withValidityAssertion {
if (coneType.isExtensionFunctionType) (typeArguments.first() as KtTypeArgumentWithVariance).type
else null
}
override val parameterTypes: List<KtType> by cached {
val parameterTypeArgs = if (coneType.isExtensionFunctionType) typeArguments.subList(1, typeArguments.lastIndex)
else typeArguments.subList(0, typeArguments.lastIndex)
parameterTypeArgs.map { (it as KtTypeArgumentWithVariance).type }
}
override val returnType: KtType
get() = withValidityAssertion { (typeArguments.last() as KtTypeArgumentWithVariance).type }
override fun asString(): String = withValidityAssertion {
coneType.render() //todo
}
}
internal class KtFirErrorType(
coneType: ConeClassErrorType,
override val token: ValidityToken,