From d1b797ed97043a706b780c178abe09753563d929 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 18 Jan 2023 17:29:41 +0200 Subject: [PATCH] [FIR] Generify resolution and inference of arguments of functional types --- .../components/KtFirExpressionTypeProvider.kt | 3 +- .../FirJsInheritanceClassChecker.kt | 3 +- .../kotlin/fir/types/ConeInferenceContext.kt | 35 +++++---------- .../types/FirFunctionalTypeKindServiceImpl.kt | 30 +++++++++++++ .../kotlin/fir/types/FunctionalTypeUtils.kt | 35 ++++++++++----- .../kotlin/fir/resolve/ResolveUtils.kt | 29 +++++------- .../kotlin/fir/resolve/SamResolution.kt | 8 ++-- .../kotlin/fir/resolve/calls/Arguments.kt | 19 ++++---- .../calls/CallableReferenceResolution.kt | 45 +++++++++++++------ .../kotlin/fir/resolve/calls/Candidate.kt | 5 +-- .../calls/ConeOverloadConflictResolver.kt | 3 +- .../fir/resolve/inference/InferenceUtils.kt | 4 +- .../resolve/inference/PostponedArguments.kt | 15 +++---- .../fir/resolve/inference/PostponedAtoms.kt | 3 +- ...rCallCompletionResultsWriterTransformer.kt | 11 ++--- .../FirDeclarationsResolveTransformer.kt | 2 +- .../fir/types/FirFunctionalTypeKindService.kt | 5 +++ .../PostponedArgumentInputTypesResolver.kt | 24 +++++----- .../adaptedExtensionFunctions.fir.ir.txt | 6 +-- .../cannotCastToFunction.fir.ir.txt | 4 +- .../builtins/functions/FunctionalTypeKind.kt | 6 ++- .../kotlin/types/model/TypeSystemContext.kt | 15 ++++--- .../kotlin/builtins/functionTypes.kt | 11 +++-- .../types/checker/ClassicTypeSystemContext.kt | 27 +++++++---- ...FirSamWithReceiverConventionTransformer.kt | 8 ++-- .../plugin/impl/compilationContext.kt | 8 ++-- 26 files changed, 219 insertions(+), 145 deletions(-) diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirExpressionTypeProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirExpressionTypeProvider.kt index fc278d814fd..98fe53d902e 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirExpressionTypeProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirExpressionTypeProvider.kt @@ -18,7 +18,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe import org.jetbrains.kotlin.analysis.utils.errors.unexpectedElementError import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.declarations.utils.isSuspend import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.references.FirNamedReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference @@ -114,7 +113,7 @@ internal class KtFirExpressionTypeProvider( declaration.toFirAnonymousFunction() else declaration.getOrBuildFirOfType(firResolveSession) - return firFunction.constructFunctionalType(firFunction.isSuspend).asKtType() + return firFunction.constructFunctionalType(firFunction.specialFunctionalTypeKind(firResolveSession.useSiteFirSession)).asKtType() } @OptIn(ExperimentalContracts::class) diff --git a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsInheritanceClassChecker.kt b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsInheritanceClassChecker.kt index 795233f8463..3966194a6e6 100644 --- a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsInheritanceClassChecker.kt +++ b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsInheritanceClassChecker.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.fir.scopes.collectAllFunctions import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionOverrideFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.types.ConeClassLikeType +import org.jetbrains.kotlin.fir.types.isSuspendFunctionType import org.jetbrains.kotlin.fir.types.typeContext object FirJsInheritanceClassChecker : FirClassChecker() { @@ -52,7 +53,7 @@ object FirJsInheritanceClassChecker : FirClassChecker() { } private fun ConeClassLikeType.isSuspendFunctionTypeOrSubtype(session: FirSession): Boolean { - return with(session.typeContext) { isSuspendFunctionTypeOrSubtype() } + return with(session.typeContext) { isTypeOrSubtypeOf { it.isSuspendFunctionType(session) } } } private fun FirClass.findFakeMethodOverridingExternalWithOptionalParams(context: CheckerContext): FirNamedFunctionSymbol? { 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 384745d6b67..2cbc7a0080f 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 @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.types +import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.fir.declarations.utils.modality import org.jetbrains.kotlin.fir.diagnostics.ConeIntermediateDiagnostic @@ -466,7 +467,7 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo return this.isSomeFunctionalType(session) } - private fun ConeKotlinType.isTypeOrSubtypeOf(predicate: (ConeKotlinType) -> Boolean): Boolean { + fun ConeKotlinType.isTypeOrSubtypeOf(predicate: (ConeKotlinType) -> Boolean): Boolean { return predicate(this) || DFS.dfsFromNode( this, { @@ -489,13 +490,6 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo ) } - override fun KotlinTypeMarker.isSuspendFunctionTypeOrSubtype(): Boolean { - require(this is ConeKotlinType) - return isTypeOrSubtypeOf { - (it.lowerBoundIfFlexible() as ConeKotlinType).isSuspendOrKSuspendFunctionType(session) - } - } - override fun KotlinTypeMarker.isExtensionFunctionType(): Boolean { require(this is ConeKotlinType) return (this.lowerBoundIfFlexible() as? ConeKotlinType)?.isExtensionFunctionType(session) == true @@ -536,24 +530,17 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo } } - override fun getFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker { - val classId = if (isSuspend) { - StandardClassIds.SuspendFunctionN(parametersNumber) - } else { - StandardClassIds.FunctionN(parametersNumber) - } - return session.symbolProvider.getClassLikeSymbolByClassId(classId)?.toLookupTag() - ?: error("Can't find Function type") + override fun KotlinTypeMarker.functionalTypeKind(): FunctionalTypeKind? { + require(this is ConeKotlinType) + return this.functionalTypeKind(session) } - override fun getKFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker { - val classId = if (isSuspend) { - StandardClassIds.KSuspendFunctionN(parametersNumber) - } else { - StandardClassIds.KFunctionN(parametersNumber) - } - return session.symbolProvider.getClassLikeSymbolByClassId(classId)?.toLookupTag() - ?: error("Can't find KFunction type") + override fun getNonReflectFunctionTypeConstructor(parametersNumber: Int, kind: FunctionalTypeKind): TypeConstructorMarker { + return kind.nonReflectKind().numberedClassId(parametersNumber).toLookupTag() + } + + override fun getReflectFunctionTypeConstructor(parametersNumber: Int, kind: FunctionalTypeKind): TypeConstructorMarker { + return kind.reflectKind().numberedClassId(parametersNumber).toLookupTag() } override fun createTypeWithAlternativeForIntersectionResult( diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/FirFunctionalTypeKindServiceImpl.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/FirFunctionalTypeKindServiceImpl.kt index 8a5713788b8..7732b4e20f0 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/FirFunctionalTypeKindServiceImpl.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/FirFunctionalTypeKindServiceImpl.kt @@ -8,11 +8,15 @@ package org.jetbrains.kotlin.fir.types import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKind import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKindExtractor import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.utils.isSuspend import org.jetbrains.kotlin.fir.extensions.FirFunctionalTypeKindExtension import org.jetbrains.kotlin.fir.extensions.extensionService import org.jetbrains.kotlin.fir.extensions.functionalTypeKindExtensions +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol class FirFunctionalTypeKindServiceImpl(session: FirSession) : FirFunctionalTypeKindService() { + private val nonReflectKindsFromExtensions = mutableListOf() + override val extractor: FunctionalTypeKindExtractor = run { val kinds = buildList { add(FunctionalTypeKind.Function) @@ -26,6 +30,7 @@ class FirFunctionalTypeKindServiceImpl(session: FirSession) : FirFunctionalTypeK require(reflectKind.nonReflectKind() == nonReflectKind) add(nonReflectKind) add(reflectKind) + nonReflectKindsFromExtensions += nonReflectKind } } @@ -38,6 +43,31 @@ class FirFunctionalTypeKindServiceImpl(session: FirSession) : FirFunctionalTypeK "There are clashing functional type kinds: $allNames" } } + FunctionalTypeKindExtractor(kinds) } + + override fun extractSingleSpecialKindForFunction(functionSymbol: FirNamedFunctionSymbol): FunctionalTypeKind? { + if (nonReflectKindsFromExtensions.isEmpty()) { + return FunctionalTypeKind.SuspendFunction.takeIf { functionSymbol.isSuspend } + } + return extractAllSpecialKindsForFunction(functionSymbol).singleOrNull() + } + + override fun extractAllSpecialKindsForFunction(functionSymbol: FirNamedFunctionSymbol): List { + return buildList { + if (functionSymbol.isSuspend) { + add(FunctionalTypeKind.SuspendFunction) + } + if (nonReflectKindsFromExtensions.isNotEmpty()) { + for (annotationClassId in functionSymbol.resolvedAnnotationClassIds) { + for (kind in nonReflectKindsFromExtensions) { + if (kind.annotationOnInvokeClassId == annotationClassId) { + add(kind) + } + } + } + } + } + } } 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 index 29faa911646..88118c9ae2e 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/FunctionalTypeUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/FunctionalTypeUtils.kt @@ -6,8 +6,10 @@ package org.jetbrains.kotlin.fir.types import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKind +import org.jetbrains.kotlin.builtins.functions.isRegularFunction import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.declarations.FirFunction import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.originalForSubstitutionOverride import org.jetbrains.kotlin.fir.resolve.ScopeSession @@ -82,14 +84,12 @@ fun ConeClassLikeLookupTag.isSomeFunctionalType(session: FirSession): Boolean { // Function, KFunction private fun ConeKotlinType.isSimpleFunctionalType(session: FirSession, errorOnNotFunctionalType: Boolean): Boolean { - return isFunctionalTypeWithPredicate(session, errorOnNotFunctionalType) { - it == FunctionalTypeKind.Function || it == FunctionalTypeKind.KFunction - } + return isFunctionalTypeWithPredicate(session, errorOnNotFunctionalType) { it.isRegularFunction } } // SuspendFunction, [Custom]Function, KSuspendFunction, K[Custom]Function -private fun ConeKotlinType.isNotSimpleFunctionalType(session: FirSession): Boolean { - return !isSimpleFunctionalType(session, errorOnNotFunctionalType = false) +fun ConeKotlinType.isNotSimpleFunctionalType(session: FirSession): Boolean { + return isFunctionalTypeWithPredicate(session, errorOnNotFunctionalType = false) { !it.isRegularFunction } } // ---------------------------------------------- functional type conversions ---------------------------------------------- @@ -106,7 +106,7 @@ fun ConeKotlinType.customFunctionalTypeToSimpleFunctionalType(session: FirSessio } else { FunctionalTypeKind.Function } - return createFunctionalTypeWithNewKind(newKind) + return createFunctionalTypeWithNewKind(session, newKind) } /* @@ -117,12 +117,17 @@ fun ConeKotlinType.customFunctionalTypeToSimpleFunctionalType(session: FirSessio fun ConeKotlinType.reflectFunctionalTypeToNonReflectFunctionalType(session: FirSession): ConeClassLikeType { val kind = functionalTypeKind(session) require(kind != null && kind.isReflectType) - return createFunctionalTypeWithNewKind(kind.nonReflectKind()) + return createFunctionalTypeWithNewKind(session, kind.nonReflectKind()) } -private fun ConeKotlinType.createFunctionalTypeWithNewKind(kind: FunctionalTypeKind): ConeClassLikeType { - val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(typeArguments.size - 1)) - return functionalTypeId.toLookupTag().constructClassType(typeArguments, isNullable = false, attributes = attributes) +private fun ConeKotlinType.createFunctionalTypeWithNewKind(session: FirSession, kind: FunctionalTypeKind): ConeClassLikeType { + val expandedType = fullyExpandedType(session) + val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(expandedType.typeArguments.size - 1)) + return functionalTypeId.toLookupTag().constructClassType( + expandedType.typeArguments, + isNullable = false, + attributes = expandedType.attributes + ) } // ---------------------------------------------- functional type subtyping ---------------------------------------------- @@ -139,8 +144,8 @@ private fun ConeKotlinType.findSubtypeOfSimpleFunctionalTypeImpl( ): ConeKotlinType? { return when (this) { is ConeClassLikeType -> { - // Expect the argument type is a simple functional type. when { + // Expect the argument type is a simple functional type. isNotSimpleFunctionalType(session) -> null isSubtypeOfFunctionalType(session, expectedFunctionalType) -> this else -> null @@ -247,3 +252,11 @@ private fun ConeTypeProjection.typeOrDefault(default: ConeKotlinType): ConeKotli is ConeKotlinTypeProjection -> type is ConeStarProjection -> default } + +// ----------------- TODO fir utils + +fun FirFunction.specialFunctionalTypeKind(session: FirSession): FunctionalTypeKind? { + return (symbol as? FirNamedFunctionSymbol)?.let { + session.functionalTypeService.extractSingleSpecialKindForFunction(it) + } +} 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 3502ea64a0b..7bb8be2e637 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 @@ -60,15 +60,9 @@ import org.jetbrains.kotlin.utils.addToStdlib.runIf import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract -fun List.toTypeProjections(): Array = - asReversed().flatMap { it.typeArgumentList.typeArguments.map { typeArgument -> typeArgument.toConeTypeProjection() } }.toTypedArray() - fun FirAnonymousFunction.shouldReturnUnit(returnStatements: Collection): Boolean = isLambda && returnStatements.any { it is FirUnitExpression } -fun FirAnonymousFunction.isExplicitlySuspend(session: FirSession): Boolean = - typeRef.coneTypeSafe()?.isSuspendOrKSuspendFunctionType(session) == true - fun FirAnonymousFunction.addReturnToLastStatementIfNeeded() { // If this lambda's resolved, expected return type is Unit, we don't need an explicit return statement. // During conversion (to backend IR), the last expression will be coerced to Unit if needed. @@ -96,7 +90,10 @@ fun FirAnonymousFunction.addReturnToLastStatementIfNeeded() { ) } -fun FirFunction.constructFunctionalType(isSuspend: Boolean = false): ConeLookupTagBasedType { +/** + * [kind] == null means that [FunctionalTypeKind.Function] will be used + */ +fun FirFunction.constructFunctionalType(kind: FunctionalTypeKind? = null): ConeLookupTagBasedType { val receiverTypeRef = when (this) { is FirSimpleFunction -> receiverParameter is FirAnonymousFunction -> receiverParameter @@ -114,25 +111,27 @@ fun FirFunction.constructFunctionalType(isSuspend: Boolean = false): ConeLookupT val rawReturnType = (this as FirCallableDeclaration).returnTypeRef.coneType return createFunctionalType( - parameters, receiverTypeRef?.coneType, rawReturnType, isSuspend = isSuspend, + kind ?: FunctionalTypeKind.Function, parameters, receiverTypeRef?.coneType, rawReturnType, contextReceivers = contextReceivers.map { it.typeRef.coneType } ) } -fun FirFunction.constructFunctionalTypeRef(isSuspend: Boolean = false): FirResolvedTypeRef { +/** + * [kind] == null means that [FunctionalTypeKind.Function] will be used + */ +fun FirFunction.constructFunctionalTypeRef(kind: FunctionalTypeKind? = null): FirResolvedTypeRef { return buildResolvedTypeRef { source = this@constructFunctionalTypeRef.source?.fakeElement(KtFakeSourceElementKind.ImplicitTypeRef) - type = constructFunctionalType(isSuspend) + type = constructFunctionalType(kind) } } fun createFunctionalType( + kind: FunctionalTypeKind, parameters: List, receiverType: ConeKotlinType?, rawReturnType: ConeKotlinType, - isSuspend: Boolean, contextReceivers: List = emptyList(), - isKFunctionType: Boolean = false ): ConeLookupTagBasedType { val receiverAndParameterTypes = buildList { @@ -142,12 +141,6 @@ fun createFunctionalType( add(rawReturnType) } - val kind = if (isSuspend) { - if (isKFunctionType) FunctionalTypeKind.KSuspendFunction else FunctionalTypeKind.SuspendFunction - } else { - if (isKFunctionType) FunctionalTypeKind.KFunction else FunctionalTypeKind.Function - } - val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(receiverAndParameterTypes.size - 1)) val attributes = when { contextReceivers.isNotEmpty() -> ConeAttributes.create( diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SamResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SamResolution.kt index 00b19d77252..af9332f3f2a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SamResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SamResolution.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.resolve +import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKind import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.EffectiveVisibility import org.jetbrains.kotlin.descriptors.Modality @@ -265,7 +266,7 @@ class FirSamResolver( it.getCustomFunctionalTypeForSamConversion(abstractMethod) } - SAMInfo(abstractMethod.symbol, typeFromExtension ?: abstractMethod.getFunctionTypeForAbstractMethod()) + SAMInfo(abstractMethod.symbol, typeFromExtension ?: abstractMethod.getFunctionTypeForAbstractMethod(session)) } } @@ -407,18 +408,19 @@ fun FirSimpleFunction.isPublicInObject(checkOnlyName: Boolean): Boolean { private val PUBLIC_METHOD_NAMES_IN_OBJECT = setOf("equals", "hashCode", "getClass", "wait", "notify", "notifyAll", "toString") -private fun FirSimpleFunction.getFunctionTypeForAbstractMethod(): ConeLookupTagBasedType { +private fun FirSimpleFunction.getFunctionTypeForAbstractMethod(session: FirSession): ConeLookupTagBasedType { val parameterTypes = valueParameters.map { it.returnTypeRef.coneTypeSafe() ?: ConeErrorType(ConeIntermediateDiagnostic("No type for parameter $it")) } val contextReceiversTypes = contextReceivers.map { it.typeRef.coneTypeSafe() ?: ConeErrorType(ConeIntermediateDiagnostic("No type for context receiver $it")) } + val kind = session.functionalTypeService.extractSingleSpecialKindForFunction(symbol) ?: FunctionalTypeKind.Function return createFunctionalType( + kind, parameterTypes, receiverType = receiverParameter?.typeRef?.coneType, rawReturnType = returnTypeRef.coneType, - isSuspend = this.isSuspend, contextReceivers = contextReceiversTypes ) } 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 9834b58571b..02cd1902df2 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 @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.resolve.calls +import org.jetbrains.kotlin.builtins.functions.isRegularFunction import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirValueParameter @@ -265,12 +266,12 @@ fun Candidate.resolvePlainArgumentType( // If the argument is of functional type and the expected type is a suspend function type, we need to do "suspend conversion." if (expectedType != null) { - argumentTypeWithSuspendConversion( + argumentTypeWithCustomConversion( session, context.bodyResolveComponents.scopeSession, expectedType, argumentTypeForApplicabilityCheck )?.let { argumentTypeForApplicabilityCheck = it substitutor.substituteOrSelf(argumentTypeForApplicabilityCheck) - usesSuspendConversion = true + usesFunctionalConversion = true } } @@ -279,18 +280,15 @@ fun Candidate.resolvePlainArgumentType( ) } -private fun argumentTypeWithSuspendConversion( +private fun argumentTypeWithCustomConversion( session: FirSession, scopeSession: ScopeSession, expectedType: ConeKotlinType, argumentType: ConeKotlinType ): ConeKotlinType? { - // TODO: should refer to LanguageVersionSettings.SuspendConversion - - // Expect the expected type to be a suspend functional type. - if (!expectedType.isSuspendOrKSuspendFunctionType(session)) { - return null - } + // Expect the expected type to be a not regular functional type (e.g. suspend or custom) + val expectedTypeKind = expectedType.functionalTypeKind(session) ?: return null + if (expectedTypeKind.isRegularFunction) return null // We want to check the argument type against non-suspend functional type. val expectedFunctionalType = expectedType.customFunctionalTypeToSimpleFunctionalType(session) @@ -304,11 +302,10 @@ private fun argumentTypeWithSuspendConversion( shouldCalculateReturnTypesOfFakeOverrides = false )?.let { invokeSymbol -> createFunctionalType( + expectedTypeKind, invokeSymbol.fir.valueParameters.map { it.returnTypeRef.coneType }, null, invokeSymbol.fir.returnTypeRef.coneType, - isSuspend = true, - isKFunctionType = argumentType.isReflectFunctionalType(session) ) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallableReferenceResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallableReferenceResolution.kt index d4d7697699a..bb868f2ff04 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallableReferenceResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallableReferenceResolution.kt @@ -7,10 +7,11 @@ package org.jetbrains.kotlin.fir.resolve.calls import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.KtSourceElement +import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKind +import org.jetbrains.kotlin.builtins.functions.isRegularFunction import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.declarations.utils.isSuspend import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirNamedArgumentExpression @@ -26,7 +27,6 @@ import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.FirVisitor import org.jetbrains.kotlin.name.StandardClassIds -import org.jetbrains.kotlin.resolve.calls.components.SuspendConversionStrategy import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.runTransaction @@ -130,14 +130,16 @@ private fun buildReflectionType( fir.valueParameters.mapTo(parameters) { it.returnTypeRef.coneType } } - val isSuspend = (fir as? FirSimpleFunction)?.isSuspend == true || - callableReferenceAdaptation?.suspendConversionStrategy == SuspendConversionStrategy.SUSPEND_CONVERSION + + val baseFunctionalTypeKind = callableReferenceAdaptation?.suspendConversionStrategy?.kind + ?: fir.specialFunctionalTypeKind(context.session) + ?: FunctionalTypeKind.Function + return createFunctionalType( + baseFunctionalTypeKind.reflectKind(), parameters, receiverType = receiverType.takeIf { fir.receiverParameter != null }, rawReturnType = returnType, - isKFunctionType = true, - isSuspend = isSuspend, contextReceivers = fir.contextReceivers.map { it.typeRef.coneType } ) to callableReferenceAdaptation } @@ -151,14 +153,14 @@ internal class CallableReferenceAdaptation( val coercionStrategy: CoercionStrategy, val defaults: Int, val mappedArguments: CallableReferenceMappedArguments, - val suspendConversionStrategy: SuspendConversionStrategy + val suspendConversionStrategy: CallableReferenceConversionStrategy ) private fun CallableReferenceAdaptation?.needCompatibilityResolveForCallableReference(): Boolean { // KT-13934: check containing declaration for companion object if (this == null) return false return defaults != 0 || - suspendConversionStrategy != SuspendConversionStrategy.NO_CONVERSION || + suspendConversionStrategy != CallableReferenceConversionStrategy.NoConversion || coercionStrategy != CoercionStrategy.NO_COERCION || mappedArguments.values.any { it is ResolvedCallArgument.VarargArgument } } @@ -253,10 +255,14 @@ private fun BodyResolveComponents.getCallableReferenceAdaptation( else mappedArguments - val suspendConversionStrategy = if ((function as? FirSimpleFunction)?.isSuspend != true && expectedType.isSuspendOrKSuspendFunctionType(session)) - SuspendConversionStrategy.SUSPEND_CONVERSION - else - SuspendConversionStrategy.NO_CONVERSION + val expectedTypeFunctionalKind = expectedType.functionalTypeKind(session)?.takeUnless { it.isRegularFunction } + val functionKind = function.specialFunctionalTypeKind(session) + + val conversionStrategy = if (expectedTypeFunctionalKind != null && functionKind == null) { + CallableReferenceConversionStrategy.CustomConversion(expectedTypeFunctionalKind) + } else { + CallableReferenceConversionStrategy.NoConversion + } @Suppress("UNCHECKED_CAST") return CallableReferenceAdaptation( @@ -264,10 +270,23 @@ private fun BodyResolveComponents.getCallableReferenceAdaptation( coercionStrategy, defaults, adaptedArguments, - suspendConversionStrategy + conversionStrategy ) } + + +sealed class CallableReferenceConversionStrategy { + abstract val kind: FunctionalTypeKind? + + object NoConversion : CallableReferenceConversionStrategy() { + override val kind: FunctionalTypeKind? + get() = null + } + + class CustomConversion(override val kind: FunctionalTypeKind) : CallableReferenceConversionStrategy() +} + private fun varargParameterTypeByExpectedParameter( expectedParameterType: ConeKotlinType, substitutedParameter: FirValueParameter, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt index e1935433007..10946376cef 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt @@ -16,7 +16,6 @@ import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeTypeVariable -import org.jetbrains.kotlin.resolve.calls.components.SuspendConversionStrategy import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintSystemError @@ -63,13 +62,13 @@ class Candidate( internal var callableReferenceAdaptation: CallableReferenceAdaptation? = null set(value) { field = value - usesSuspendConversion = value?.suspendConversionStrategy == SuspendConversionStrategy.SUSPEND_CONVERSION + usesFunctionalConversion = value?.suspendConversionStrategy is CallableReferenceConversionStrategy.CustomConversion if (value != null) { numDefaults = value.defaults } } - var usesSuspendConversion: Boolean = false + var usesFunctionalConversion: Boolean = false var argumentMapping: LinkedHashMap? = null var numDefaults: Int = 0 diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeOverloadConflictResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeOverloadConflictResolver.kt index 044fb24ec5f..6b72992a0ea 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeOverloadConflictResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeOverloadConflictResolver.kt @@ -14,7 +14,6 @@ import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeParameterBasedTypeVariable import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap -import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl @@ -95,7 +94,7 @@ class ConeOverloadConflictResolver( } if (discriminateSuspendConversions) { - val filtered = candidates.filterTo(mutableSetOf()) { !it.usesSuspendConversion } + val filtered = candidates.filterTo(mutableSetOf()) { !it.usesFunctionalConversion } when (filtered.size) { 1 -> return filtered 0, candidates.size -> { 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 a5d2388a206..1dfcb602a80 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.isSomeFunctionalType(session)) return null + val expectedFunctionalKind = expectedType.functionalTypeKind(session) ?: return null val singleStatement = argument.body?.statements?.singleOrNull() as? FirReturnExpression if (argument.returnType == null && singleStatement != null && @@ -100,7 +100,7 @@ fun extractLambdaInfoFromFunctionalType( return ResolvedLambdaAtom( argument, expectedType, - expectedType.isSuspendOrKSuspendFunctionType(session), + expectedFunctionalKind, receiverType, contextReceivers, parameters, 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 3b1d75629a9..f35293ae195 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 @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.resolve.inference +import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKind import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction import org.jetbrains.kotlin.fir.expressions.FirAnonymousFunctionExpression @@ -21,6 +22,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind import org.jetbrains.kotlin.types.model.typeConstructor +import org.jetbrains.kotlin.utils.addToStdlib.runIf fun Candidate.preprocessLambdaArgument( csBuilder: ConstraintSystemBuilder, @@ -62,10 +64,10 @@ fun Candidate.preprocessLambdaArgument( if (expectedType != null) { val parameters = resolvedArgument.parameters val lambdaType = createFunctionalType( + resolvedArgument.expectedFunctionalTypeKind ?: FunctionalTypeKind.Function, if (resolvedArgument.coerceFirstParameterToExtensionReceiver) parameters.drop(1) else parameters, resolvedArgument.receiver, resolvedArgument.returnType, - isSuspend = resolvedArgument.isSuspend, contextReceivers = resolvedArgument.contextReceivers, ) @@ -105,18 +107,15 @@ private fun extractLambdaInfo( session: FirSession, candidate: Candidate? ): ResolvedLambdaAtom { - val isSuspend = expectedType?.isSuspendOrKSuspendFunctionType(session) ?: false - - val isFunctionSupertype = - expectedType != null && expectedType.lowerBoundIfFlexible() - .isSomeFunctionalType(session)//isNotNullOrNullableFunctionSupertype(expectedType) + val expectedFunctionalKind = expectedType?.lowerBoundIfFlexible()?.functionalTypeKind(session) + val isFunctionSupertype = expectedFunctionalKind != null val typeVariable = ConeTypeVariableForLambdaReturnType(argument, "_L") val receiverType = argument.receiverType val returnType = argument.returnType - ?: (expectedType?.typeArguments?.singleOrNull() as? ConeKotlinTypeProjection)?.type?.takeIf { isFunctionSupertype } + ?: runIf(isFunctionSupertype) { (expectedType?.typeArguments?.singleOrNull() as? ConeKotlinTypeProjection)?.type } ?: typeVariable.defaultType val nothingType = session.builtinTypes.nothingType.type @@ -134,7 +133,7 @@ private fun extractLambdaInfo( return ResolvedLambdaAtom( argument, expectedType, - isSuspend, + expectedFunctionalKind, receiverType, contextReceivers, parameters, 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 3c74f848f23..0a54a689679 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 @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.resolve.inference +import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKind import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction @@ -39,7 +40,7 @@ sealed class PostponedResolvedAtom : PostponedResolvedAtomMarker { class ResolvedLambdaAtom( override val atom: FirAnonymousFunction, expectedType: ConeKotlinType?, - val isSuspend: Boolean, + val expectedFunctionalTypeKind: FunctionalTypeKind?, val receiver: ConeKotlinType?, val contextReceivers: List, val parameters: List, 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 3d3bad539d4..45b594a3692 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 @@ -570,12 +570,12 @@ class FirCallCompletionResultsWriterTransformer( firRegularClass?.let answer@{ val functionType = samResolver.getFunctionTypeForPossibleSamType(firRegularClass.defaultType()) ?: return@answer null + val kind = functionType.functionalTypeKind(session) ?: FunctionalTypeKind.Function createFunctionalType( + kind, functionType.typeArguments.dropLast(1).map { it as ConeKotlinType }, null, - functionType.typeArguments.last() as ConeKotlinType, - functionType.classId?.relativeClassName?.asString() - ?.startsWith(FunctionalTypeKind.SuspendFunction.classNamePrefix) == true + functionType.typeArguments.last() as ConeKotlinType ) } } @@ -617,8 +617,9 @@ class FirCallCompletionResultsWriterTransformer( } if (needUpdateLambdaType) { - val isSuspend = expectedType?.isSuspendOrKSuspendFunctionType(session) ?: result.isExplicitlySuspend(session) - result.replaceTypeRef(result.constructFunctionalTypeRef(isSuspend)) + val kind = expectedType?.functionalTypeKind(session) + ?: result.typeRef.coneTypeSafe()?.functionalTypeKind(session) + result.replaceTypeRef(result.constructFunctionalTypeRef(kind)) session.lookupTracker?.recordTypeResolveAsLookup(result.typeRef, result.source, context.file.source) } // Have to delay this until the type is written to avoid adding a return if the type is Unit. 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 c9647dacb69..febda3d0848 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 @@ -805,7 +805,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve session.lookupTracker?.recordTypeResolveAsLookup(lambda.returnTypeRef, lambda.source, context.file.source) } - lambda.replaceTypeRef(lambda.constructFunctionalTypeRef(resolvedLambdaAtom?.isSuspend == true)) + lambda.replaceTypeRef(lambda.constructFunctionalTypeRef(resolvedLambdaAtom?.expectedFunctionalTypeKind)) session.lookupTracker?.recordTypeResolveAsLookup(lambda.typeRef, lambda.source, context.file.source) lambda.addReturnToLastStatementIfNeeded() return lambda 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 index f30278bdab1..01ad9794f3c 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirFunctionalTypeKindService.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirFunctionalTypeKindService.kt @@ -9,6 +9,8 @@ import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKind import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKindExtractor import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSessionComponent +import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.name.FqName abstract class FirFunctionalTypeKindService : FirSessionComponent { @@ -21,6 +23,9 @@ abstract class FirFunctionalTypeKindService : FirSessionComponent { fun hasKindWithSpecificPackage(packageFqName: FqName): Boolean { return extractor.hasKindWithSpecificPackage(packageFqName) } + + abstract fun extractSingleSpecialKindForFunction(functionSymbol: FirNamedFunctionSymbol): FunctionalTypeKind? + abstract fun extractAllSpecialKindsForFunction(functionSymbol: FirNamedFunctionSymbol): List } val FirSession.functionalTypeService: FirFunctionalTypeKindService by FirSession.sessionComponentAccessor() diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt index 692a75015b3..264c39612cd 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt @@ -5,6 +5,8 @@ package org.jetbrains.kotlin.resolve.calls.inference.components +import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKind +import org.jetbrains.kotlin.builtins.functions.isRegularFunction import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.resolve.calls.inference.model.* @@ -28,7 +30,7 @@ class PostponedArgumentInputTypesResolver( val parametersFromConstraints: Set>?, val annotations: List?, val isExtensionFunction: Boolean, - val isSuspend: Boolean, + val functionalTypeKind: FunctionalTypeKind, val isNullable: Boolean ) @@ -94,14 +96,16 @@ class PostponedArgumentInputTypesResolver( parameterTypesFromDeclaration, ) - var isSuspend = false + var functionalTypeKind: FunctionalTypeKind? = null var isNullable = false - if (!functionalTypesFromConstraints.isNullOrEmpty()) { + if (functionalTypesFromConstraints.isNotEmpty()) { isNullable = true for (funType in functionalTypesFromConstraints) { - if (!isSuspend && funType.type.isSuspendFunctionTypeOrSubtype()) isSuspend = true + if (functionalTypeKind == null) { + funType.type.functionalTypeKind()?.takeUnless { it.isRegularFunction }?.let { functionalTypeKind = it } + } if (isNullable && !funType.type.isMarkedNullable()) isNullable = false - if (isSuspend && !isNullable) break + if ((functionalTypeKind != null) && !isNullable) break } } @@ -122,7 +126,7 @@ class PostponedArgumentInputTypesResolver( parameterTypesFromConstraints, annotations = annotations, isExtensionFunction, - isSuspend = isSuspend, + functionalTypeKind ?: FunctionalTypeKind.Function, isNullable = isNullable ) } @@ -254,7 +258,7 @@ class PostponedArgumentInputTypesResolver( private fun Context.computeResultingFunctionalConstructor( argument: PostponedAtomWithRevisableExpectedType, parametersNumber: Int, - isSuspend: Boolean, + functionalTypeKind: FunctionalTypeKind, resultTypeResolver: ResultTypeResolver ): TypeConstructorMarker { val expectedType = argument.expectedType @@ -264,7 +268,7 @@ class PostponedArgumentInputTypesResolver( return when (argument) { is LambdaWithTypeVariableAsExpectedTypeMarker -> - getFunctionTypeConstructor(parametersNumber, isSuspend) + getNonReflectFunctionTypeConstructor(parametersNumber, functionalTypeKind) is PostponedCallableReferenceMarker -> { val computedResultType = resultTypeResolver.findResultType( this@computeResultingFunctionalConstructor, @@ -276,7 +280,7 @@ class PostponedArgumentInputTypesResolver( if (computedResultType.isBuiltinFunctionalTypeOrSubtype() && computedResultType.argumentsCount() > 1) { computedResultType.typeConstructor() } else { - getKFunctionTypeConstructor(parametersNumber, isSuspend) + getReflectFunctionTypeConstructor(parametersNumber, functionalTypeKind) } } else -> throw IllegalStateException("Unsupported postponed argument type of $argument") @@ -378,7 +382,7 @@ class PostponedArgumentInputTypesResolver( val functionalConstructor = computeResultingFunctionalConstructor( argument, variablesForParameterTypes.size, - parameterTypesInfo.isSuspend, + parameterTypesInfo.functionalTypeKind, resultTypeResolver ) diff --git a/compiler/testData/ir/irText/expressions/callableReferences/adaptedExtensionFunctions.fir.ir.txt b/compiler/testData/ir/irText/expressions/callableReferences/adaptedExtensionFunctions.fir.ir.txt index 318a0636e69..e51d09e756d 100644 --- a/compiler/testData/ir/irText/expressions/callableReferences/adaptedExtensionFunctions.fir.ir.txt +++ b/compiler/testData/ir/irText/expressions/callableReferences/adaptedExtensionFunctions.fir.ir.txt @@ -44,7 +44,7 @@ FILE fqName: fileName:/adaptedExtensionFunctions.kt FUN name:testExtensionVararg visibility:public modality:FINAL <> () returnType:kotlin.Unit BLOCK_BODY CALL 'public final fun use (f: @[ExtensionFunctionType] kotlin.Function2<.C, kotlin.Int, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - f: FUN_EXPR type=kotlin.Function2<.C, kotlin.Int, kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE + f: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function2<.C, kotlin.Int, kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE FUN ADAPTER_FOR_CALLABLE_REFERENCE name:extensionVararg visibility:local modality:FINAL <> (p0:.C, p1:kotlin.Int) returnType:kotlin.Unit VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:.C VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p1 index:1 type:kotlin.Int @@ -55,7 +55,7 @@ FILE fqName: fileName:/adaptedExtensionFunctions.kt FUN name:testExtensionDefault visibility:public modality:FINAL <> () returnType:kotlin.Unit BLOCK_BODY CALL 'public final fun use (f: @[ExtensionFunctionType] kotlin.Function2<.C, kotlin.Int, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - f: FUN_EXPR type=kotlin.Function2<.C, kotlin.Int, kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE + f: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function2<.C, kotlin.Int, kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE FUN ADAPTER_FOR_CALLABLE_REFERENCE name:extensionDefault visibility:local modality:FINAL <> (p0:.C, p1:kotlin.Int) returnType:kotlin.Unit VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:.C VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p1 index:1 type:kotlin.Int @@ -66,7 +66,7 @@ FILE fqName: fileName:/adaptedExtensionFunctions.kt FUN name:testExtensionBoth visibility:public modality:FINAL <> () returnType:kotlin.Unit BLOCK_BODY CALL 'public final fun use (f: @[ExtensionFunctionType] kotlin.Function2<.C, kotlin.Int, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - f: FUN_EXPR type=kotlin.Function2<.C, kotlin.Int, kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE + f: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function2<.C, kotlin.Int, kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE FUN ADAPTER_FOR_CALLABLE_REFERENCE name:extensionBoth visibility:local modality:FINAL <> (p0:.C, p1:kotlin.Int) returnType:kotlin.Unit VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:.C VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p1 index:1 type:kotlin.Int diff --git a/compiler/testData/ir/irText/firProblems/cannotCastToFunction.fir.ir.txt b/compiler/testData/ir/irText/firProblems/cannotCastToFunction.fir.ir.txt index abc91bb3a44..6ad32facdc2 100644 --- a/compiler/testData/ir/irText/firProblems/cannotCastToFunction.fir.ir.txt +++ b/compiler/testData/ir/irText/firProblems/cannotCastToFunction.fir.ir.txt @@ -47,7 +47,7 @@ FILE fqName: fileName:/cannotCastToFunction.kt if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ arg0: GET_VAR 'dumpStrategy: kotlin.String declared in .dump' type=kotlin.String origin=null arg1: CONST String type=kotlin.String value="KotlinLike" - then: FUN_EXPR type=kotlin.Function1<.IrElement, kotlin.String> origin=ADAPTED_FUNCTION_REFERENCE + then: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1<.IrElement, kotlin.String> origin=ADAPTED_FUNCTION_REFERENCE FUN ADAPTER_FOR_CALLABLE_REFERENCE name:dumpKotlinLike visibility:local modality:FINAL <> (p0:.IrElement) returnType:kotlin.String VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:.IrElement BLOCK_BODY @@ -56,7 +56,7 @@ FILE fqName: fileName:/cannotCastToFunction.kt $receiver: GET_VAR 'p0: .IrElement declared in .dump.dumpKotlinLike' type=.IrElement origin=null BRANCH if: CONST Boolean type=kotlin.Boolean value=true - then: FUN_EXPR type=kotlin.Function1<.IrElement, kotlin.String> origin=ADAPTED_FUNCTION_REFERENCE + then: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1<.IrElement, kotlin.String> origin=ADAPTED_FUNCTION_REFERENCE FUN ADAPTER_FOR_CALLABLE_REFERENCE name:dump visibility:local modality:FINAL <> (p0:.IrElement) returnType:kotlin.String VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:.IrElement BLOCK_BODY diff --git a/core/compiler.common/src/org/jetbrains/kotlin/builtins/functions/FunctionalTypeKind.kt b/core/compiler.common/src/org/jetbrains/kotlin/builtins/functions/FunctionalTypeKind.kt index babe5a4e217..1ddd85adece 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/builtins/functions/FunctionalTypeKind.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/builtins/functions/FunctionalTypeKind.kt @@ -85,6 +85,8 @@ abstract class FunctionalTypeKind internal constructor( fun numberedClassName(arity: Int): Name = Name.identifier("$classNamePrefix$arity") + fun numberedClassId(arity: Int): ClassId = ClassId(packageFqName, numberedClassName(arity)) + override fun toString(): String { return "$packageFqName.${classNamePrefix}N" } @@ -141,5 +143,7 @@ val FunctionalTypeKind.isBuiltin: Boolean } val FunctionalTypeKind.isSuspendType: Boolean - get() = this == FunctionalTypeKind.SuspendFunction || this == FunctionalTypeKind.KSuspendFunction + get() = this.nonReflectKind() == FunctionalTypeKind.SuspendFunction +val FunctionalTypeKind.isRegularFunction: Boolean + get() = this.nonReflectKind() == FunctionalTypeKind.Function diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt index 41d99388a33..81b2ca3f595 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.types.model +import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKind import org.jetbrains.kotlin.resolve.checkers.EmptyIntersectionTypeChecker import org.jetbrains.kotlin.resolve.checkers.EmptyIntersectionTypeInfo import org.jetbrains.kotlin.types.* @@ -247,9 +248,11 @@ interface TypeSystemInferenceExtensionContext : TypeSystemContext, TypeSystemBui fun KotlinTypeMarker.isSignedOrUnsignedNumberType(): Boolean + // ------------- functional type utils ------------- + fun KotlinTypeMarker.isFunctionOrKFunctionWithAnySuspendability(): Boolean - fun KotlinTypeMarker.isSuspendFunctionTypeOrSubtype(): Boolean + fun KotlinTypeMarker.functionalTypeKind(): FunctionalTypeKind? fun KotlinTypeMarker.isExtensionFunctionType(): Boolean @@ -257,12 +260,14 @@ interface TypeSystemInferenceExtensionContext : TypeSystemContext, TypeSystemBui fun KotlinTypeMarker.getFunctionalTypeFromSupertypes(): KotlinTypeMarker + fun getNonReflectFunctionTypeConstructor(parametersNumber: Int, kind: FunctionalTypeKind): TypeConstructorMarker + + fun getReflectFunctionTypeConstructor(parametersNumber: Int, kind: FunctionalTypeKind): TypeConstructorMarker + + // ------------------------------------------------- + fun StubTypeMarker.getOriginalTypeVariable(): TypeVariableTypeConstructorMarker - fun getFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker - - fun getKFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker - private fun KotlinTypeMarker.extractTypeOf(to: MutableSet, getIfApplicable: (TypeConstructorMarker) -> T?) { for (i in 0 until argumentsCount()) { val argument = getArgument(i) diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt index 8ab099e7ce6..d03415ef169 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/functionTypes.kt @@ -59,17 +59,20 @@ val KotlinType.isBuiltinFunctionalTypeOrSubtype: Boolean fun KotlinType.isFunctionTypeOrSubtype(predicate: (KotlinType) -> Boolean): Boolean = isTypeOrSubtypeOf { it.isFunctionType && predicate(it) } +val KotlinType.functionalTypeKind: FunctionalTypeKind? + get() = constructor.declarationDescriptor?.getFunctionalClassKind() + val KotlinType.isFunctionType: Boolean - get() = constructor.declarationDescriptor?.getFunctionalClassKind() == FunctionalTypeKind.Function + get() = functionalTypeKind == FunctionalTypeKind.Function val KotlinType.isKFunctionType: Boolean - get() = constructor.declarationDescriptor?.getFunctionalClassKind() == FunctionalTypeKind.KFunction + get() = functionalTypeKind == FunctionalTypeKind.KFunction val KotlinType.isSuspendFunctionType: Boolean - get() = constructor.declarationDescriptor?.getFunctionalClassKind() == FunctionalTypeKind.SuspendFunction + get() = functionalTypeKind == FunctionalTypeKind.SuspendFunction val KotlinType.isKSuspendFunctionType: Boolean - get() = constructor.declarationDescriptor?.getFunctionalClassKind() == FunctionalTypeKind.KSuspendFunction + get() = functionalTypeKind == FunctionalTypeKind.KSuspendFunction val KotlinType.isFunctionOrSuspendFunctionType: Boolean get() = isFunctionType || isSuspendFunctionType diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt index b1cbea8c5a7..86ef6c008f0 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.types.checker import org.jetbrains.kotlin.builtins.* import org.jetbrains.kotlin.builtins.StandardNames.FqNames +import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKind import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations @@ -849,11 +850,6 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy return this.isFunctionOrKFunctionTypeWithAnySuspendability } - override fun KotlinTypeMarker.isSuspendFunctionTypeOrSubtype(): Boolean { - require(this is KotlinType, this::errorMessage) - return this.isSuspendFunctionTypeOrSubtype - } - override fun KotlinTypeMarker.isExtensionFunctionType(): Boolean { require(this is KotlinType, this::errorMessage) return this.isBuiltinExtensionFunctionalType @@ -869,12 +865,25 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy return this.extractFunctionalTypeFromSupertypes() } - override fun getFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker { - return getFunctionDescriptor(builtIns, parametersNumber, isSuspend).typeConstructor + override fun KotlinTypeMarker.functionalTypeKind(): FunctionalTypeKind? { + require(this is KotlinType) + return this.functionalTypeKind } - override fun getKFunctionTypeConstructor(parametersNumber: Int, isSuspend: Boolean): TypeConstructorMarker { - return getKFunctionDescriptor(builtIns, parametersNumber, isSuspend).typeConstructor + override fun getNonReflectFunctionTypeConstructor(parametersNumber: Int, kind: FunctionalTypeKind): TypeConstructorMarker { + return getFunctionDescriptor( + builtIns, + parametersNumber, + isSuspendFunction = kind.nonReflectKind() == FunctionalTypeKind.SuspendFunction + ).typeConstructor + } + + override fun getReflectFunctionTypeConstructor(parametersNumber: Int, kind: FunctionalTypeKind): TypeConstructorMarker { + return getKFunctionDescriptor( + builtIns, + parametersNumber, + isSuspendFunction = kind.reflectKind() == FunctionalTypeKind.KSuspendFunction + ).typeConstructor } override fun createSubstitutorForSuperTypes(baseType: KotlinTypeMarker): TypeSubstitutorMarker? { diff --git a/plugins/sam-with-receiver/sam-with-receiver.k2/src/org/jetbrains/kotlin/samWithReceiver/k2/FirSamWithReceiverConventionTransformer.kt b/plugins/sam-with-receiver/sam-with-receiver.k2/src/org/jetbrains/kotlin/samWithReceiver/k2/FirSamWithReceiverConventionTransformer.kt index 1424ab79122..34df3743e9b 100644 --- a/plugins/sam-with-receiver/sam-with-receiver.k2/src/org/jetbrains/kotlin/samWithReceiver/k2/FirSamWithReceiverConventionTransformer.kt +++ b/plugins/sam-with-receiver/sam-with-receiver.k2/src/org/jetbrains/kotlin/samWithReceiver/k2/FirSamWithReceiverConventionTransformer.kt @@ -5,15 +5,16 @@ package org.jetbrains.kotlin.samWithReceiver.k2 +import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKind import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.containingClassLookupTag import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction -import org.jetbrains.kotlin.fir.declarations.utils.isSuspend import org.jetbrains.kotlin.fir.resolve.FirSamConversionTransformerExtension import org.jetbrains.kotlin.fir.resolve.createFunctionalType import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType import org.jetbrains.kotlin.fir.types.coneType +import org.jetbrains.kotlin.fir.types.functionalTypeService import org.jetbrains.kotlin.utils.addToStdlib.runIf class FirSamWithReceiverConventionTransformer( @@ -25,11 +26,12 @@ class FirSamWithReceiverConventionTransformer( return runIf(containingClassSymbol.resolvedAnnotationClassIds.any { it.asSingleFqName().asString() in annotations }) { val parameterTypes = function.valueParameters.map { it.returnTypeRef.coneType } if (parameterTypes.isEmpty()) return null + val kind = session.functionalTypeService.extractSingleSpecialKindForFunction(function.symbol) ?: FunctionalTypeKind.Function createFunctionalType( + kind, parameters = parameterTypes.subList(1, parameterTypes.size), receiverType = parameterTypes[0], - rawReturnType = function.returnTypeRef.coneType, - isSuspend = function.isSuspend + rawReturnType = function.returnTypeRef.coneType ) } } diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/compilationContext.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/compilationContext.kt index 062363256e1..8a1e1e632a3 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/compilationContext.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/compilationContext.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.scripting.compiler.plugin.impl import com.intellij.openapi.Disposable +import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKind import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments @@ -41,7 +42,6 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.builder.scriptConfigurators import org.jetbrains.kotlin.fir.containingClassLookupTag import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction -import org.jetbrains.kotlin.fir.declarations.utils.isSuspend import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar import org.jetbrains.kotlin.fir.extensions.extensionService import org.jetbrains.kotlin.fir.resolve.FirSamConversionTransformerExtension @@ -49,6 +49,7 @@ import org.jetbrains.kotlin.fir.resolve.createFunctionalType import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType import org.jetbrains.kotlin.fir.types.coneType +import org.jetbrains.kotlin.fir.types.functionalTypeService import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.psi.KtFile @@ -158,11 +159,12 @@ internal class FirScriptingSamWithReceiverExtensionRegistrar() : FirExtensionReg return runIf(containingClassSymbol.resolvedAnnotationClassIds.any { it.asSingleFqName().asString() in knownAnnotations }) { val parameterTypes = function.valueParameters.map { it.returnTypeRef.coneType } if (parameterTypes.isEmpty()) return null + val kind = session.functionalTypeService.extractSingleSpecialKindForFunction(function.symbol) ?: FunctionalTypeKind.Function createFunctionalType( + kind, parameters = parameterTypes.subList(1, parameterTypes.size), receiverType = parameterTypes[0], - rawReturnType = function.returnTypeRef.coneType, - isSuspend = function.isSuspend + rawReturnType = function.returnTypeRef.coneType ) } }