From c86495dcaeb77222f85dbad183ec856a0b9b0a02 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 18 Jan 2023 14:12:11 +0200 Subject: [PATCH] [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 --- .../fir/components/KtFirTypeInfoProvider.kt | 9 +- .../api/fir/types/KtFirFunctionalType.kt | 5 +- .../FirSynchronizedAnnotationChecker.kt | 6 +- .../analysis/cfa/FirCallsEffectAnalyzer.kt | 2 +- .../fir/analysis/checkers/FirConstChecks.kt | 2 +- .../FirInlineDeclarationChecker.kt | 12 +- .../expression/FirSuspendCallChecker.kt | 4 +- .../checkers/extended/UnusedChecker.kt | 4 +- .../checkers/type/FirTypeAnnotationChecker.kt | 8 +- .../kotlin/fir/renderer/ConeTypeRenderer.kt | 28 +- .../renderer/ConeTypeRendererForDebugging.kt | 11 +- .../fir/types/ConeFunctionalTypeKind.kt | 128 +++++++++ .../kotlin/fir/types/ConeTypeUtils.kt | 14 +- .../fir/session/ComponentsContainers.kt | 4 + .../impl/FirBuiltinSymbolProvider.kt | 88 +++---- .../fir/serialization/FirElementSerializer.kt | 3 +- .../fir/serialization/serializationUtil.kt | 26 +- .../backend/jvm/FirJvmSerializerExtension.kt | 4 +- .../fir/backend/jvm/FirJvmTypeMapper.kt | 6 +- .../fir/backend/Fir2IrDeclarationStorage.kt | 2 +- .../backend/generators/AdapterGenerator.kt | 12 +- .../generators/CallAndReferenceGenerator.kt | 2 +- .../impl/FirCachingCompositeSymbolProvider.kt | 4 +- .../kotlin/fir/types/ConeInferenceContext.kt | 10 +- .../kotlin/fir/types/FunctionalTypeUtils.kt | 248 ++++++++++++++++++ .../kotlin/fir/types/InferenceUtils.kt | 208 --------------- .../FirOverloadByLambdaReturnTypeResolver.kt | 4 +- .../kotlin/fir/resolve/ResolveUtils.kt | 20 +- .../kotlin/fir/resolve/calls/Arguments.kt | 10 +- .../fir/resolve/calls/ResolutionStages.kt | 2 +- .../fir/resolve/inference/InferenceUtils.kt | 2 +- .../resolve/inference/PostponedArguments.kt | 2 +- .../fir/resolve/inference/PostponedAtoms.kt | 2 +- ...rCallCompletionResultsWriterTransformer.kt | 2 +- .../transformers/InvocationKindTransformer.kt | 4 +- .../FirDeclarationsResolveTransformer.kt | 3 +- .../kotlin/fir/renderer/FirRenderer.kt | 8 +- .../fir/types/FirFunctionalTypeKindService.kt | 32 +++ .../compiler/visualizer/FirVisualizer.kt | 5 +- .../FirParcelizePropertyChecker.kt | 2 +- 40 files changed, 583 insertions(+), 365 deletions(-) create mode 100644 compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeFunctionalTypeKind.kt create mode 100644 compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/FunctionalTypeUtils.kt create mode 100644 compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirFunctionalTypeKindService.kt diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirTypeInfoProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirTypeInfoProvider.kt index 752a763e6f1..0666253577c 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirTypeInfoProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirTypeInfoProvider.kt @@ -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 diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirFunctionalType.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirFunctionalType.kt index 090a219b9cc..d968adcf639 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirFunctionalType.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirFunctionalType.kt @@ -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 { diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirSynchronizedAnnotationChecker.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirSynchronizedAnnotationChecker.kt index aaac7f1c736..b303bb257d5 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirSynchronizedAnnotationChecker.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirSynchronizedAnnotationChecker.kt @@ -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) } } -} \ No newline at end of file +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt index 8048330a890..dd18d44e15b 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt @@ -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? { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConstChecks.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConstChecks.kt index b3d79f83cc7..9cb62bfc661 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConstChecks.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConstChecks.kt @@ -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) } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineDeclarationChecker.kt index 901f144a118..a04f2287c95 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineDeclarationChecker.kt @@ -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 diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuspendCallChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuspendCallChecker.kt index 87d53bb7178..7d1fe5754e8 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuspendCallChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuspendCallChecker.kt @@ -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 { 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 diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/UnusedChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/UnusedChecker.kt index e00b32afe6e..6a8cbd8856f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/UnusedChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/UnusedChecker.kt @@ -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 diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirTypeAnnotationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirTypeAnnotationChecker.kt index cb0c71d1e33..484e63bb169 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirTypeAnnotationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirTypeAnnotationChecker.kt @@ -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 { diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/renderer/ConeTypeRenderer.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/renderer/ConeTypeRenderer.kt index 5dfe2e44892..0fcdbdddb88 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/renderer/ConeTypeRenderer.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/renderer/ConeTypeRenderer.kt @@ -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() { } } } -} \ No newline at end of file +} diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/renderer/ConeTypeRendererForDebugging.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/renderer/ConeTypeRendererForDebugging.kt index 8f54eb16f33..e26c78d7e5a 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/renderer/ConeTypeRendererForDebugging.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/renderer/ConeTypeRendererForDebugging.kt @@ -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("|") } -} \ No newline at end of file +} diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeFunctionalTypeKind.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeFunctionalTypeKind.kt new file mode 100644 index 00000000000..215d81b98d0 --- /dev/null +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeFunctionalTypeKind.kt @@ -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 : kotlin.Function { + * @some.Anno + * operator fun invoke(p1: P1, p2: P2, ..., pN: PN): R + * } + * + * interface KCustomFunctionN : kotlin.reflect.KFunction, some.CustomFunctionN { + * @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`, + * 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 + } +} diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypeUtils.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypeUtils.kt index 14947b72149..98adb196582 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypeUtils.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypeUtils.kt @@ -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) diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt index ae2eb13af8c..cb2d064a269 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt @@ -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) diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirBuiltinSymbolProvider.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirBuiltinSymbolProvider.kt index f5f41c0e782..fef02e2071f 100644 --- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirBuiltinSymbolProvider.kt +++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirBuiltinSymbolProvider.kt @@ -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 { 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)) } diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt index 6b904f87fc3..0359397010d 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt @@ -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 ) diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/serializationUtil.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/serializationUtil.kt index 8f88d5e0e86..90137df9304 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/serializationUtil.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/serializationUtil.kt @@ -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 + ) +} diff --git a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmSerializerExtension.kt b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmSerializerExtension.kt index 41941b19c98..6281e25ab94 100644 --- a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmSerializerExtension.kt +++ b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmSerializerExtension.kt @@ -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, diff --git a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmTypeMapper.kt b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmTypeMapper.kt index 59410d8b56c..25f6d5ea440 100644 --- a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmTypeMapper.kt +++ b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmTypeMapper.kt @@ -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 { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt index 83229d3ce02..a6204a63bfe 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt @@ -538,7 +538,7 @@ class Fir2IrDeclarationStorage( ?: if (isLambda) SpecialNames.ANONYMOUS else Name.special("") 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 -> diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AdapterGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AdapterGenerator.kt index 9c9b9daefb6..f5c025a2720 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AdapterGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AdapterGenerator.kt @@ -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( diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt index a92845e9ca9..f77c4b5b19a 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt @@ -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 diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirCachingCompositeSymbolProvider.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirCachingCompositeSymbolProvider.kt index 8fe90b62001..00431221835 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirCachingCompositeSymbolProvider.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirCachingCompositeSymbolProvider.kt @@ -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) diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt index 075ef3c86bd..384745d6b67 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt @@ -66,7 +66,7 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo ): SimpleTypeMarker { val attributesList = attributes?.filterIsInstanceTo, MutableList>>(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 diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/FunctionalTypeUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/FunctionalTypeUtils.kt new file mode 100644 index 00000000000..6ba7e7ffec6 --- /dev/null +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/FunctionalTypeUtils.kt @@ -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 { + 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 +} diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/InferenceUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/InferenceUtils.kt index 6a0ccbab12a..03885b39587 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/InferenceUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/InferenceUtils.kt @@ -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 { - 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() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirOverloadByLambdaReturnTypeResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirOverloadByLambdaReturnTypeResolver.kt index 36ac6531b3a..350e12b02df 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirOverloadByLambdaReturnTypeResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirOverloadByLambdaReturnTypeResolver.kt @@ -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 diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index b23209e7dea..7dee73470fa 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -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 } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt index f2a568de542..9834b58571b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt @@ -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() ?: return false - if (coneType.isBuiltinFunctionalType(session)) { + if (coneType.isSomeFunctionalType(session)) { return true } val classLikeExpectedFunctionType = expectedFunctionType?.lowerBoundIfFlexible() as? ConeClassLikeType diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt index 512fe07025c..2ad9bed3d90 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt @@ -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 diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt index 4a4d534b1ae..a5d2388a206 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt @@ -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 && diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArguments.kt index 6d8e207a88d..3b1d75629a9 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArguments.kt @@ -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") diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedAtoms.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedAtoms.kt index 41ef9cfa577..3c74f848f23 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedAtoms.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedAtoms.kt @@ -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) -> diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt index 1663af9c3fd..b728f14be6a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt @@ -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 = diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/InvocationKindTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/InvocationKindTransformer.kt index bd2642ef258..ddbd950837a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/InvocationKindTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/InvocationKindTransformer.kt @@ -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) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt index 0e58bb542b5..c9647dacb69 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt @@ -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 { 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() } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/renderer/FirRenderer.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/renderer/FirRenderer.kt index 338024b6976..ab41265ca25 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/renderer/FirRenderer.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/renderer/FirRenderer.kt @@ -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) { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirFunctionalTypeKindService.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirFunctionalTypeKindService.kt new file mode 100644 index 00000000000..f06dcb6fcb1 --- /dev/null +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirFunctionalTypeKindService.kt @@ -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() diff --git a/compiler/visualizer/render-fir/src/org/jetbrains/kotlin/compiler/visualizer/FirVisualizer.kt b/compiler/visualizer/render-fir/src/org/jetbrains/kotlin/compiler/visualizer/FirVisualizer.kt index 6fa33bb1ac4..25969d0a17b 100644 --- a/compiler/visualizer/render-fir/src/org/jetbrains/kotlin/compiler/visualizer/FirVisualizer.kt +++ b/compiler/visualizer/render-fir/src/org/jetbrains/kotlin/compiler/visualizer/FirVisualizer.kt @@ -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()) diff --git a/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/FirParcelizePropertyChecker.kt b/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/FirParcelizePropertyChecker.kt index d33bd7e8cf9..4f1b11bb976 100644 --- a/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/FirParcelizePropertyChecker.kt +++ b/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/FirParcelizePropertyChecker.kt @@ -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)) } } }