diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AdapterGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AdapterGenerator.kt index 8a545df2e03..79e66bca164 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AdapterGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AdapterGenerator.kt @@ -400,8 +400,8 @@ internal class AdapterGenerator( return this } val expectedType = parameter?.returnTypeRef?.coneType ?: return this - // Expect the expected type to be a suspend functional type, and the argument type is not a suspend functional type. - if (!expectedType.isSuspendFunctionType(session) || argument.typeRef.coneType.isSuspendFunctionType(session)) { + // Expect the expected type to be a suspend functional type. + if (!expectedType.isSuspendFunctionType(session)) { return this } val expectedFunctionalType = expectedType.suspendFunctionTypeToFunctionType(session) @@ -424,22 +424,17 @@ internal class AdapterGenerator( private fun findInvokeSymbol(expectedFunctionalType: ConeClassLikeType, argument: FirExpression): IrSimpleFunctionSymbol? { val argumentType = argument.typeRef.coneType - // To avoid any remaining exotic types, e.g., intersection type, like it(FunctionN..., SuspendFunctionN...) - if (argumentType !is ConeClassLikeType) { - return null - } + val argumentTypeWithInvoke = argumentType.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType) ?: return null - if (argumentType.isSubtypeOfFunctionalType(session, expectedFunctionalType)) { - return if (argumentType.isBuiltinFunctionalType(session)) { - argumentType.findBaseInvokeSymbol(session, scopeSession) - } else { - argumentType.findContributedInvokeSymbol(session, scopeSession, expectedFunctionalType, shouldCalculateReturnTypesOfFakeOverrides = true) - }?.let { - declarationStorage.getIrFunctionSymbol(it) as? IrSimpleFunctionSymbol - } + return if (argumentTypeWithInvoke.isBuiltinFunctionalType(session)) { + (argumentTypeWithInvoke as? ConeClassLikeType)?.findBaseInvokeSymbol(session, scopeSession) + } else { + argumentTypeWithInvoke.findContributedInvokeSymbol( + session, scopeSession, expectedFunctionalType, shouldCalculateReturnTypesOfFakeOverrides = true + ) + }?.let { + declarationStorage.getIrFunctionSymbol(it) as? IrSimpleFunctionSymbol } - - return null } private fun createAdapterFunctionForArgument( 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 a217d289950..25593e0f709 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 @@ -247,36 +247,30 @@ private fun argumentTypeWithSuspendConversion( ): ConeKotlinType? { // TODO: should refer to LanguageVersionSettings.SuspendConversion - // To avoid any remaining exotic types, e.g., intersection type, like it(FunctionN..., SuspendFunctionN...) - if (argumentType !is ConeClassLikeType) { - return null - } - - // Expect the expected type to be a suspend functional type, and the argument type is not a suspend functional type. - if (!expectedType.isSuspendFunctionType(session) || argumentType.isSuspendFunctionType(session)) { + // Expect the expected type to be a suspend functional type. + if (!expectedType.isSuspendFunctionType(session)) { return null } // We want to check the argument type against non-suspend functional type. val expectedFunctionalType = expectedType.suspendFunctionTypeToFunctionType(session) - if (argumentType.isSubtypeOfFunctionalType(session, expectedFunctionalType)) { - return argumentType.findContributedInvokeSymbol( - session, - scopeSession, - expectedFunctionalType, - shouldCalculateReturnTypesOfFakeOverrides = false - )?.let { invokeSymbol -> - createFunctionalType( - invokeSymbol.fir.valueParameters.map { it.returnTypeRef.coneType }, - null, - invokeSymbol.fir.returnTypeRef.coneType, - isSuspend = true, - isKFunctionType = argumentType.isKFunctionType(session) - ) - } - } - return null + val argumentTypeWithInvoke = argumentType.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType) + + return argumentTypeWithInvoke?.findContributedInvokeSymbol( + session, + scopeSession, + expectedFunctionalType, + shouldCalculateReturnTypesOfFakeOverrides = false + )?.let { invokeSymbol -> + createFunctionalType( + invokeSymbol.fir.valueParameters.map { it.returnTypeRef.coneType }, + null, + invokeSymbol.fir.returnTypeRef.coneType, + isSuspend = true, + isKFunctionType = argumentType.isKFunctionType(session) + ) + } } fun Candidate.prepareCapturedType(argumentType: ConeKotlinType, context: ResolutionContext): ConeKotlinType { 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 0ebce74b100..f884ff32dd0 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 @@ -97,6 +97,33 @@ fun ConeKotlinType.isSubtypeOfFunctionalType(session: FirSession, expectedFuncti return AbstractTypeChecker.isSubtypeOf(session.typeContext, this, expectedFunctionalType.replaceArgumentsWithStarProjections()) } +fun ConeKotlinType.findSubtypeOfNonSuspendFunctionalType(session: FirSession, expectedFunctionalType: ConeClassLikeType): ConeKotlinType? { + require(expectedFunctionalType.isBuiltinFunctionalType(session) && !expectedFunctionalType.isSuspendFunctionType(session)) + return when (this) { + is ConeClassLikeType -> { + // Expect the argument type is not a suspend functional type. + if (isSuspendFunctionType(session) || !isSubtypeOfFunctionalType(session, expectedFunctionalType)) + null + else + this + } + is ConeIntersectionType -> { + if (intersectedTypes.any { it.isSuspendFunctionType(session) }) + null + else + intersectedTypes.find { it.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType) != null } + } + is ConeTypeParameterType -> { + val bounds = lookupTag.typeParameterSymbol.fir.bounds.map { it.coneType } + if (bounds.any { it.isSuspendFunctionType(session) }) + null + else + bounds.find { it.findSubtypeOfNonSuspendFunctionalType(session, expectedFunctionalType) != null } + } + else -> null + } +} + fun ConeClassLikeType.findBaseInvokeSymbol(session: FirSession, scopeSession: ScopeSession): FirFunctionSymbol<*>? { require(this.isBuiltinFunctionalType(session)) val functionN = (lookupTag.toSymbol(session)?.fir as? FirClass<*>) ?: return null diff --git a/compiler/testData/codegen/box/coroutines/suspendConversion/intersectionTypeToSubtypeConversion.kt b/compiler/testData/codegen/box/coroutines/suspendConversion/intersectionTypeToSubtypeConversion.kt index e23cf2d35d3..0b626b0b9e5 100644 --- a/compiler/testData/codegen/box/coroutines/suspendConversion/intersectionTypeToSubtypeConversion.kt +++ b/compiler/testData/codegen/box/coroutines/suspendConversion/intersectionTypeToSubtypeConversion.kt @@ -3,7 +3,6 @@ // WITH_COROUTINES // IGNORE_BACKEND: JVM, NATIVE, JS, JS_IR // IGNORE_BACKEND: JS_IR_ES6 -// IGNORE_BACKEND_FIR: JVM_IR // IGNORE_LIGHT_ANALYSIS import helpers.*