diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 4fd29a7fa66..6a019a2ee39 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -26028,6 +26028,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/samConversions/kt17765.kt"); } + @Test + @TestMetadata("kt50477.kt") + public void testKt50477() throws Exception { + runTest("compiler/testData/diagnostics/tests/samConversions/kt50477.kt"); + } + @Test @TestMetadata("OverloadPriority.kt") public void testOverloadPriority() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 925eb8c2a1d..5e4d706dede 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -26028,6 +26028,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/samConversions/kt17765.kt"); } + @Test + @TestMetadata("kt50477.kt") + public void testKt50477() throws Exception { + runTest("compiler/testData/diagnostics/tests/samConversions/kt50477.kt"); + } + @Test @TestMetadata("OverloadPriority.kt") public void testOverloadPriority() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index 3c58cd2b4c7..b96f813c804 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -26028,6 +26028,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/samConversions/kt17765.kt"); } + @Test + @TestMetadata("kt50477.kt") + public void testKt50477() throws Exception { + runTest("compiler/testData/diagnostics/tests/samConversions/kt50477.kt"); + } + @Test @TestMetadata("OverloadPriority.kt") public void testOverloadPriority() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 63d404a27a2..a22f0462613 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -44497,6 +44497,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/sam/kt50171.kt"); } + @Test + @TestMetadata("kt50477Enabled.kt") + public void testKt50477Enabled() throws Exception { + runTest("compiler/testData/codegen/box/sam/kt50477Enabled.kt"); + } + @Test @TestMetadata("nonInlinedSamWrapper.kt") public void testNonInlinedSamWrapper() throws Exception { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SamTypeConversions.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SamTypeConversions.kt index 7ccdba8595b..f68e81443c9 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SamTypeConversions.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SamTypeConversions.kt @@ -5,6 +5,8 @@ package org.jetbrains.kotlin.resolve.calls.components +import org.jetbrains.kotlin.builtins.isFunctionOrKFunctionTypeWithAnySuspendability +import org.jetbrains.kotlin.builtins.isFunctionOrSuspendFunctionType import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype import org.jetbrains.kotlin.config.LanguageFeature @@ -41,15 +43,23 @@ object SamTypeConversions : ParameterTypeConversion { return false } - override fun conversionIsNeededBeforeSubtypingCheck(argument: KotlinCallArgument): Boolean { + override fun conversionIsNeededBeforeSubtypingCheck( + argument: KotlinCallArgument, + areSuspendOnlySamConversionsSupported: Boolean + ): Boolean { return when (argument) { is SubKotlinCallArgument -> { val stableType = argument.receiver.stableType - if (stableType.isFunctionType) return true + if ( + stableType.isFunctionType || + (areSuspendOnlySamConversionsSupported && stableType.isFunctionOrKFunctionTypeWithAnySuspendability) + ) return true hasNonAnalyzedLambdaAsReturnType(argument.callResult.subResolvedAtoms, stableType) } - is SimpleKotlinCallArgument -> argument.receiver.stableType.isFunctionType + is SimpleKotlinCallArgument -> argument.receiver.stableType.run { + isFunctionType || (areSuspendOnlySamConversionsSupported && isFunctionOrKFunctionTypeWithAnySuspendability) + } is LambdaKotlinCallArgument, is CallableReferenceKotlinCallArgument -> true else -> false } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SuspendConversionUtils.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SuspendConversionUtils.kt index 2ce67531ca6..9908c88d6a6 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SuspendConversionUtils.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SuspendConversionUtils.kt @@ -27,8 +27,12 @@ object SuspendTypeConversions : ParameterTypeConversion { return false } - override fun conversionIsNeededBeforeSubtypingCheck(argument: KotlinCallArgument): Boolean = - argument is SimpleKotlinCallArgument && argument.receiver.stableType.isFunctionType + override fun conversionIsNeededBeforeSubtypingCheck( + argument: KotlinCallArgument, + areSuspendOnlySamConversionsSupported: Boolean + ): Boolean = + argument is SimpleKotlinCallArgument && + (argument.receiver.stableType.isFunctionType || argument.receiver.stableType.isKFunctionType) override fun conversionIsNeededAfterSubtypingCheck(argument: KotlinCallArgument): Boolean = argument is SimpleKotlinCallArgument && argument.receiver.stableType.isFunctionTypeOrSubtype diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/UnitTypeConversions.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/UnitTypeConversions.kt index ccabf7a3fd4..caeaced5512 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/UnitTypeConversions.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/UnitTypeConversions.kt @@ -51,7 +51,10 @@ object UnitTypeConversions : ParameterTypeConversion { isUnit() || isDynamic() || isNothing() - override fun conversionIsNeededBeforeSubtypingCheck(argument: KotlinCallArgument): Boolean = + override fun conversionIsNeededBeforeSubtypingCheck( + argument: KotlinCallArgument, + areSuspendOnlySamConversionsSupported: Boolean + ): Boolean = argument is SimpleKotlinCallArgument && argument.receiver.stableType.isFunctionType override fun conversionIsNeededAfterSubtypingCheck(argument: KotlinCallArgument): Boolean { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/typeConversions.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/typeConversions.kt index e123e1d488e..e236e4bcda6 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/typeConversions.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/typeConversions.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.resolve.calls.components +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.ParameterDescriptor import org.jetbrains.kotlin.resolve.calls.components.candidate.ResolutionCandidate import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument @@ -17,7 +18,7 @@ interface ParameterTypeConversion { expectedParameterType: UnwrappedType ): Boolean - fun conversionIsNeededBeforeSubtypingCheck(argument: KotlinCallArgument): Boolean + fun conversionIsNeededBeforeSubtypingCheck(argument: KotlinCallArgument, areSuspendOnlySamConversionsSupported: Boolean): Boolean fun conversionIsNeededAfterSubtypingCheck(argument: KotlinCallArgument): Boolean fun convertParameterType( @@ -110,7 +111,12 @@ object TypeConversions { conversion: ParameterTypeConversion ): ConversionData { val conversionDefinitelyNotNeeded = conversion.conversionDefinitelyNotNeeded(candidate, argument, candidateExpectedType) - return if (!conversionDefinitelyNotNeeded && conversion.conversionIsNeededBeforeSubtypingCheck(argument)) { + val areSuspendOnlySamConversionsSupported = + candidate.callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SuspendOnlySamConversions) + return if ( + !conversionDefinitelyNotNeeded && + conversion.conversionIsNeededBeforeSubtypingCheck(argument, areSuspendOnlySamConversionsSupported) + ) { ConversionData( conversion.convertParameterType(candidate, argument, candidateParameter, candidateExpectedType), wasConversion = true, diff --git a/compiler/testData/codegen/box/sam/kt50477Enabled.kt b/compiler/testData/codegen/box/sam/kt50477Enabled.kt new file mode 100644 index 00000000000..f16df138c0a --- /dev/null +++ b/compiler/testData/codegen/box/sam/kt50477Enabled.kt @@ -0,0 +1,30 @@ +// !LANGUAGE: +SuspendOnlySamConversions +// TARGET_BACKEND: JVM_IR + +fun interface FI { + suspend fun call() // suspending now(!!!) +} + +fun accept(fi: FI): Int = 1 + +suspend fun foo() {} +fun foo2() {} + +fun box(): String { + val fi0: () -> Unit = {} + accept(fi0) + + val fi: suspend () -> Unit = {} // Lambda of a suspending(!!!) functional type + accept(fi) // ERROR: Type mismatch. Required: FI Found: suspend () → Unit + + accept(::foo) + val x1 = ::foo + accept(x1) // ERROR: Type mismatch. Required: FI Found: suspend () → Unit + + accept(::foo2) + val x2 = ::foo2 + accept(x2) // ERROR: Type mismatch. Required: FI Found: suspend () → Unit + + return "OK" +} + diff --git a/compiler/testData/diagnostics/tests/samConversions/kt50477.fir.kt b/compiler/testData/diagnostics/tests/samConversions/kt50477.fir.kt new file mode 100644 index 00000000000..db6ddb4e561 --- /dev/null +++ b/compiler/testData/diagnostics/tests/samConversions/kt50477.fir.kt @@ -0,0 +1,23 @@ +// !LANGUAGE: -SuspendOnlySamConversions + +fun interface FI { + suspend fun call() // suspending now(!!!) +} + +fun accept(fi: FI): Int = TODO() + +suspend fun foo() {} +fun foo2() {} + +fun main() { + val fi: suspend () -> Unit = {} // Lambda of a suspending(!!!) functional type + accept(fi) // ERROR: Type mismatch. Required: FI Found: suspend () → Unit + + accept(::foo) + val x1 = ::foo + accept(x1) // ERROR: Type mismatch. Required: FI Found: suspend () → Unit + + accept(::foo2) + val x2 = ::foo2 + accept(x2) +} diff --git a/compiler/testData/diagnostics/tests/samConversions/kt50477.kt b/compiler/testData/diagnostics/tests/samConversions/kt50477.kt new file mode 100644 index 00000000000..2db45457359 --- /dev/null +++ b/compiler/testData/diagnostics/tests/samConversions/kt50477.kt @@ -0,0 +1,23 @@ +// !LANGUAGE: -SuspendOnlySamConversions + +fun interface FI { + suspend fun call() // suspending now(!!!) +} + +fun accept(fi: FI): Int = TODO() + +suspend fun foo() {} +fun foo2() {} + +fun main() { + val fi: suspend () -> Unit = {} // Lambda of a suspending(!!!) functional type + accept(fi) // ERROR: Type mismatch. Required: FI Found: suspend () → Unit + + accept(::foo) + val x1 = ::foo + accept(x1) // ERROR: Type mismatch. Required: FI Found: suspend () → Unit + + accept(::foo2) + val x2 = ::foo2 + accept(x2) +} diff --git a/compiler/testData/diagnostics/tests/samConversions/kt50477.txt b/compiler/testData/diagnostics/tests/samConversions/kt50477.txt new file mode 100644 index 00000000000..c2c30312e45 --- /dev/null +++ b/compiler/testData/diagnostics/tests/samConversions/kt50477.txt @@ -0,0 +1,13 @@ +package + +public fun accept(/*0*/ fi: FI): kotlin.Int +public suspend fun foo(): kotlin.Unit +public fun foo2(): kotlin.Unit +public fun main(): kotlin.Unit + +public fun interface FI { + public abstract suspend fun call(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index b11ae933097..efc3303bb4a 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -26040,6 +26040,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/samConversions/kt17765.kt"); } + @Test + @TestMetadata("kt50477.kt") + public void testKt50477() throws Exception { + runTest("compiler/testData/diagnostics/tests/samConversions/kt50477.kt"); + } + @Test @TestMetadata("OverloadPriority.kt") public void testOverloadPriority() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 57b7d80c5e5..dddd79d355b 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -44497,6 +44497,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/sam/kt50171.kt"); } + @Test + @TestMetadata("kt50477Enabled.kt") + public void testKt50477Enabled() throws Exception { + runTest("compiler/testData/codegen/box/sam/kt50477Enabled.kt"); + } + @Test @TestMetadata("nonInlinedSamWrapper.kt") public void testNonInlinedSamWrapper() throws Exception { diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 163f7d2c5de..eafd22b4e64 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -242,6 +242,7 @@ enum class LanguageFeature( ProhibitQualifiedAccessToUninitializedEnumEntry(KOTLIN_1_7, kind = BUG_FIX), // KT-41124 ForbidRecursiveDelegateExpressions(KOTLIN_1_7, kind = BUG_FIX), KotlinFunInterfaceConstructorReference(KOTLIN_1_7), + SuspendOnlySamConversions(KOTLIN_1_7), // 1.8