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 b489089603e..7174e44d0ba 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 @@ -414,12 +414,10 @@ internal class AdapterGenerator( if (!needSamConversion(argument, parameter)) { return this } - val samFirType = parameter.returnTypeRef.coneTypeSafe()?.let { - var substituted = substitutor.substituteOrSelf(it) - substituted = starProjectionApproximator.substituteOrSelf(substituted) - if (substituted is ConeRawType) substituted.lowerBound else substituted - } - var samType = samFirType?.toIrType(ConversionTypeContext.WITH_INVARIANT) ?: createErrorType() + val parameterType = parameter.returnTypeRef.coneType + val substitutedParameterType = starProjectionApproximator.substituteOrSelf(substitutor.substituteOrSelf(parameterType)) + val samFirType = if (substitutedParameterType is ConeRawType) substitutedParameterType.lowerBound else substitutedParameterType + var samType = samFirType.toIrType(ConversionTypeContext.WITH_INVARIANT) if (shouldUnwrapVarargType) { samType = samType.getArrayElementType(irBuiltIns) } @@ -448,10 +446,14 @@ internal class AdapterGenerator( return false } // On the other hand, the actual type should be either a functional type or a subtype of a class that has a contributed `invoke`. - val expectedFunctionType = samResolver.getFunctionTypeForPossibleSamType(parameter.returnTypeRef.coneType) + val expectedFunctionType = getFunctionTypeForPossibleSamType(parameter.returnTypeRef.coneType) return argument.isFunctional(session, scopeSession, expectedFunctionType) } + internal fun getFunctionTypeForPossibleSamType(parameterType: ConeKotlinType): ConeKotlinType? { + return samResolver.getFunctionTypeForPossibleSamType(parameterType) + } + /** * For example, * fun consumer(f: suspend () -> Unit) = ... @@ -468,21 +470,22 @@ internal class AdapterGenerator( */ internal fun IrExpression.applySuspendConversionIfNeeded( argument: FirExpression, - parameter: FirValueParameter? + parameterType: ConeKotlinType, + samFunctionType: ConeKotlinType? ): IrExpression { // TODO: should refer to LanguageVersionSettings.SuspendConversion if (this is IrBlock && origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE) { return this } - val expectedType = parameter?.returnTypeRef?.coneType ?: return this // Expect the expected type to be a suspend functional type. - if (!expectedType.isSuspendFunctionType(session)) { + val potentialFunctionType = samFunctionType ?: parameterType + if (!potentialFunctionType.isSuspendFunctionType(session)) { return this } - val expectedFunctionalType = expectedType.suspendFunctionTypeToFunctionType(session) + val expectedFunctionalType = potentialFunctionType.suspendFunctionTypeToFunctionType(session) val invokeSymbol = findInvokeSymbol(expectedFunctionalType, argument) ?: return this - val suspendConvertedType = expectedType.toIrType() as IrSimpleType + val suspendConvertedType = potentialFunctionType.toIrType() as IrSimpleType return argument.convertWithOffsets { startOffset, endOffset -> val irAdapterFunction = createAdapterFunctionForArgument(startOffset, endOffset, suspendConvertedType, type, invokeSymbol) // TODO add a bound receiver property to IrFunctionExpressionImpl? diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt index 8617ae2d47f..b6159b4c988 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt @@ -657,7 +657,9 @@ class CallAndReferenceGenerator( with(adapterGenerator) { if (parameter?.returnTypeRef is FirResolvedTypeRef) { // Java type case (from annotations) - irArgument = irArgument.applySuspendConversionIfNeeded(argument, parameter) + val parameterType = parameter.returnTypeRef.coneType + val samFunctionType = getFunctionTypeForPossibleSamType(parameterType) + irArgument = irArgument.applySuspendConversionIfNeeded(argument, parameterType, samFunctionType) irArgument = irArgument.applySamConversionIfNeeded(argument, parameter, substitutor) } } diff --git a/compiler/testData/codegen/box/suspendConversion/chainedFunSuspendConversionForSimpleExpression.kt b/compiler/testData/codegen/box/suspendConversion/chainedFunSuspendConversionForSimpleExpression.kt index 985b5cf6cf2..e44ea4e6b3f 100644 --- a/compiler/testData/codegen/box/suspendConversion/chainedFunSuspendConversionForSimpleExpression.kt +++ b/compiler/testData/codegen/box/suspendConversion/chainedFunSuspendConversionForSimpleExpression.kt @@ -1,7 +1,5 @@ // !LANGUAGE: +SuspendConversion // IGNORE_BACKEND: JVM -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: ChainedFunSuspendConversionForSimpleExpressionKt$box$1 cannot be cast to kotlin.jvm.functions.Function1 fun interface SuspendRunnable { suspend fun invoke() diff --git a/compiler/testData/codegen/box/suspendConversion/severalConversionsInOneCall.kt b/compiler/testData/codegen/box/suspendConversion/severalConversionsInOneCall.kt index 23362be1de5..6ca62133796 100644 --- a/compiler/testData/codegen/box/suspendConversion/severalConversionsInOneCall.kt +++ b/compiler/testData/codegen/box/suspendConversion/severalConversionsInOneCall.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // !LANGUAGE: +SuspendConversion // !DIAGNOSTICS: -UNUSED_PARAMETER // IGNORE_BACKEND: JVM diff --git a/compiler/testData/codegen/box/suspendConversion/suspendAndFunConversionInDisabledMode.kt b/compiler/testData/codegen/box/suspendConversion/suspendAndFunConversionInDisabledMode.kt index 322c583e92e..53172dfd006 100644 --- a/compiler/testData/codegen/box/suspendConversion/suspendAndFunConversionInDisabledMode.kt +++ b/compiler/testData/codegen/box/suspendConversion/suspendAndFunConversionInDisabledMode.kt @@ -1,8 +1,6 @@ // !LANGUAGE: +SuspendConversion // !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION // IGNORE_BACKEND: JVM -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: SuspendAndFunConversionInDisabledModeKt$box$1 cannot be cast to kotlin.jvm.functions.Function1 fun interface Runnable { fun run() diff --git a/compiler/testData/codegen/box/suspendConversion/suspendConversionOnVarargElements.kt b/compiler/testData/codegen/box/suspendConversion/suspendConversionOnVarargElements.kt index 8d974827a4b..ea1ad511abe 100644 --- a/compiler/testData/codegen/box/suspendConversion/suspendConversionOnVarargElements.kt +++ b/compiler/testData/codegen/box/suspendConversion/suspendConversionOnVarargElements.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // !LANGUAGE: +SuspendConversion // !DIAGNOSTICS: -UNUSED_PARAMETER // IGNORE_BACKEND: JVM diff --git a/compiler/testData/codegen/box/suspendConversion/suspendConversionWithFunInterfaces.kt b/compiler/testData/codegen/box/suspendConversion/suspendConversionWithFunInterfaces.kt index 67f2b5331bd..e6a16cc3d24 100644 --- a/compiler/testData/codegen/box/suspendConversion/suspendConversionWithFunInterfaces.kt +++ b/compiler/testData/codegen/box/suspendConversion/suspendConversionWithFunInterfaces.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // !LANGUAGE: +SuspendConversion // !DIAGNOSTICS: -UNUSED_PARAMETER // IGNORE_BACKEND: JVM diff --git a/compiler/testData/codegen/box/suspendConversion/suspendConversionWithReferenceAdaptation.kt b/compiler/testData/codegen/box/suspendConversion/suspendConversionWithReferenceAdaptation.kt index 8c0e29359c6..37932b3109f 100644 --- a/compiler/testData/codegen/box/suspendConversion/suspendConversionWithReferenceAdaptation.kt +++ b/compiler/testData/codegen/box/suspendConversion/suspendConversionWithReferenceAdaptation.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // !LANGUAGE: +SuspendConversion // !DIAGNOSTICS: -UNUSED_PARAMETER diff --git a/compiler/testData/ir/irText/expressions/chainedFunSuspendConversionForSimpleExpression.fir.ir.txt b/compiler/testData/ir/irText/expressions/chainedFunSuspendConversionForSimpleExpression.fir.ir.txt index 4c7e1ead528..da398e97deb 100644 --- a/compiler/testData/ir/irText/expressions/chainedFunSuspendConversionForSimpleExpression.fir.ir.txt +++ b/compiler/testData/ir/irText/expressions/chainedFunSuspendConversionForSimpleExpression.fir.ir.txt @@ -32,12 +32,33 @@ FILE fqName: fileName:/chainedFunSuspendConversionForSimpleExpression.kt BLOCK_BODY CALL 'public final fun foo (s: .SuspendRunnable): kotlin.Unit declared in ' type=kotlin.Unit origin=null s: TYPE_OP type=.SuspendRunnable origin=SAM_CONVERSION typeOperand=.SuspendRunnable - GET_VAR 'f: kotlin.Function0 declared in .test' type=kotlin.Function0 origin=null + BLOCK type=kotlin.coroutines.SuspendFunction0 origin=SUSPEND_CONVERSION + FUN ADAPTER_FOR_SUSPEND_CONVERSION name:suspendConversion visibility:local modality:FINAL <> ($receiver:kotlin.Function0) returnType:kotlin.Unit [suspend] + $receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_SUSPEND_CONVERSION name:callee type:kotlin.Function0 + BLOCK_BODY + CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=null + $this: GET_VAR 'callee: kotlin.Function0 declared in .test.suspendConversion' type=kotlin.Function0 origin=null + FUNCTION_REFERENCE 'local final fun suspendConversion (): kotlin.Unit [suspend] declared in .test' type=kotlin.coroutines.SuspendFunction0 origin=SUSPEND_CONVERSION reflectionTarget=null + $receiver: GET_VAR 'f: kotlin.Function0 declared in .test' type=kotlin.Function0 origin=null CALL 'public final fun foo (s: .SuspendRunnable): kotlin.Unit declared in ' type=kotlin.Unit origin=null s: TYPE_OP type=.SuspendRunnable origin=SAM_CONVERSION typeOperand=.SuspendRunnable - CALL 'public final fun bar (): kotlin.Function0 declared in ' type=kotlin.Function0 origin=null + BLOCK type=kotlin.coroutines.SuspendFunction0 origin=SUSPEND_CONVERSION + FUN ADAPTER_FOR_SUSPEND_CONVERSION name:suspendConversion visibility:local modality:FINAL <> ($receiver:kotlin.Function0) returnType:kotlin.Unit [suspend] + $receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_SUSPEND_CONVERSION name:callee type:kotlin.Function0 + BLOCK_BODY + CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=null + $this: GET_VAR 'callee: kotlin.Function0 declared in .test.suspendConversion' type=kotlin.Function0 origin=null + FUNCTION_REFERENCE 'local final fun suspendConversion (): kotlin.Unit [suspend] declared in .test' type=kotlin.coroutines.SuspendFunction0 origin=SUSPEND_CONVERSION reflectionTarget=null + $receiver: CALL 'public final fun bar (): kotlin.Function0 declared in ' type=kotlin.Function0 origin=null VAR name:t type:kotlin.Function0 [var] GET_VAR 'f: kotlin.Function0 declared in .test' type=kotlin.Function0 origin=null CALL 'public final fun foo (s: .SuspendRunnable): kotlin.Unit declared in ' type=kotlin.Unit origin=null s: TYPE_OP type=.SuspendRunnable origin=SAM_CONVERSION typeOperand=.SuspendRunnable - GET_VAR 'var t: kotlin.Function0 [var] declared in .test' type=kotlin.Function0 origin=null + BLOCK type=kotlin.coroutines.SuspendFunction0 origin=SUSPEND_CONVERSION + FUN ADAPTER_FOR_SUSPEND_CONVERSION name:suspendConversion visibility:local modality:FINAL <> ($receiver:kotlin.Function0) returnType:kotlin.Unit [suspend] + $receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_SUSPEND_CONVERSION name:callee type:kotlin.Function0 + BLOCK_BODY + CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=null + $this: GET_VAR 'callee: kotlin.Function0 declared in .test.suspendConversion' type=kotlin.Function0 origin=null + FUNCTION_REFERENCE 'local final fun suspendConversion (): kotlin.Unit [suspend] declared in .test' type=kotlin.coroutines.SuspendFunction0 origin=SUSPEND_CONVERSION reflectionTarget=null + $receiver: GET_VAR 'var t: kotlin.Function0 [var] declared in .test' type=kotlin.Function0 origin=null