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 f099e320355..cdfc0e31bb4 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 @@ -240,7 +240,6 @@ 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." // TODO: should refer to LanguageVersionSettings.SuspendConversion - // TODO: should prefer another candidate without suspend conversion when ambiguous if (expectedType?.isSuspendFunctionType(session) == true && argumentTypeForApplicabilityCheck.isBuiltinFunctionalType(session) && !argumentTypeForApplicabilityCheck.isSuspendFunctionType(session) @@ -253,6 +252,7 @@ fun Candidate.resolvePlainArgumentType( isKFunctionType = argumentTypeForApplicabilityCheck.isKFunctionType(session) ) substitutor.substituteOrSelf(argumentTypeForApplicabilityCheck) + usesSuspendConversion = true } checkApplicabilityForArgumentType( 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 bdf1c8f9bdf..b9ef206b0d4 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 @@ -97,6 +97,7 @@ class Candidate( var resultingTypeForCallableReference: ConeKotlinType? = null var outerConstraintBuilderEffect: (ConstraintSystemOperation.() -> Unit)? = null var usesSAM: Boolean = false + var usesSuspendConversion: Boolean = false var argumentMapping: Map? = null lateinit var typeArgumentMapping: TypeArgumentMapping 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 40300cf1ac9..b062a4d5575 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 @@ -42,7 +42,7 @@ class ConeOverloadConflictResolver( candidates return chooseMaximallySpecificCandidates( - fixedCandidates, discriminateGenerics, discriminateAbstracts, discriminateSAMs = true + fixedCandidates, discriminateGenerics, discriminateAbstracts, discriminateSAMs = true, discriminateSuspendConversions = true ) } @@ -63,7 +63,8 @@ class ConeOverloadConflictResolver( candidates: Set, discriminateGenerics: Boolean, discriminateAbstracts: Boolean, - discriminateSAMs: Boolean + discriminateSAMs: Boolean, + discriminateSuspendConversions: Boolean, ): Set { findMaximallySpecificCall(candidates, false)?.let { return setOf(it) } @@ -78,7 +79,23 @@ class ConeOverloadConflictResolver( 0, candidates.size -> { } else -> return chooseMaximallySpecificCandidates( - filtered, discriminateGenerics, discriminateAbstracts, discriminateSAMs = false + filtered, discriminateGenerics, discriminateAbstracts, discriminateSAMs = false, discriminateSuspendConversions + ) + } + } + + if (discriminateSuspendConversions) { + val filtered = candidates.filterTo(mutableSetOf()) { !it.usesSuspendConversion } + when (filtered.size) { + 1 -> return filtered + 0, candidates.size -> { + } + else -> return chooseMaximallySpecificCandidates( + filtered, + discriminateGenerics, + discriminateAbstracts, + discriminateSAMs = false, + discriminateSuspendConversions = false ) } } @@ -90,7 +107,11 @@ class ConeOverloadConflictResolver( 0, candidates.size -> { } else -> return chooseMaximallySpecificCandidates( - filtered, discriminateGenerics, discriminateAbstracts = false, discriminateSAMs = false + filtered, + discriminateGenerics, + discriminateAbstracts = false, + discriminateSAMs = false, + discriminateSuspendConversions = false ) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt index 292143f2823..1507c68cc56 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt @@ -226,7 +226,7 @@ internal object CheckCallableReferenceExpectedType : CheckerStage() { is FirVariable<*> -> createKPropertyType(fir, resultingReceiverType, returnTypeRef) else -> ConeKotlinErrorType(ConeSimpleDiagnostic("Unknown callable kind: ${fir::class}", DiagnosticKind.UnknownCallableKind)) }.let(candidate.substitutor::substituteOrSelf) - + candidate.usesSuspendConversion = requireSuspendConversion candidate.resultingTypeForCallableReference = resultingType candidate.outerConstraintBuilderEffect = fun ConstraintSystemOperation.() { addOtherSystem(candidate.system.asReadOnlyStorage()) diff --git a/compiler/testData/diagnostics/tests/suspendConversion/overloadResolutionBySuspendModifier.fir.kt b/compiler/testData/diagnostics/tests/suspendConversion/overloadResolutionBySuspendModifier.fir.kt index 286713a41be..8e1492e8364 100644 --- a/compiler/testData/diagnostics/tests/suspendConversion/overloadResolutionBySuspendModifier.fir.kt +++ b/compiler/testData/diagnostics/tests/suspendConversion/overloadResolutionBySuspendModifier.fir.kt @@ -14,6 +14,6 @@ fun test1() { // candidate without suspend conversions is more specific fun test2(f: () -> Int, g: suspend () -> Int) { - foo(f) + foo(f) foo(g) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/functionVsSuspendFunction.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/functionVsSuspendFunction.fir.kt index b85141c411a..a29feb03691 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/functionVsSuspendFunction.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/functionVsSuspendFunction.fir.kt @@ -15,5 +15,5 @@ fun test4(): suspend () -> Unit = useSuspendFn {} fun test5() = useSuspendFn {} fun test5(sfn: suspend () -> Unit) = ambiguous(sfn) -fun test6(fn: () -> Unit) = ambiguous(fn) +fun test6(fn: () -> Unit) = ambiguous(fn) fun test7(): () -> Unit = ambiguous {} \ No newline at end of file