diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirLookupElementFactory.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirLookupElementFactory.kt index 5f42e22a93b..9ed8bdef843 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirLookupElementFactory.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirLookupElementFactory.kt @@ -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 { 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 58962276c6a..9c022a268e4 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 @@ -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) 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 38bcd0906d7..587da915d6f 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 @@ -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 diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/types/KtType.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/types/KtType.kt index 56bffaa6994..6a7ff0a9ac0 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/types/KtType.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/types/KtType.kt @@ -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 } +abstract class KtFunctionalType : KtClassType() { + abstract val isSuspend: Boolean + abstract val arity: Int + abstract val receiverType: KtType? + abstract val parameterTypes: List + abstract val returnType: KtType +} + +abstract class KtUsualClassType : KtClassType() + abstract class KtErrorType : KtType { abstract val error: String } 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 ed58a6588f2..f8eed28fe78 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 @@ -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 ): PsiClassType? { if (this !is KtClassType) return null - require(this is KtFirClassType) + require(this is KtFirType) val contextSymbol = classSymbol require(contextSymbol is KtFirSymbol<*>) diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtSymbolByFirBuilder.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtSymbolByFirBuilder.kt index 1fab2ac2dc5..493688cf636 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtSymbolByFirBuilder.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtSymbolByFirBuilder.kt @@ -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) diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirBuiltInTypes.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirBuiltInTypes.kt index 605bef300c7..96566b5ca79 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirBuiltInTypes.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirBuiltInTypes.kt @@ -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 = cached { + KtFirUsualClassType(builtinTypeRef.type as ConeClassLikeTypeImpl, token, builder) // TODO builder leaking } } \ No newline at end of file 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 1bf05a63ae6..3fddeed7a34 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 @@ -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) diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/types/FirKtType.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/types/FirKtType.kt index 30f1b39c1fe..c7a78758424 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/types/FirKtType.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/types/FirKtType.kt @@ -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 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 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,