From ac642cf175924fff54072a723317eb7dbe55ef0e Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Wed, 22 Apr 2020 04:51:07 +0300 Subject: [PATCH] Support suspend conversion in callable reference adaptation #KT-15917 In Progress --- ...irOldFrontendDiagnosticsTestGenerated.java | 15 +++++++++++ .../components/CallableReferenceResolution.kt | 25 ++++++++++++++++--- ...spendConversionForCallableReference.fir.kt | 18 +++++++++++++ ...icSuspendConversionForCallableReference.kt | 18 +++++++++++++ ...cSuspendConversionForCallableReference.txt | 8 ++++++ .../suspendConversionWithFunInterfaces.fir.kt | 21 ++++++++++++++++ .../suspendConversionWithFunInterfaces.kt | 21 ++++++++++++++++ .../suspendConversionWithFunInterfaces.txt | 15 +++++++++++ ...ndConversionWithReferenceAdaptation.fir.kt | 21 ++++++++++++++++ ...uspendConversionWithReferenceAdaptation.kt | 21 ++++++++++++++++ ...spendConversionWithReferenceAdaptation.txt | 11 ++++++++ .../checkers/DiagnosticsTestGenerated.java | 15 +++++++++++ .../DiagnosticsUsingJavacTestGenerated.java | 15 +++++++++++ 13 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionForCallableReference.fir.kt create mode 100644 compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionForCallableReference.kt create mode 100644 compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionForCallableReference.txt create mode 100644 compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.fir.kt create mode 100644 compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.kt create mode 100644 compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.txt create mode 100644 compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithReferenceAdaptation.fir.kt create mode 100644 compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithReferenceAdaptation.kt create mode 100644 compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithReferenceAdaptation.txt diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index dc5e1a3e0e9..1af61258989 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -23011,6 +23011,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversion.kt"); } + @TestMetadata("basicSuspendConversionForCallableReference.kt") + public void testBasicSuspendConversionForCallableReference() throws Exception { + runTest("compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionForCallableReference.kt"); + } + @TestMetadata("basicSuspendConversionGenerics.kt") public void testBasicSuspendConversionGenerics() throws Exception { runTest("compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionGenerics.kt"); @@ -23025,6 +23030,16 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte public void testSuspendConversionDisabled() throws Exception { runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.kt"); } + + @TestMetadata("suspendConversionWithFunInterfaces.kt") + public void testSuspendConversionWithFunInterfaces() throws Exception { + runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.kt"); + } + + @TestMetadata("suspendConversionWithReferenceAdaptation.kt") + public void testSuspendConversionWithReferenceAdaptation() throws Exception { + runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithReferenceAdaptation.kt"); + } } @TestMetadata("compiler/testData/diagnostics/tests/syntheticExtensions") diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt index 45a8709ed84..ad9abcdf1e8 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt @@ -75,9 +75,14 @@ class CallableReferenceAdaptation( val argumentTypes: Array, val coercionStrategy: CoercionStrategy, val defaults: Int, - val mappedArguments: Map + val mappedArguments: Map, + val suspendConversionStrategy: SuspendConversionStrategy ) +enum class SuspendConversionStrategy { + SUSPEND_CONVERSION, NO_CONVERSION +} + /** * cases: class A {}, class B { companion object }, object C, enum class D { E } * A::foo <-> Type @@ -332,10 +337,21 @@ class CallableReferencesCandidateFactory( else mappedArguments + val suspendConversionStrategy = + if ( + callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SuspendConversion) && + !descriptor.isSuspend && expectedType?.isSuspendFunctionType == true + ) { + SuspendConversionStrategy.SUSPEND_CONVERSION + } else { + SuspendConversionStrategy.NO_CONVERSION + } + return CallableReferenceAdaptation( @Suppress("UNCHECKED_CAST") (mappedArgumentTypes as Array), coercion, defaults, - adaptedArguments + adaptedArguments, + suspendConversionStrategy ) } @@ -428,9 +444,12 @@ class CallableReferencesCandidateFactory( descriptorReturnType } + val suspendConversionStrategy = callableReferenceAdaptation?.suspendConversionStrategy + val isSuspend = descriptor.isSuspend || suspendConversionStrategy == SuspendConversionStrategy.SUSPEND_CONVERSION + return callComponents.reflectionTypes.getKFunctionType( Annotations.EMPTY, null, argumentsAndReceivers, null, - returnType, descriptor.builtIns, descriptor.isSuspend + returnType, descriptor.builtIns, isSuspend ) to callableReferenceAdaptation } else -> return ErrorUtils.createErrorType("Unsupported descriptor type: $descriptor") to null diff --git a/compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionForCallableReference.fir.kt b/compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionForCallableReference.fir.kt new file mode 100644 index 00000000000..e939a1927b4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionForCallableReference.fir.kt @@ -0,0 +1,18 @@ +// !LANGUAGE: +SuspendConversion +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun foo1(f: suspend () -> Unit) {} +fun bar1() {} + +fun foo2(e: T, f: suspend (T) -> Unit) {} +fun bar2(x: Int) {} +fun bar2(s: String) {} + +fun test() { + foo1(::bar1) + + foo2(42, ::bar2) + foo2("str", ::bar2) + + foo2(42, ::bar1) +} diff --git a/compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionForCallableReference.kt b/compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionForCallableReference.kt new file mode 100644 index 00000000000..dd0f341fe3f --- /dev/null +++ b/compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionForCallableReference.kt @@ -0,0 +1,18 @@ +// !LANGUAGE: +SuspendConversion +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun foo1(f: suspend () -> Unit) {} +fun bar1() {} + +fun foo2(e: T, f: suspend (T) -> Unit) {} +fun bar2(x: Int) {} +fun bar2(s: String) {} + +fun test() { + foo1(::bar1) + + foo2(42, ::bar2) + foo2("str", ::bar2) + + foo2(42, ::bar1) +} diff --git a/compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionForCallableReference.txt b/compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionForCallableReference.txt new file mode 100644 index 00000000000..93d0d2da1dd --- /dev/null +++ b/compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionForCallableReference.txt @@ -0,0 +1,8 @@ +package + +public fun bar1(): kotlin.Unit +public fun bar2(/*0*/ x: kotlin.Int): kotlin.Unit +public fun bar2(/*0*/ s: kotlin.String): kotlin.Unit +public fun foo1(/*0*/ f: suspend () -> kotlin.Unit): kotlin.Unit +public fun foo2(/*0*/ e: T, /*1*/ f: suspend (T) -> kotlin.Unit): kotlin.Unit +public fun test(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.fir.kt b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.fir.kt new file mode 100644 index 00000000000..b8f3daddd31 --- /dev/null +++ b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.fir.kt @@ -0,0 +1,21 @@ +// !LANGUAGE: +SuspendConversion +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun interface SuspendRunnable { + suspend fun invoke() +} + +fun foo1(s: SuspendRunnable) {} +fun bar1() {} + +fun bar2(s: String = ""): Int = 0 + +fun bar3() {} +suspend fun bar3(s: String = ""): Int = 0 + +fun test() { + foo1(::bar1) + foo1(::bar2) + + foo1(::bar3) // Should be ambiguity +} diff --git a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.kt b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.kt new file mode 100644 index 00000000000..9737580400a --- /dev/null +++ b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.kt @@ -0,0 +1,21 @@ +// !LANGUAGE: +SuspendConversion +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun interface SuspendRunnable { + suspend fun invoke() +} + +fun foo1(s: SuspendRunnable) {} +fun bar1() {} + +fun bar2(s: String = ""): Int = 0 + +fun bar3() {} +suspend fun bar3(s: String = ""): Int = 0 + +fun test() { + foo1(::bar1) + foo1(::bar2) + + foo1(::bar3) // Should be ambiguity +} diff --git a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.txt b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.txt new file mode 100644 index 00000000000..e3c1c2274da --- /dev/null +++ b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.txt @@ -0,0 +1,15 @@ +package + +public fun bar1(): kotlin.Unit +public fun bar2(/*0*/ s: kotlin.String = ...): kotlin.Int +public fun bar3(): kotlin.Unit +public suspend fun bar3(/*0*/ s: kotlin.String = ...): kotlin.Int +public fun foo1(/*0*/ s: SuspendRunnable): kotlin.Unit +public fun test(): kotlin.Unit + +public fun interface SuspendRunnable { + 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 abstract suspend fun invoke(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithReferenceAdaptation.fir.kt b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithReferenceAdaptation.fir.kt new file mode 100644 index 00000000000..24ebf2b341e --- /dev/null +++ b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithReferenceAdaptation.fir.kt @@ -0,0 +1,21 @@ +// !LANGUAGE: +SuspendConversion +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun unitCoercion(f: suspend () -> Unit) {} +fun foo(): Int = 0 + +fun defaults(f: suspend (Int) -> String) {} +fun bar(i: Int, l: Long = 42L): String = "" + +fun varargs(f: suspend (Int, Int, Int) -> String) {} +fun baz(vararg ints: Int): String = "" + +fun unitCoercionAndDefaults(f: suspend () -> Unit) {} +fun all(s: String = ""): Int = 0 + +fun test() { + unitCoercion(::foo) + defaults(::bar) + varargs(::baz) + unitCoercionAndDefaults(::all) +} diff --git a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithReferenceAdaptation.kt b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithReferenceAdaptation.kt new file mode 100644 index 00000000000..73f5ea5fa48 --- /dev/null +++ b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithReferenceAdaptation.kt @@ -0,0 +1,21 @@ +// !LANGUAGE: +SuspendConversion +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun unitCoercion(f: suspend () -> Unit) {} +fun foo(): Int = 0 + +fun defaults(f: suspend (Int) -> String) {} +fun bar(i: Int, l: Long = 42L): String = "" + +fun varargs(f: suspend (Int, Int, Int) -> String) {} +fun baz(vararg ints: Int): String = "" + +fun unitCoercionAndDefaults(f: suspend () -> Unit) {} +fun all(s: String = ""): Int = 0 + +fun test() { + unitCoercion(::foo) + defaults(::bar) + varargs(::baz) + unitCoercionAndDefaults(::all) +} diff --git a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithReferenceAdaptation.txt b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithReferenceAdaptation.txt new file mode 100644 index 00000000000..391ad648b99 --- /dev/null +++ b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithReferenceAdaptation.txt @@ -0,0 +1,11 @@ +package + +public fun all(/*0*/ s: kotlin.String = ...): kotlin.Int +public fun bar(/*0*/ i: kotlin.Int, /*1*/ l: kotlin.Long = ...): kotlin.String +public fun baz(/*0*/ vararg ints: kotlin.Int /*kotlin.IntArray*/): kotlin.String +public fun defaults(/*0*/ f: suspend (kotlin.Int) -> kotlin.String): kotlin.Unit +public fun foo(): kotlin.Int +public fun test(): kotlin.Unit +public fun unitCoercion(/*0*/ f: suspend () -> kotlin.Unit): kotlin.Unit +public fun unitCoercionAndDefaults(/*0*/ f: suspend () -> kotlin.Unit): kotlin.Unit +public fun varargs(/*0*/ f: suspend (kotlin.Int, kotlin.Int, kotlin.Int) -> kotlin.String): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 832f783a7d7..ed2dea498ff 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -23093,6 +23093,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversion.kt"); } + @TestMetadata("basicSuspendConversionForCallableReference.kt") + public void testBasicSuspendConversionForCallableReference() throws Exception { + runTest("compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionForCallableReference.kt"); + } + @TestMetadata("basicSuspendConversionGenerics.kt") public void testBasicSuspendConversionGenerics() throws Exception { runTest("compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionGenerics.kt"); @@ -23107,6 +23112,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali public void testSuspendConversionDisabled() throws Exception { runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.kt"); } + + @TestMetadata("suspendConversionWithFunInterfaces.kt") + public void testSuspendConversionWithFunInterfaces() throws Exception { + runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.kt"); + } + + @TestMetadata("suspendConversionWithReferenceAdaptation.kt") + public void testSuspendConversionWithReferenceAdaptation() throws Exception { + runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithReferenceAdaptation.kt"); + } } @TestMetadata("compiler/testData/diagnostics/tests/syntheticExtensions") diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 3d1d9d1ca5c..1a8e2cb6ede 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -23013,6 +23013,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversion.kt"); } + @TestMetadata("basicSuspendConversionForCallableReference.kt") + public void testBasicSuspendConversionForCallableReference() throws Exception { + runTest("compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionForCallableReference.kt"); + } + @TestMetadata("basicSuspendConversionGenerics.kt") public void testBasicSuspendConversionGenerics() throws Exception { runTest("compiler/testData/diagnostics/tests/suspendConversion/basicSuspendConversionGenerics.kt"); @@ -23027,6 +23032,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing public void testSuspendConversionDisabled() throws Exception { runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.kt"); } + + @TestMetadata("suspendConversionWithFunInterfaces.kt") + public void testSuspendConversionWithFunInterfaces() throws Exception { + runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithFunInterfaces.kt"); + } + + @TestMetadata("suspendConversionWithReferenceAdaptation.kt") + public void testSuspendConversionWithReferenceAdaptation() throws Exception { + runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionWithReferenceAdaptation.kt"); + } } @TestMetadata("compiler/testData/diagnostics/tests/syntheticExtensions")