[FIR] Introduce ConeFunctionalTypeKind as a replacement of FunctionClassKind

This is needed to provide an ability to extend different kinds of
  functional types

Also, cleanup and rename utilities related to functional types to avoid
  possible confusions
This commit is contained in:
Dmitriy Novozhilov
2023-01-18 14:12:11 +02:00
committed by Space Team
parent c98c8d3682
commit c86495dcae
40 changed files with 583 additions and 365 deletions
@@ -33,7 +33,14 @@ internal class KtFirTypeInfoProvider(
override fun getFunctionClassKind(type: KtType): FunctionClassKind? {
val coneType = (type as KtFirType).coneType
return coneType.functionClassKind(analysisSession.useSiteSession)
return when (coneType.functionalTypeKind(analysisSession.useSiteSession)) {
ConeFunctionalTypeKind.Function -> FunctionClassKind.Function
ConeFunctionalTypeKind.KFunction -> FunctionClassKind.KFunction
ConeFunctionalTypeKind.SuspendFunction -> FunctionClassKind.SuspendFunction
ConeFunctionalTypeKind.KSuspendFunction -> FunctionClassKind.KSuspendFunction
null -> null
else -> null // TODO: consider handling of custom functional type kinds from plugins
}
}
override fun canBeNull(type: KtType): Boolean = (type as KtFirType).coneType.canBeNull
@@ -49,9 +49,10 @@ internal class KtFirFunctionalType(
override val nullability: KtTypeNullability get() = withValidityAssertion { coneType.nullability.asKtNullability() }
override val isSuspend: Boolean get() = withValidityAssertion { coneType.isSuspendOrKSuspendFunctionType(builder.rootSession) }
override val isSuspend: Boolean get() = withValidityAssertion { coneType.isSuspendFunctionType(builder.rootSession) }
override val isReflectType: Boolean get() = withValidityAssertion { coneType.isKFunctionType(builder.rootSession) }
override val isReflectType: Boolean
get() = withValidityAssertion { coneType.functionalTypeKind(builder.rootSession)?.isReflectType == true }
override val arity: Int
get() = withValidityAssertion {
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.isAbstract
import org.jetbrains.kotlin.fir.declarations.utils.isInline
import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isSuspendOrKSuspendFunctionType
import org.jetbrains.kotlin.fir.types.isSuspendFunctionType
import org.jetbrains.kotlin.name.JvmNames.SYNCHRONIZED_ANNOTATION_CLASS_ID
object FirSynchronizedAnnotationChecker : FirFunctionChecker() {
@@ -33,7 +33,7 @@ object FirSynchronizedAnnotationChecker : FirFunctionChecker() {
return
}
if (declaration.isSuspend ||
(declaration as? FirAnonymousFunction)?.typeRef?.coneType?.isSuspendOrKSuspendFunctionType(session) == true
(declaration as? FirAnonymousFunction)?.typeRef?.coneType?.isSuspendFunctionType(session) == true
) {
reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_ON_SUSPEND, context)
return
@@ -46,4 +46,4 @@ object FirSynchronizedAnnotationChecker : FirFunctionChecker() {
reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_ON_ABSTRACT, context)
}
}
}
}
@@ -278,7 +278,7 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() {
}
private fun FirTypeRef?.isFunctionalTypeRef(session: FirSession): Boolean {
return this?.coneType?.isBuiltinFunctionalType(session) == true
return this?.coneType?.isSomeFunctionalType(session) == true
}
private fun FirContractDescription?.getParameterCallsEffectDeclaration(index: Int): ConeCallsEffectDeclaration? {
@@ -144,7 +144,7 @@ internal fun checkConstantArguments(
}
expression is FirQualifiedAccessExpression -> {
val expressionType = expression.typeRef.coneType
if (expressionType.isKFunctionType(session) || expressionType.isKProperty(session) || expressionType.isKMutableProperty(session)) {
if (expressionType.isReflectFunctionalType(session) || expressionType.isKProperty(session) || expressionType.isKMutableProperty(session)) {
return checkConstantArguments(expression.dispatchReceiver, session)
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.builtins.StandardNames.BACKING_FIELD
import org.jetbrains.kotlin.builtins.functions.isSuspendType
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.Visibilities
@@ -61,7 +62,7 @@ abstract class FirInlineDeclarationChecker : FirFunctionChecker() {
val inalienableParameters = function.valueParameters.filter {
if (it.isNoinline) return@filter false
val type = it.returnTypeRef.coneType
!type.isMarkedNullable && type.isFunctionalType(context.session) { kind -> !kind.isReflectType }
!type.isMarkedNullable && type.isNonReflectFunctionalType(context.session)
}.map { it.symbol }
val visitor = inlineVisitor(
@@ -233,7 +234,7 @@ abstract class FirInlineDeclarationChecker : FirFunctionChecker() {
// TODO: receivers are currently not inline (KT-5837)
// if (targetSymbol.isInline) return true
return targetSymbol.name == OperatorNameConventions.INVOKE &&
targetSymbol.dispatchReceiverType?.isBuiltinFunctionalType(session) == true
targetSymbol.dispatchReceiverType?.isSomeFunctionalType(session) == true
}
private fun checkQualifiedAccess(
@@ -404,8 +405,9 @@ abstract class FirInlineDeclarationChecker : FirFunctionChecker() {
) {
for (param in function.valueParameters) {
val coneType = param.returnTypeRef.coneType
val isFunctionalType = coneType.isFunctionalType(context.session)
val isSuspendFunctionalType = coneType.isSuspendOrKSuspendFunctionType(context.session)
val functionalKind = coneType.functionalTypeKind(context.session)
val isFunctionalType = functionalKind != null
val isSuspendFunctionalType = functionalKind?.isSuspendType == true
val defaultValue = param.defaultValue
if (!(isFunctionalType || isSuspendFunctionalType) && (param.isNoinline || param.isCrossinline)) {
@@ -488,7 +490,7 @@ abstract class FirInlineDeclarationChecker : FirFunctionChecker() {
function.valueParameters.any { param ->
val type = param.returnTypeRef.coneType
!param.isNoinline && !type.isNullable
&& (type.isFunctionalType(session) || type.isSuspendOrKSuspendFunctionType(session))
&& (type.isSimpleFunctionType(session) || type.isSuspendFunctionType(session))
}
if (hasInlinableParameters) return
if (function.isInlineOnly(session)) return
@@ -130,7 +130,7 @@ object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() {
private fun findEnclosingSuspendFunction(context: CheckerContext): FirFunction? {
return context.containingDeclarations.lastOrNull {
when (it) {
is FirAnonymousFunction -> it.typeRef.coneType.isSuspendOrKSuspendFunctionType(context.session)
is FirAnonymousFunction -> it.typeRef.coneType.isSuspendFunctionType(context.session)
is FirSimpleFunction -> it.isSuspend
else -> false
}
@@ -218,7 +218,7 @@ object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() {
calledDeclarationSymbol: FirCallableSymbol<*>
): Triple<FirExpression?, FirExpression?, ConeKotlinType?> {
if (this is FirImplicitInvokeCall &&
dispatchReceiver != FirNoReceiverExpression && dispatchReceiver.typeRef.coneType.isSuspendOrKSuspendFunctionType(session)
dispatchReceiver != FirNoReceiverExpression && dispatchReceiver.typeRef.coneType.isSuspendFunctionType(session)
) {
val variableForInvoke = dispatchReceiver
val variableForInvokeType = variableForInvoke.typeRef.coneType
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isFunctionalType
import org.jetbrains.kotlin.fir.types.isSimpleFunctionType
object UnusedChecker : AbstractFirPropertyInitializationChecker() {
override fun analyze(data: PropertyInitializationInfoData, reporter: DiagnosticReporter, context: CheckerContext) {
@@ -278,7 +278,7 @@ object UnusedChecker : AbstractFirPropertyInitializationChecker() {
val reference = node.fir.calleeReference.resolved ?: return dataForNode
val functionSymbol = reference.resolvedSymbol as? FirFunctionSymbol<*> ?: return dataForNode
val symbol = if (functionSymbol.callableId.callableName.identifier == "invoke") {
localProperties.find { it.name == reference.name && it.resolvedReturnTypeRef.coneType.isFunctionalType(session) }
localProperties.find { it.name == reference.name && it.resolvedReturnTypeRef.coneType.isSimpleFunctionType(session) }
} else null
symbol ?: return dataForNode
@@ -7,15 +7,15 @@ package org.jetbrains.kotlin.fir.analysis.checkers.type
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getAllowedAnnotationTargets
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.isBuiltinFunctionalType
import org.jetbrains.kotlin.fir.types.isSomeFunctionalType
import org.jetbrains.kotlin.name.StandardClassIds
object FirTypeAnnotationChecker : FirTypeRefChecker() {
@@ -33,7 +33,7 @@ object FirTypeAnnotationChecker : FirTypeRefChecker() {
}
}
if (annotation.toAnnotationClassId(context.session) == StandardClassIds.Annotations.ExtensionFunctionType) {
if (!typeRef.type.isBuiltinFunctionalType(context.session)) {
if (!typeRef.type.isSomeFunctionalType(context.session)) {
if (context.languageVersionSettings.supportsFeature(LanguageFeature.ForbidExtensionFunctionTypeOnNonFunctionTypes)) {
reporter.reportOn(annotation.source, FirErrors.WRONG_EXTENSION_FUNCTION_TYPE, context)
} else {
@@ -5,21 +5,20 @@
package org.jetbrains.kotlin.fir.renderer
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.fir.types.*
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
open class ConeTypeRenderer() {
open class ConeTypeRenderer {
lateinit var builder: StringBuilder
lateinit var idRenderer: ConeIdRenderer
open fun renderAsPossibleFunctionType(
type: ConeKotlinType, renderType: ConeTypeProjection.() -> Unit = { render() }
type: ConeKotlinType,
functionalClassKindExtractor: (ConeKotlinType) -> ConeFunctionalTypeKind?,
renderType: ConeTypeProjection.() -> Unit = { render() }
) {
val kind = type.functionTypeKind
if (!kind.withPrettyRender()) {
val kind = functionalClassKindExtractor(type)
if (kind?.isReflectType != false) {
type.renderType()
return
}
@@ -27,8 +26,9 @@ open class ConeTypeRenderer() {
if (type.isMarkedNullable) {
builder.append("(")
}
if (kind == FunctionClassKind.SuspendFunction) {
builder.append("suspend ")
kind.prefixForTypeRender?.let {
builder.append(it)
builder.append(" ")
}
val typeArguments = type.typeArguments
val isExtension = type.isExtensionFunctionType
@@ -57,14 +57,6 @@ open class ConeTypeRenderer() {
}
}
@OptIn(ExperimentalContracts::class)
private fun FunctionClassKind?.withPrettyRender(): Boolean {
contract {
returns(true) implies (this@withPrettyRender != null)
}
return this != null && this != FunctionClassKind.KSuspendFunction && this != FunctionClassKind.KFunction
}
fun render(type: ConeKotlinType) {
if (type !is ConeFlexibleType && type !is ConeDefinitelyNotNullType) {
// We don't render attributes for flexible/definitely not null types here,
@@ -216,4 +208,4 @@ open class ConeTypeRenderer() {
}
}
}
}
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.renderer
import org.jetbrains.kotlin.fir.types.ConeFunctionalTypeKind
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeTypeProjection
@@ -16,9 +17,13 @@ class ConeTypeRendererForDebugging() : ConeTypeRenderer() {
idRenderer.builder = builder
}
override fun renderAsPossibleFunctionType(type: ConeKotlinType, renderType: ConeTypeProjection.() -> Unit) {
override fun renderAsPossibleFunctionType(
type: ConeKotlinType,
functionalClassKindExtractor: (ConeKotlinType) -> ConeFunctionalTypeKind?,
renderType: ConeTypeProjection.() -> Unit
) {
builder.append("R|")
super.renderAsPossibleFunctionType(type, renderType)
super.renderAsPossibleFunctionType(type, functionalClassKindExtractor, renderType)
builder.append("|")
}
}
}
@@ -0,0 +1,128 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.types
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
/**
* [ConeFunctionalTypeKind] describes a family of various similar functional types (like kotlin.FunctionN)
* All types in the same family have corresponding shape of classId: [packageFqName].[classNamePrefix]N,
* where `N` is an arity of function
*
* Functional type kind may be either reflect type or non-reflect type
* Each non-reflect kind should have corresponding reflect kind and vice-versa (like `kotlin.FunctionN` and `kotlin.reflection.KFunctionN`)
*
* Classes for such functional types are synthetic and generated by compiler itself
* [annotationOnInvokeClassId] is a classId of annotation, which will be added to `invoke` function of generated
* functional interface. This argument is mandatory for non-standard functional kinds
*
* Assume we have `some.CustomFunctionN` and `some.KCustomFunctionN` families with [annotationOnInvokeClassId] = /some.Anno
* Classes for those kinds will look like this:
*
* interface CustomFunctionN<P1, P2, ..., PN, R> : kotlin.Function<R> {
* @some.Anno
* operator fun invoke(p1: P1, p2: P2, ..., pN: PN): R
* }
*
* interface KCustomFunctionN<P1, P2, ..., PN, R> : kotlin.reflect.KFunction<R>, some.CustomFunctionN<P1, P2, ..., PN, R> {
* @some.Anno
* override operator fun invoke(p1: P1, p2: P2, ..., pN: PN): R
* }
*
* Note that if you provide some new functional type kind it's your responsibility to handle all references to it in backend
* with [IrGenerationExtension] implementation
*/
abstract class ConeFunctionalTypeKind internal constructor(
val packageFqName: FqName,
val classNamePrefix: String,
val isReflectType: Boolean,
val annotationOnInvokeClassId: ClassId?
) {
/*
* This constructor is needed to enforce not nullable [annotationOnInvokeClassId] for
* functional kinds provided by compiler plugins
*/
constructor(
packageFqName: FqName,
classNamePrefix: String,
annotationOnInvokeClassId: ClassId,
isReflectType: Boolean
) : this(packageFqName, classNamePrefix, isReflectType, annotationOnInvokeClassId)
/*
* Specifies how corresponding type will be rendered
* E.g. if `prefixForTypeRender = @Some` and type is `some.CustomFunction2<Int, String, Double>`,
* then type will be rendered as `@Some (Int, String) -> Double`
*/
open val prefixForTypeRender: String?
get() = null
/**
* @return corresponding non-reflect kind for reflect kind
* @return [this] if [isReflectType] is false
*
* Should be overridden for reflect kinds
*/
open fun nonReflectKind(): ConeFunctionalTypeKind {
return if (isReflectType) error("Should be overridden explicitly") else this
}
/**
* @return corresponding reflect kind for non-reflect kind
* @return [this] if [isReflectType] is true
*
* Should be overridden for non reflect kinds
*/
open fun reflectKind(): ConeFunctionalTypeKind {
return if (isReflectType) this else error("Should be overridden explicitly")
}
fun numberedClassName(arity: Int): Name = Name.identifier("$classNamePrefix$arity")
// ------------------------------------------- Builtin functional kinds -------------------------------------------
object Function : ConeFunctionalTypeKind(
StandardNames.BUILT_INS_PACKAGE_FQ_NAME,
"Function",
isReflectType = false,
annotationOnInvokeClassId = null
) {
override fun reflectKind(): ConeFunctionalTypeKind = KFunction
}
object SuspendFunction : ConeFunctionalTypeKind(
StandardNames.COROUTINES_PACKAGE_FQ_NAME,
"SuspendFunction",
isReflectType = false,
annotationOnInvokeClassId = null
) {
override val prefixForTypeRender: String
get() = "suspend"
override fun reflectKind(): ConeFunctionalTypeKind = KSuspendFunction
}
object KFunction : ConeFunctionalTypeKind(
StandardNames.KOTLIN_REFLECT_FQ_NAME,
"KFunction",
isReflectType = true,
annotationOnInvokeClassId = null
) {
override fun nonReflectKind(): ConeFunctionalTypeKind = Function
}
object KSuspendFunction : ConeFunctionalTypeKind(
StandardNames.KOTLIN_REFLECT_FQ_NAME,
"KSuspendFunction",
isReflectType = true,
annotationOnInvokeClassId = null
) {
override fun nonReflectKind(): ConeFunctionalTypeKind = SuspendFunction
}
}
@@ -5,8 +5,10 @@
package org.jetbrains.kotlin.fir.types
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.fir.renderer.*
import org.jetbrains.kotlin.fir.renderer.ConeIdRendererForDebugging
import org.jetbrains.kotlin.fir.renderer.ConeIdShortRenderer
import org.jetbrains.kotlin.fir.renderer.ConeTypeRendererForDebugging
import org.jetbrains.kotlin.fir.renderer.ConeTypeRendererWithJavaFlexibleTypes
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.types.Variance
@@ -111,14 +113,6 @@ fun ConeClassLikeType.replaceArgumentsWithStarProjections(): ConeClassLikeType {
return withArguments(newArguments)
}
val ConeKotlinType?.functionTypeKind: FunctionClassKind?
get() {
val classId = (this as? ConeClassLikeType)?.lookupTag?.classId ?: return null
return FunctionClassKind.getFunctionalClassKind(
classId.shortClassName.asString(), classId.packageFqName
)
}
fun ConeKotlinType.renderForDebugging(): String {
val builder = StringBuilder()
ConeTypeRendererForDebugging(builder).render(this)
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirIntersectionOverrideStorage
import org.jetbrains.kotlin.fir.scopes.impl.FirSubstitutionOverrideStorage
import org.jetbrains.kotlin.fir.symbols.FirLazyDeclarationResolver
import org.jetbrains.kotlin.fir.types.FirCorrespondingSupertypesCache
import org.jetbrains.kotlin.fir.types.FirFunctionalTypeKindService
import org.jetbrains.kotlin.fir.types.TypeComponents
import org.jetbrains.kotlin.incremental.components.EnumWhenTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
@@ -71,6 +72,9 @@ fun FirSession.registerCommonComponents(languageVersionSettings: LanguageVersion
register(FirSamConstructorStorage::class, FirSamConstructorStorage(this))
register(FirOverrideService::class, FirOverrideService(this))
register(FirDynamicMembersStorage::class, FirDynamicMembersStorage(this))
// TODO: replace with proper implementation
register(FirFunctionalTypeKindService::class, FirFunctionalTypeKindService.Default)
}
@OptIn(SessionConfiguration::class)
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.fir.resolve.providers.impl
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.FirSession
@@ -25,16 +24,15 @@ import org.jetbrains.kotlin.fir.deserialization.FirBuiltinAnnotationDeserializer
import org.jetbrains.kotlin.fir.deserialization.FirConstDeserializer
import org.jetbrains.kotlin.fir.deserialization.FirDeserializationContext
import org.jetbrains.kotlin.fir.deserialization.deserializeClassToSymbol
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyAnnotationArgumentMapping
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.constructClassType
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.fir.types.toLookupTag
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.builtins.BuiltInsBinaryVersion
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
@@ -53,7 +51,7 @@ open class FirBuiltinSymbolProvider(
val kotlinScopeProvider: FirKotlinScopeProvider
) : FirSymbolProvider(session) {
private val allPackageFragments = loadBuiltIns().groupBy { it.fqName }
private val syntheticFunctionalInterfaceCache = SyntheticFunctionalInterfaceCache(moduleData, kotlinScopeProvider)
private val syntheticFunctionalInterfaceCache = SyntheticFunctionalInterfaceCache(session, moduleData, kotlinScopeProvider)
private fun loadBuiltIns(): List<BuiltInsPackageFragment> {
val classLoader = this::class.java.classLoader
@@ -201,7 +199,11 @@ private data class BinaryVersionAndPackageFragment(
}
}
private class SyntheticFunctionalInterfaceCache(private val moduleData: FirModuleData, private val kotlinScopeProvider: FirKotlinScopeProvider) {
private class SyntheticFunctionalInterfaceCache(
private val session: FirSession,
private val moduleData: FirModuleData,
private val kotlinScopeProvider: FirKotlinScopeProvider
) {
private val syntheticFunctionalInterfaceCache =
moduleData.session.firCachesFactory.createCache(::createSyntheticFunctionalInterface)
@@ -212,7 +214,7 @@ private class SyntheticFunctionalInterfaceCache(private val moduleData: FirModul
private fun createSyntheticFunctionalInterface(classId: ClassId): FirRegularClassSymbol? {
return with(classId) {
val className = relativeClassName.asString()
val kind = FunctionClassKind.byClassNamePrefix(packageFqName, className) ?: return@with null
val kind = session.functionalTypeService.getKindByClassNamePrefix(packageFqName, className) ?: return null
val prefix = kind.classNamePrefix
val arity = className.substring(prefix.length).toIntOrNull() ?: return null
FirRegularClassSymbol(classId).apply symbol@{
@@ -279,55 +281,30 @@ private class SyntheticFunctionalInterfaceCache(private val moduleData: FirModul
isTailRec = false
isExternal = false
isSuspend =
kind == FunctionClassKind.SuspendFunction ||
kind == FunctionClassKind.KSuspendFunction
kind == ConeFunctionalTypeKind.SuspendFunction ||
kind == ConeFunctionalTypeKind.KSuspendFunction
}
val typeArguments = typeParameters.map {
buildResolvedTypeRef {
type = ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false)
}
ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false).toFirResolvedTypeRef()
}
fun createSuperType(
kind: FunctionClassKind,
): FirResolvedTypeRef {
return buildResolvedTypeRef {
type = kind.classId(arity).toLookupTag()
.constructClassType(typeArguments.map { it.type }.toTypedArray(), isNullable = false)
}
fun createSuperType(kind: ConeFunctionalTypeKind): FirResolvedTypeRef {
return kind.classId(arity).toLookupTag()
.constructClassType(typeArguments.map { it.type }.toTypedArray(), isNullable = false)
.toFirResolvedTypeRef()
}
superTypeRefs += when (kind) {
FunctionClassKind.Function -> listOf(
buildResolvedTypeRef {
type = StandardClassIds.Function.toLookupTag()
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
}
)
FunctionClassKind.SuspendFunction -> listOf(
buildResolvedTypeRef {
type = StandardClassIds.Function.toLookupTag()
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
}
)
FunctionClassKind.KFunction -> listOf(
buildResolvedTypeRef {
type = StandardClassIds.KFunction.toLookupTag()
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
},
createSuperType(FunctionClassKind.Function)
)
FunctionClassKind.KSuspendFunction -> listOf(
buildResolvedTypeRef {
type = StandardClassIds.KFunction.toLookupTag()
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
},
createSuperType(FunctionClassKind.SuspendFunction)
)
if (kind.isReflectType) {
superTypeRefs += StandardClassIds.KFunction.toLookupTag()
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
.toFirResolvedTypeRef()
superTypeRefs += createSuperType(kind.nonReflectKind())
} else {
superTypeRefs += StandardClassIds.Function.toLookupTag()
.constructClassType(arrayOf(typeArguments.last().type), isNullable = false)
.toFirResolvedTypeRef()
}
addDeclaration(
buildSimpleFunction {
moduleData = this@SyntheticFunctionalInterfaceCache.moduleData
@@ -357,6 +334,14 @@ private class SyntheticFunctionalInterfaceCache(private val moduleData: FirModul
}
}
dispatchReceiverType = classId.defaultType(this@klass.typeParameters.map { it.symbol })
kind.annotationOnInvokeClassId?.let { annotationClassId ->
annotations += buildAnnotation {
annotationTypeRef = annotationClassId
.constructClassLikeType(emptyArray(), isNullable = false)
.toFirResolvedTypeRef()
argumentMapping = FirEmptyAnnotationArgumentMapping
}
}
}
)
}
@@ -364,6 +349,5 @@ private class SyntheticFunctionalInterfaceCache(private val moduleData: FirModul
}
}
private fun FunctionClassKind.classId(arity: Int) = ClassId(packageFqName, numberedClassName(arity))
private fun ConeFunctionalTypeKind.classId(arity: Int) = ClassId(packageFqName, numberedClassName(arity))
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.serialization
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKind
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ClassKind
@@ -681,7 +682,7 @@ class FirElementSerializer private constructor(
return lowerBound
}
is ConeClassLikeType -> {
if (type.isSuspendFunctionType(session)) {
if (type.functionalTypeKind(session) == FunctionalTypeKind.SuspendFunction) {
val runtimeFunctionType = type.suspendFunctionTypeToFunctionTypeWithContinuation(
session, StandardClassIds.Continuation
)
@@ -5,11 +5,14 @@
package org.jetbrains.kotlin.fir.serialization
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.diagnostics.ConeIntermediateDiagnostic
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.types.ConeErrorType
import org.jetbrains.kotlin.fir.types.typeContext
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.types.AbstractTypeApproximator
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
@@ -21,3 +24,22 @@ class TypeApproximatorForMetadataSerializer(session: FirSession) :
}
}
fun ConeKotlinType.suspendFunctionTypeToFunctionTypeWithContinuation(session: FirSession, continuationClassId: ClassId): ConeClassLikeType {
require(this.isSuspendFunctionType(session))
val kind =
if (isReflectFunctionalType(session)) FunctionClassKind.KFunction
else FunctionClassKind.Function
val fullyExpandedType = type.fullyExpandedType(session)
val typeArguments = fullyExpandedType.typeArguments
val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(typeArguments.size))
val lastTypeArgument = typeArguments.last()
return ConeClassLikeTypeImpl(
functionalTypeId.toLookupTag(),
typeArguments = (typeArguments.dropLast(1) + continuationClassId.toLookupTag().constructClassType(
arrayOf(lastTypeArgument),
isNullable = false
) + lastTypeArgument).toTypedArray(),
isNullable = fullyExpandedType.isNullable,
attributes = fullyExpandedType.attributes
)
}
@@ -233,8 +233,8 @@ class FirJvmSerializerExtension(
private fun FirFunction.needsInlineParameterNullCheckRequirement(): Boolean =
this is FirSimpleFunction && isInline && !isSuspend && !isParamAssertionsDisabled &&
!Visibilities.isPrivate(visibility) &&
(valueParameters.any { it.returnTypeRef.coneType.isBuiltinFunctionalType(session) } ||
receiverParameter?.typeRef?.coneType?.isBuiltinFunctionalType(session) == true)
(valueParameters.any { it.returnTypeRef.coneType.isSomeFunctionalType(session) } ||
receiverParameter?.typeRef?.coneType?.isSomeFunctionalType(session) == true)
override fun serializeProperty(
property: FirProperty,
@@ -172,8 +172,8 @@ class FirJvmTypeMapper(val session: FirSession) : FirSessionComponent {
val parameters = classifier?.typeParameters.orEmpty().map { it.symbol }
val arguments = type.arguments
if ((defaultType.isFunctionalType(session) && arguments.size > BuiltInFunctionArity.BIG_ARITY)
|| defaultType.isKFunctionType(session)
if ((defaultType.isSimpleFunctionType(session) && arguments.size > BuiltInFunctionArity.BIG_ARITY)
|| defaultType.isReflectFunctionalType(session)
) {
writeGenericArguments(sw, listOf(arguments.last()), listOf(parameters.last()), mode)
return
@@ -264,7 +264,7 @@ class ConeTypeSystemCommonBackendContextForTypeMapping(
override fun SimpleTypeMarker.isSuspendFunction(): Boolean {
require(this is ConeSimpleKotlinType)
return isSuspendOrKSuspendFunctionType(session)
return isSuspendFunctionType(session)
}
override fun SimpleTypeMarker.isKClass(): Boolean {
@@ -538,7 +538,7 @@ class Fir2IrDeclarationStorage(
?: if (isLambda) SpecialNames.ANONYMOUS else Name.special("<no name provided>")
val visibility = simpleFunction?.visibility ?: Visibilities.Local
val isSuspend =
if (isLambda) ((function as FirAnonymousFunction).typeRef as? FirResolvedTypeRef)?.type?.isSuspendOrKSuspendFunctionType(session) == true
if (isLambda) ((function as FirAnonymousFunction).typeRef as? FirResolvedTypeRef)?.type?.isSuspendFunctionType(session) == true
else simpleFunction?.isSuspend == true
val created = function.convertWithOffsets { startOffset, endOffset ->
val result = declareIrSimpleFunction(signature, simpleFunction?.containerSource) { symbol ->
@@ -134,7 +134,7 @@ internal class AdapterGenerator(
}
internal fun ConeKotlinType.kFunctionTypeToFunctionType(): IrSimpleType =
kFunctionTypeToFunctionType(session).toIrType() as IrSimpleType
reflectFunctionalTypeToNonReflectFunctionalType(session).toIrType() as IrSimpleType
internal fun generateAdaptedCallableReference(
callableReferenceAccess: FirCallableReferenceAccess,
@@ -479,7 +479,7 @@ internal class AdapterGenerator(
}
// If the expected type is a built-in functional type, we don't need SAM conversion.
val expectedType = argument.getExpectedType(parameter)
if (expectedType is ConeTypeParameterType || expectedType.isBuiltinFunctionalType(session)) {
if (expectedType is ConeTypeParameterType || expectedType.isSomeFunctionalType(session)) {
return false
}
// On the other hand, the actual type should be either a functional type or a subtype of a class that has a contributed `invoke`.
@@ -514,10 +514,10 @@ internal class AdapterGenerator(
return this
}
// Expect the expected type to be a suspend functional type.
if (!parameterType.isSuspendOrKSuspendFunctionType(session)) {
if (!parameterType.isSuspendFunctionType(session)) {
return this
}
val expectedFunctionalType = parameterType.suspendFunctionTypeToFunctionType(session)
val expectedFunctionalType = parameterType.customFunctionalTypeToSimpleFunctionalType(session)
if (this is IrVararg) {
// element-wise conversion if and only if we can build 1-to-1 mapping for elements.
return applyConversionOnVararg(argument) { firVarargArgument ->
@@ -546,9 +546,9 @@ internal class AdapterGenerator(
argument: FirExpression
): IrSimpleFunctionSymbol? {
val argumentType = argument.typeRef.coneType
val argumentTypeWithInvoke = argumentType.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType) ?: return null
val argumentTypeWithInvoke = argumentType.findSubtypeOfSimpleFunctionalType(session, expectedFunctionalType) ?: return null
return if (argumentTypeWithInvoke.isBuiltinFunctionalType(session)) {
return if (argumentTypeWithInvoke.isSomeFunctionalType(session)) {
(argumentTypeWithInvoke as? ConeClassLikeType)?.findBaseInvokeSymbol(session, scopeSession)
} else {
argumentTypeWithInvoke.findContributedInvokeSymbol(
@@ -188,7 +188,7 @@ class CallAndReferenceGenerator(
// This would cause ClassCastException in case of usual type approximation,
// because '{ X1 & ... & Xm }' would be approximated to 'Nothing'.
// JVM_OLD just relies on type mapping for generic argument types in such case.
if (!kotlinType.isKFunctionType(session))
if (!kotlinType.isReflectFunctionalType(session))
return kotlinType
if (kotlinType !is ConeSimpleKotlinType)
return kotlinType
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.fir.resolve.providers.impl
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.NoMutableState
import org.jetbrains.kotlin.fir.caches.FirCache
@@ -19,6 +18,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.functionalTypeService
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -116,7 +116,7 @@ class FirCachingCompositeSymbolProvider(
}
private fun isNameForFunctionClass(classId: ClassId): Boolean {
return FunctionClassKind.byClassNamePrefix(classId.packageFqName, classId.shortClassName.asString()) != null
return session.functionalTypeService.getKindByClassNamePrefix(classId.packageFqName, classId.shortClassName.asString()) != null
}
@OptIn(FirSymbolProviderInternals::class)
@@ -66,7 +66,7 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo
): SimpleTypeMarker {
val attributesList = attributes?.filterIsInstanceTo<ConeAttribute<*>, MutableList<ConeAttribute<*>>>(mutableListOf())
val coneAttributes: ConeAttributes = if (isExtensionFunction) {
require(constructor is ConeClassLikeLookupTag && constructor.isBuiltinFunctionalType())
require(constructor is ConeClassLikeLookupTag && constructor.isSomeFunctionalType(session))
// We don't want to create new instance of ConeAttributes which
// contains only CompilerConeAttributes.ExtensionFunctionType
// to avoid memory consumption
@@ -226,7 +226,7 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo
override fun KotlinTypeMarker.isBuiltinFunctionalTypeOrSubtype(): Boolean {
require(this is ConeKotlinType)
return this.isTypeOrSubtypeOf {
(it.lowerBoundIfFlexible() as ConeKotlinType).isBuiltinFunctionalType(session)
(it.lowerBoundIfFlexible() as ConeKotlinType).isSomeFunctionalType(session)
}
}
@@ -463,7 +463,7 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo
override fun KotlinTypeMarker.isFunctionOrKFunctionWithAnySuspendability(): Boolean {
require(this is ConeKotlinType)
return this.isBuiltinFunctionalType(session)
return this.isSomeFunctionalType(session)
}
private fun ConeKotlinType.isTypeOrSubtypeOf(predicate: (ConeKotlinType) -> Boolean): Boolean {
@@ -519,13 +519,13 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo
return fullyExpandedType(session).let {
val simpleType = it.lowerBoundIfFlexible()
if ((simpleType as ConeKotlinType).isBuiltinFunctionalType(session))
if ((simpleType as ConeKotlinType).isSomeFunctionalType(session))
this
else {
var functionalSupertype: KotlinTypeMarker? = null
simpleType.anySuperTypeConstructor { type ->
simpleType.fastCorrespondingSupertypes(type.typeConstructor())?.any { superType ->
val isFunctional = (superType as ConeKotlinType).isBuiltinFunctionalType(session)
val isFunctional = (superType as ConeKotlinType).isSomeFunctionalType(session)
if (isFunctional)
functionalSupertype = superType
isFunctional
@@ -0,0 +1,248 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.types
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.originalForSubstitutionOverride
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.scope
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.runUnless
// ---------------------------------------------- is type is a functional type ----------------------------------------------
fun ConeKotlinType.functionalTypeKind(session: FirSession): ConeFunctionalTypeKind? {
if (this !is ConeClassLikeType) return null
return fullyExpandedType(session).lookupTag.functionalTypeKind(session)
}
private fun ConeClassLikeLookupTag.functionalTypeKind(session: FirSession): ConeFunctionalTypeKind? {
val classId = classId
return session.functionalTypeService.getKindByClassNamePrefix(classId.packageFqName, classId.shortClassName.asString())
}
private inline fun ConeKotlinType.isFunctionalTypeWithPredicate(
session: FirSession,
errorOnNotFunctionalType: Boolean = false,
predicate: (ConeFunctionalTypeKind) -> Boolean
): Boolean {
val kind = functionalTypeKind(session)
?: if (errorOnNotFunctionalType) error("$this is not a functional type") else return false
return predicate(kind)
}
// Function
fun ConeKotlinType.isSimpleFunctionType(session: FirSession): Boolean {
return isFunctionalTypeWithPredicate(session) { it == ConeFunctionalTypeKind.Function }
}
// Function, SuspendFunction, [Custom]Function
fun ConeKotlinType.isNonReflectFunctionalType(session: FirSession): Boolean {
return isFunctionalTypeWithPredicate(session) { !it.isReflectType }
}
// SuspendFunction, KSuspendFunction
fun ConeKotlinType.isSuspendFunctionType(session: FirSession): Boolean {
return isFunctionalTypeWithPredicate(session) {
it == ConeFunctionalTypeKind.SuspendFunction || it == ConeFunctionalTypeKind.KSuspendFunction
}
}
// KFunction, KSuspendFunction, K[Custom]Function
fun ConeKotlinType.isReflectFunctionalType(session: FirSession): Boolean {
return isFunctionalTypeWithPredicate(session) { it.isReflectType }
}
// Function, SuspendFunction, [Custom]Function, KFunction, KSuspendFunction, K[Custom]Function
fun ConeKotlinType.isSomeFunctionalType(session: FirSession): Boolean {
return functionalTypeKind(session) != null
}
// Function, SuspendFunction, [Custom]Function, KFunction, KSuspendFunction, K[Custom]Function
fun ConeClassLikeLookupTag.isSomeFunctionalType(session: FirSession): Boolean {
return functionalTypeKind(session) != null
}
// Function, KFunction
private fun ConeKotlinType.isSimpleFunctionalType(session: FirSession, errorOnNotFunctionalType: Boolean): Boolean {
return isFunctionalTypeWithPredicate(session, errorOnNotFunctionalType) {
it == ConeFunctionalTypeKind.Function || it == ConeFunctionalTypeKind.KFunction
}
}
// SuspendFunction, [Custom]Function, KSuspendFunction, K[Custom]Function
private fun ConeKotlinType.isNotSimpleFunctionalType(session: FirSession): Boolean {
return !isSimpleFunctionalType(session, errorOnNotFunctionalType = false)
}
// ---------------------------------------------- functional type conversions ----------------------------------------------
/*
* SuspendFunction/[Custom]Function -> Function
* KSuspendFunction/K[Custom]Function -> KFunction
*/
fun ConeKotlinType.customFunctionalTypeToSimpleFunctionalType(session: FirSession): ConeClassLikeType {
val kind = functionalTypeKind(session)
require(kind != null && kind != ConeFunctionalTypeKind.Function && kind != ConeFunctionalTypeKind.KFunction)
val newKind = if (kind.isReflectType) {
ConeFunctionalTypeKind.KFunction
} else {
ConeFunctionalTypeKind.Function
}
return createFunctionalTypeWithNewKind(newKind)
}
/*
* KFunction -> Function
* KSuspendFunction -> SuspendFunction
* K[Custom]Function -> [Custom]Function
*/
fun ConeKotlinType.reflectFunctionalTypeToNonReflectFunctionalType(session: FirSession): ConeClassLikeType {
val kind = functionalTypeKind(session)
require(kind != null && kind.isReflectType)
return createFunctionalTypeWithNewKind(kind.nonReflectKind())
}
private fun ConeKotlinType.createFunctionalTypeWithNewKind(kind: ConeFunctionalTypeKind): ConeClassLikeType {
val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(typeArguments.size - 1))
return functionalTypeId.toLookupTag().constructClassType(typeArguments, isNullable = false, attributes = attributes)
}
// ---------------------------------------------- functional type subtyping ----------------------------------------------
// expectedFunctionalType is kotlin.FunctionN or kotlin.reflect.KFunctionN
fun ConeKotlinType.findSubtypeOfSimpleFunctionalType(session: FirSession, expectedFunctionalType: ConeClassLikeType): ConeKotlinType? {
require(expectedFunctionalType.isSimpleFunctionalType(session, errorOnNotFunctionalType = true))
return findSubtypeOfSimpleFunctionalTypeImpl(session, expectedFunctionalType)
}
private fun ConeKotlinType.findSubtypeOfSimpleFunctionalTypeImpl(
session: FirSession,
expectedFunctionalType: ConeClassLikeType
): ConeKotlinType? {
return when (this) {
is ConeClassLikeType -> {
// Expect the argument type is a simple functional type.
when {
isNotSimpleFunctionalType(session) -> null
isSubtypeOfFunctionalType(session, expectedFunctionalType) -> this
else -> null
}
}
is ConeIntersectionType -> {
runUnless(intersectedTypes.any { it.isNotSimpleFunctionalType(session) }) {
intersectedTypes.find { it.findSubtypeOfSimpleFunctionalTypeImpl(session, expectedFunctionalType) != null }
}
}
is ConeTypeParameterType -> {
val bounds = lookupTag.typeParameterSymbol.resolvedBounds.map { it.coneType }
runUnless(bounds.any { it.isNotSimpleFunctionalType(session) }) {
bounds.find { it.findSubtypeOfSimpleFunctionalTypeImpl(session, expectedFunctionalType) != null }
}
}
else -> null
}
}
private fun ConeKotlinType.isSubtypeOfFunctionalType(session: FirSession, expectedFunctionalType: ConeClassLikeType): Boolean {
return AbstractTypeChecker.isSubtypeOf(session.typeContext, this, expectedFunctionalType.replaceArgumentsWithStarProjections())
}
// ---------------------------------------------- functional type scope utils ----------------------------------------------
fun ConeClassLikeType.findBaseInvokeSymbol(session: FirSession, scopeSession: ScopeSession): FirNamedFunctionSymbol? {
require(this.isSomeFunctionalType(session))
val functionN = (lookupTag.toSymbol(session)?.fir as? FirClass) ?: return null
var baseInvokeSymbol: FirNamedFunctionSymbol? = null
functionN.unsubstitutedScope(
session,
scopeSession,
withForcedTypeCalculator = false
).processFunctionsByName(OperatorNameConventions.INVOKE) { functionSymbol ->
baseInvokeSymbol = functionSymbol
return@processFunctionsByName
}
return baseInvokeSymbol
}
fun ConeKotlinType.findContributedInvokeSymbol(
session: FirSession,
scopeSession: ScopeSession,
expectedFunctionalType: ConeClassLikeType,
shouldCalculateReturnTypesOfFakeOverrides: Boolean
): FirFunctionSymbol<*>? {
val baseInvokeSymbol = expectedFunctionalType.findBaseInvokeSymbol(session, scopeSession) ?: return null
val fakeOverrideTypeCalculator = if (shouldCalculateReturnTypesOfFakeOverrides) {
FakeOverrideTypeCalculator.Forced
} else {
FakeOverrideTypeCalculator.DoNothing
}
val scope = scope(session, scopeSession, fakeOverrideTypeCalculator, requiredPhase = FirResolvePhase.STATUS) ?: return null
var declaredInvoke: FirNamedFunctionSymbol? = null
scope.processFunctionsByName(OperatorNameConventions.INVOKE) { functionSymbol ->
if (functionSymbol.fir.valueParameters.size == baseInvokeSymbol.fir.valueParameters.size) {
declaredInvoke = functionSymbol
return@processFunctionsByName
}
}
var overriddenInvoke: FirFunctionSymbol<*>? = null
if (declaredInvoke != null) {
// Make sure the user-contributed or type-substituted invoke we just found above is an override of base invoke.
scope.processOverriddenFunctions(declaredInvoke!!) { functionSymbol ->
if (functionSymbol == baseInvokeSymbol || functionSymbol.originalForSubstitutionOverride == baseInvokeSymbol) {
overriddenInvoke = functionSymbol
ProcessorAction.STOP
} else {
ProcessorAction.NEXT
}
}
}
return if (overriddenInvoke != null) declaredInvoke else null
}
// ---------------------------------------------- functional type type argument extraction ----------------------------------------------
fun ConeKotlinType.receiverType(session: FirSession): ConeKotlinType? {
if (!isSomeFunctionalType(session) || !isExtensionFunctionType(session)) return null
return fullyExpandedType(session).let { expanded ->
expanded.typeArguments[expanded.contextReceiversNumberForFunctionType].typeOrDefault(session.builtinTypes.nothingType.type)
}
}
fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType {
require(this is ConeClassLikeType)
// TODO: add requirement
return fullyExpandedType(session).typeArguments.last().typeOrDefault(session.builtinTypes.nullableAnyType.type)
}
fun ConeKotlinType.valueParameterTypesIncludingReceiver(session: FirSession): List<ConeKotlinType> {
require(this is ConeClassLikeType)
// TODO: add requirement
return fullyExpandedType(session).typeArguments.dropLast(1).map { it.typeOrDefault(session.builtinTypes.nothingType.type) }
}
private fun ConeTypeProjection.typeOrDefault(default: ConeKotlinType): ConeKotlinType = when (this) {
is ConeKotlinTypeProjection -> type
is ConeStarProjection -> default
}
@@ -5,27 +5,12 @@
package org.jetbrains.kotlin.fir.types
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.originalForSubstitutionOverride
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.scope
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.util.OperatorNameConventions
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
@@ -50,203 +35,10 @@ fun ConeKotlinType.isKMutableProperty(session: FirSession): Boolean {
classId.shortClassName.identifier.startsWith("KMutableProperty")
}
fun ConeKotlinType.functionClassKind(session: FirSession): FunctionClassKind? {
return classId(session)?.toFunctionClassKind()
}
private fun ClassId.toFunctionClassKind(): FunctionClassKind? {
return FunctionClassKind.byClassNamePrefix(packageFqName, relativeClassName.asString())
}
// Function, SuspendFunction, KFunction, KSuspendFunction
fun ConeKotlinType.isBuiltinFunctionalType(session: FirSession): Boolean {
return functionClassKind(session) != null
}
// Function, SuspendFunction, KFunction, KSuspendFunction
fun ConeClassLikeLookupTag.isBuiltinFunctionalType(): Boolean {
return classId.toFunctionClassKind() != null
}
inline fun ConeKotlinType.isFunctionalType(session: FirSession, predicate: (FunctionClassKind) -> Boolean): Boolean {
val kind = functionClassKind(session) ?: return false
return predicate(kind)
}
// Function
fun ConeKotlinType.isFunctionalType(session: FirSession): Boolean {
return isFunctionalType(session) { it == FunctionClassKind.Function }
}
// Function, SuspendFunction
fun ConeKotlinType.isFunctionalOrSuspendFunctionalType(session: FirSession): Boolean {
return isFunctionalType(session) { it == FunctionClassKind.Function || it == FunctionClassKind.SuspendFunction }
}
// SuspendFunction, KSuspendFunction
fun ConeKotlinType.isSuspendOrKSuspendFunctionType(session: FirSession): Boolean {
return isFunctionalType(session) { it.isSuspendType }
}
fun ConeKotlinType.isSuspendFunctionType(session: FirSession): Boolean {
return isFunctionalType(session) { it == FunctionClassKind.SuspendFunction }
}
// KFunction, KSuspendFunction
fun ConeKotlinType.isKFunctionType(session: FirSession): Boolean {
return isFunctionalType(session) { it.isReflectType }
}
fun ConeKotlinType.kFunctionTypeToFunctionType(session: FirSession): ConeClassLikeType {
require(this.isKFunctionType(session))
val kind =
if (isSuspendOrKSuspendFunctionType(session)) FunctionClassKind.SuspendFunction
else FunctionClassKind.Function
val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(typeArguments.size - 1))
return ConeClassLikeTypeImpl(functionalTypeId.toLookupTag(), typeArguments, isNullable = false)
}
fun ConeKotlinType.suspendFunctionTypeToFunctionType(session: FirSession): ConeClassLikeType {
require(this.isSuspendOrKSuspendFunctionType(session))
val kind =
if (isKFunctionType(session)) FunctionClassKind.KFunction
else FunctionClassKind.Function
val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(typeArguments.size - 1))
return ConeClassLikeTypeImpl(functionalTypeId.toLookupTag(), typeArguments, isNullable = false, attributes = attributes)
}
fun ConeKotlinType.suspendFunctionTypeToFunctionTypeWithContinuation(session: FirSession, continuationClassId: ClassId): ConeClassLikeType {
require(this.isSuspendOrKSuspendFunctionType(session))
val kind =
if (isKFunctionType(session)) FunctionClassKind.KFunction
else FunctionClassKind.Function
val fullyExpandedType = type.fullyExpandedType(session)
val typeArguments = fullyExpandedType.typeArguments
val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(typeArguments.size))
val lastTypeArgument = typeArguments.last()
return ConeClassLikeTypeImpl(
functionalTypeId.toLookupTag(),
typeArguments = (typeArguments.dropLast(1) + continuationClassId.toLookupTag().constructClassType(
arrayOf(lastTypeArgument),
isNullable = false
) + lastTypeArgument).toTypedArray(),
isNullable = fullyExpandedType.isNullable,
attributes = fullyExpandedType.attributes
)
}
fun ConeKotlinType.isSubtypeOfFunctionalType(session: FirSession, expectedFunctionalType: ConeClassLikeType): Boolean {
require(expectedFunctionalType.isBuiltinFunctionalType(session))
return AbstractTypeChecker.isSubtypeOf(session.typeContext, this, expectedFunctionalType.replaceArgumentsWithStarProjections())
}
fun ConeKotlinType.findSubtypeOfNonSuspendFunctionalType(session: FirSession, expectedFunctionalType: ConeClassLikeType): ConeKotlinType? {
require(expectedFunctionalType.isBuiltinFunctionalType(session) && !expectedFunctionalType.isSuspendOrKSuspendFunctionType(session))
return when (this) {
is ConeClassLikeType -> {
// Expect the argument type is not a suspend functional type.
if (isSuspendOrKSuspendFunctionType(session) || !isSubtypeOfFunctionalType(session, expectedFunctionalType))
null
else
this
}
is ConeIntersectionType -> {
if (intersectedTypes.any { it.isSuspendOrKSuspendFunctionType(session) })
null
else
intersectedTypes.find { it.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType) != null }
}
is ConeTypeParameterType -> {
val bounds = lookupTag.typeParameterSymbol.resolvedBounds.map { it.coneType }
if (bounds.any { it.isSuspendOrKSuspendFunctionType(session) })
null
else
bounds.find { it.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType) != null }
}
else -> null
}
}
fun ConeClassLikeType.findBaseInvokeSymbol(session: FirSession, scopeSession: ScopeSession): FirNamedFunctionSymbol? {
require(this.isBuiltinFunctionalType(session))
val functionN = (lookupTag.toSymbol(session)?.fir as? FirClass) ?: return null
var baseInvokeSymbol: FirNamedFunctionSymbol? = null
functionN.unsubstitutedScope(
session,
scopeSession,
withForcedTypeCalculator = false
).processFunctionsByName(OperatorNameConventions.INVOKE) { functionSymbol ->
baseInvokeSymbol = functionSymbol
return@processFunctionsByName
}
return baseInvokeSymbol
}
fun ConeKotlinType.findContributedInvokeSymbol(
session: FirSession,
scopeSession: ScopeSession,
expectedFunctionalType: ConeClassLikeType,
shouldCalculateReturnTypesOfFakeOverrides: Boolean
): FirFunctionSymbol<*>? {
val baseInvokeSymbol = expectedFunctionalType.findBaseInvokeSymbol(session, scopeSession) ?: return null
val fakeOverrideTypeCalculator = if (shouldCalculateReturnTypesOfFakeOverrides) {
FakeOverrideTypeCalculator.Forced
} else {
FakeOverrideTypeCalculator.DoNothing
}
val scope = scope(session, scopeSession, fakeOverrideTypeCalculator, requiredPhase = null) ?: return null
var declaredInvoke: FirNamedFunctionSymbol? = null
scope.processFunctionsByName(OperatorNameConventions.INVOKE) { functionSymbol ->
if (functionSymbol.fir.valueParameters.size == baseInvokeSymbol.fir.valueParameters.size) {
declaredInvoke = functionSymbol
return@processFunctionsByName
}
}
var overriddenInvoke: FirFunctionSymbol<*>? = null
if (declaredInvoke != null) {
// Make sure the user-contributed or type-substituted invoke we just found above is an override of base invoke.
scope.processOverriddenFunctions(declaredInvoke!!) { functionSymbol ->
if (functionSymbol == baseInvokeSymbol || functionSymbol.originalForSubstitutionOverride == baseInvokeSymbol) {
overriddenInvoke = functionSymbol
ProcessorAction.STOP
} else {
ProcessorAction.NEXT
}
}
}
return if (overriddenInvoke != null) declaredInvoke else null
}
fun ConeKotlinType.isKClassType(): Boolean {
return classId == StandardClassIds.KClass
}
private fun ConeTypeProjection.typeOrDefault(default: ConeKotlinType): ConeKotlinType =
when (this) {
is ConeKotlinTypeProjection -> type
is ConeStarProjection -> default
}
fun ConeKotlinType.receiverType(session: FirSession): ConeKotlinType? {
if (!isBuiltinFunctionalType(session) || !isExtensionFunctionType(session)) return null
return fullyExpandedType(session).let { expanded ->
expanded.typeArguments[expanded.contextReceiversNumberForFunctionType].typeOrDefault(session.builtinTypes.nothingType.type)
}
}
fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType {
require(this is ConeClassLikeType)
return fullyExpandedType(session).typeArguments.last().typeOrDefault(session.builtinTypes.nullableAnyType.type)
}
fun ConeKotlinType.valueParameterTypesIncludingReceiver(session: FirSession): List<ConeKotlinType> {
require(this is ConeClassLikeType)
return fullyExpandedType(session).typeArguments.dropLast(1).map { it.typeOrDefault(session.builtinTypes.nothingType.type) }
}
val FirAnonymousFunction.returnType: ConeKotlinType? get() = returnTypeRef.coneTypeSafe()
val FirAnonymousFunction.receiverType: ConeKotlinType? get() = receiverParameter?.typeRef?.coneTypeSafe()
@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer
import org.jetbrains.kotlin.fir.types.classId
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isBuiltinFunctionalType
import org.jetbrains.kotlin.fir.types.isSomeFunctionalType
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionMode
import org.jetbrains.kotlin.resolve.descriptorUtil.OVERLOAD_RESOLUTION_BY_LAMBDA_ANNOTATION_CLASS_ID
import org.jetbrains.kotlin.utils.addToStdlib.same
@@ -104,7 +104,7 @@ class FirOverloadByLambdaReturnTypeResolver(
.values.singleOrNull()?.toMap() ?: return null
if (!lambdas.values.same { it.parameters.size }) return null
if (!lambdas.values.all { it.expectedType?.isBuiltinFunctionalType(session) == true }) return null
if (!lambdas.values.all { it.expectedType?.isSomeFunctionalType(session) == true }) return null
val originalCalleeReference = call.calleeReference
@@ -56,6 +56,7 @@ import org.jetbrains.kotlin.types.ConstantValueKind
import org.jetbrains.kotlin.types.SmartcastStability
import org.jetbrains.kotlin.types.model.safeSubstitute
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.runIf
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
@@ -581,18 +582,15 @@ fun FirFunction.getAsForbiddenNamedArgumentsTarget(
result
}
// referenced function of a Kotlin function type
FirDeclarationOrigin.BuiltIns -> {
if (dispatchReceiverClassLookupTagOrNull()?.isBuiltinFunctionalType() == true) {
ForbiddenNamedArgumentsTarget.INVOKE_ON_FUNCTION_TYPE
} else {
null
}
FirDeclarationOrigin.BuiltIns -> runIf(dispatchReceiverClassLookupTagOrNull()?.isSomeFunctionalType(session) == true) {
ForbiddenNamedArgumentsTarget.INVOKE_ON_FUNCTION_TYPE
}
FirDeclarationOrigin.Synthetic -> null
FirDeclarationOrigin.DynamicScope -> null
FirDeclarationOrigin.RenamedForOverride -> null
FirDeclarationOrigin.WrappedIntegerOperator -> null
FirDeclarationOrigin.ScriptCustomization -> null
FirDeclarationOrigin.Synthetic,
FirDeclarationOrigin.DynamicScope,
FirDeclarationOrigin.RenamedForOverride,
FirDeclarationOrigin.WrappedIntegerOperator,
FirDeclarationOrigin.ScriptCustomization,
is FirDeclarationOrigin.Plugin -> null // TODO: figure out what to do with plugin generated functions
}
}
@@ -293,9 +293,9 @@ private fun argumentTypeWithSuspendConversion(
}
// We want to check the argument type against non-suspend functional type.
val expectedFunctionalType = expectedType.suspendFunctionTypeToFunctionType(session)
val expectedFunctionalType = expectedType.customFunctionalTypeToSimpleFunctionalType(session)
val argumentTypeWithInvoke = argumentType.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType)
val argumentTypeWithInvoke = argumentType.findSubtypeOfSimpleFunctionalType(session, expectedFunctionalType)
return argumentTypeWithInvoke?.findContributedInvokeSymbol(
session,
@@ -308,7 +308,7 @@ private fun argumentTypeWithSuspendConversion(
null,
invokeSymbol.fir.returnTypeRef.coneType,
isSuspend = true,
isKFunctionType = argumentType.isKFunctionType(session)
isKFunctionType = argumentType.isReflectFunctionalType(session)
)
}
}
@@ -498,7 +498,7 @@ private fun Candidate.getExpectedTypeWithSAMConversion(
candidateExpectedType: ConeKotlinType,
context: ResolutionContext
): ConeKotlinType? {
if (candidateExpectedType.isBuiltinFunctionalType(session)) return null
if (candidateExpectedType.isSomeFunctionalType(session)) return null
// TODO: resolvedCall.registerArgumentWithSamConversion(argument, SamConversionDescription(convertedTypeByOriginal, convertedTypeByCandidate!!))
@@ -521,7 +521,7 @@ fun FirExpression.isFunctional(
else -> {
// Either a functional type or a subtype of a class that has a contributed `invoke`.
val coneType = typeRef.coneTypeSafe<ConeKotlinType>() ?: return false
if (coneType.isBuiltinFunctionalType(session)) {
if (coneType.isSomeFunctionalType(session)) {
return true
}
val classLikeExpectedFunctionType = expectedFunctionType?.lowerBoundIfFlexible() as? ConeClassLikeType
@@ -297,7 +297,7 @@ object CheckDslScopeViolation : ResolutionStage() {
// ```
// `useX()` is a call to `invoke` with `useX` as the dispatch receiver. In the FIR tree, extension receiver is represented as an
// implicit `this` expression passed as the first argument.
if (candidate.dispatchReceiverValue?.type?.fullyExpandedType(context.session)?.isBuiltinFunctionalType(context.session) == true &&
if (candidate.dispatchReceiverValue?.type?.fullyExpandedType(context.session)?.isSomeFunctionalType(context.session) == true &&
(candidate.symbol as? FirNamedFunctionSymbol)?.name == OperatorNameConventions.INVOKE
) {
val firstArg = candidate.argumentMapping?.keys?.firstOrNull() as? FirThisReceiverExpression ?: return
@@ -36,7 +36,7 @@ fun extractLambdaInfoFromFunctionalType(
duringCompletion
)
}
if (!expectedType.isBuiltinFunctionalType(session)) return null
if (!expectedType.isSomeFunctionalType(session)) return null
val singleStatement = argument.body?.statements?.singleOrNull() as? FirReturnExpression
if (argument.returnType == null && singleStatement != null &&
@@ -109,7 +109,7 @@ private fun extractLambdaInfo(
val isFunctionSupertype =
expectedType != null && expectedType.lowerBoundIfFlexible()
.isBuiltinFunctionalType(session)//isNotNullOrNullableFunctionSupertype(expectedType)
.isSomeFunctionalType(session)//isNotNullOrNullableFunctionSupertype(expectedType)
val typeVariable = ConeTypeVariableForLambdaReturnType(argument, "_L")
@@ -177,7 +177,7 @@ internal fun extractInputOutputTypesFromCallableReferenceExpectedType(
if (expectedType == null) return null
return when {
expectedType.isBuiltinFunctionalType(session) ->
expectedType.isSomeFunctionalType(session) ->
InputOutputTypes(expectedType.valueParameterTypesIncludingReceiver(session), expectedType.returnType(session))
// ReflectionTypes.isBaseTypeForNumberedReferenceTypes(expectedType) ->
@@ -561,7 +561,7 @@ class FirCallCompletionResultsWriterTransformer(
// From the argument mapping, the expected type of this anonymous function would be:
when {
// a built-in functional type, no-brainer
expectedArgumentType.isBuiltinFunctionalType(session) -> expectedArgumentType
expectedArgumentType.isSomeFunctionalType(session) -> expectedArgumentType
// fun interface (a.k.a. SAM), then unwrap it and build a functional type from that interface function
expectedArgumentType is ConeClassLikeType -> {
val firRegularClass =
@@ -19,7 +19,7 @@ import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirWrappedArgumentExpression
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isFunctionalOrSuspendFunctionalType
import org.jetbrains.kotlin.fir.types.isNonReflectFunctionalType
tailrec fun FirExpression.unwrapAnonymousFunctionExpression(): FirAnonymousFunction? = when (this) {
is FirAnonymousFunctionExpression -> anonymousFunction
@@ -47,7 +47,7 @@ fun FirFunctionCall.replaceLambdaArgumentInvocationKinds(session: FirSession) {
val kind = byParameter[parameter] ?: EventOccurrencesRange.UNKNOWN.takeIf {
// Inline functional parameters have to be called in-place; that's the only permitted operation on them.
isInline && !parameter.isNoinline && !parameter.isCrossinline &&
parameter.returnTypeRef.coneType.isFunctionalOrSuspendFunctionalType(session)
parameter.returnTypeRef.coneType.isNonReflectFunctionalType(session)
} ?: continue
lambda.replaceInvocationKind(kind)
}
@@ -39,7 +39,6 @@ import org.jetbrains.kotlin.fir.resolve.transformers.FirCallCompletionResultsWri
import org.jetbrains.kotlin.fir.resolve.transformers.FirStatusResolver
import org.jetbrains.kotlin.fir.resolve.transformers.transformVarargTypeToArrayType
import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope
import org.jetbrains.kotlin.fir.types.constructStarProjectedType
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
@@ -859,7 +858,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve
lambda: FirAnonymousFunction
): List<FirValueParameter> {
if (expectedType == null) return lambda.valueParameters
if (!expectedType.isFunctionalOrSuspendFunctionalType(session)) return lambda.valueParameters
if (!expectedType.isNonReflectFunctionalType(session)) return lambda.valueParameters
val parameterTypes = expectedType.typeArguments
.mapTo(mutableListOf()) { it.type ?: session.builtinTypes.nullableAnyType.type }
.also { it.removeLastOrNull() }
@@ -742,7 +742,13 @@ class FirRenderer(
}
override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef) {
typeRenderer.renderAsPossibleFunctionType(resolvedTypeRef.type)
typeRenderer.renderAsPossibleFunctionType(
resolvedTypeRef.type,
l@{
val classId = it.classId ?: return@l null
FirFunctionalTypeKindService.Default.getKindByClassNamePrefix(classId.packageFqName, classId.shortClassName.asString())
}
)
}
override fun visitUserTypeRef(userTypeRef: FirUserTypeRef) {
@@ -0,0 +1,32 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.types
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.name.FqName
abstract class FirFunctionalTypeKindService : FirSessionComponent {
abstract fun getKindByClassNamePrefix(packageFqName: FqName, className: String): ConeFunctionalTypeKind?
/*
* Should be used only in places where session is unavaliable by default (e.g. in default cone type render)
*/
object Default : FirFunctionalTypeKindService() {
override fun getKindByClassNamePrefix(packageFqName: FqName, className: String): ConeFunctionalTypeKind? {
return when (FunctionClassKind.parseClassName(className, packageFqName)?.kind) {
FunctionClassKind.Function -> ConeFunctionalTypeKind.Function
FunctionClassKind.SuspendFunction -> ConeFunctionalTypeKind.SuspendFunction
FunctionClassKind.KFunction -> ConeFunctionalTypeKind.KFunction
FunctionClassKind.KSuspendFunction -> ConeFunctionalTypeKind.KSuspendFunction
null -> null
}
}
}
}
val FirSession.functionalTypeService: FirFunctionalTypeKindService by FirSession.sessionComponentAccessor()
@@ -337,7 +337,10 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() {
return
}
val projectionBuilder = StringBuilder()
ConeTypeRendererForDebugging(projectionBuilder).renderAsPossibleFunctionType(this) {
ConeTypeRendererForDebugging(projectionBuilder).renderAsPossibleFunctionType(
this,
{ it.functionalTypeKind(session) }
) {
localTypeProjectionRenderer(projectionBuilder)
}
builder.append(projectionBuilder.toString().removeCurrentFilePackage())
@@ -114,7 +114,7 @@ object FirParcelizePropertyChecker : FirPropertyChecker() {
type.anySuperTypeConstructor {
it is ConeKotlinType &&
(it.classId?.asFqNameString() in BuiltinParcelableTypes.PARCELABLE_SUPERTYPE_FQNAMES ||
it.isBuiltinFunctionalType(session))
it.isSomeFunctionalType(session))
}
}
}