[FIR] Generify resolution and inference of arguments of functional types

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