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 e5d838c9646..f60f4b5466b 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 @@ -23212,6 +23212,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibility.kt"); } + @TestMetadata("suspendConversionCompatibilityInDisabledMode.kt") + public void testSuspendConversionCompatibilityInDisabledMode() throws Exception { + runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibilityInDisabledMode.kt"); + } + @TestMetadata("suspendConversionDisabled.kt") public void testSuspendConversionDisabled() throws Exception { runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.kt"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt index c2e3fdab941..79bb7f1bdd9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt @@ -49,7 +49,7 @@ private val DEFAULT_CALL_CHECKERS = listOf( PrimitiveNumericComparisonCallChecker, LambdaWithSuspendModifierCallChecker, UselessElvisCallChecker(), ResultTypeWithNullableOperatorsChecker(), NullableVarargArgumentCallChecker, NamedFunAsExpressionChecker, ContractNotAllowedCallChecker, ReifiedTypeParameterSubstitutionChecker(), - MissingDependencySupertypeChecker.ForCalls, AbstractClassInstantiationChecker, + MissingDependencySupertypeChecker.ForCalls, AbstractClassInstantiationChecker, SuspendConversionCallChecker ) private val DEFAULT_TYPE_CHECKERS = emptyList() private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/SuspendConversionCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/SuspendConversionCallChecker.kt new file mode 100644 index 00000000000..e53145b618c --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/SuspendConversionCallChecker.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.resolve.calls.checkers + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.builtins.isSuspendFunctionType +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.psi.KtCallableReferenceExpression +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgument +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallArgument +import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl +import org.jetbrains.kotlin.resolve.calls.tower.psiCallArgument +import org.jetbrains.kotlin.resolve.calls.tower.psiExpression + +object SuspendConversionCallChecker : CallChecker { + override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { + if (resolvedCall !is NewResolvedCallImpl<*>) return + + if (context.languageVersionSettings.supportsFeature(LanguageFeature.SuspendConversion)) return + + val argumentsWithSuspendConversion = resolvedCall.resolvedCallAtom.argumentsWithSuspendConversion + + for (argumentWithSuspendConversion in argumentsWithSuspendConversion.keys) { + context.trace.report( + Errors.UNSUPPORTED_FEATURE.on( + argumentWithSuspendConversion.psiCallArgument.valueArgument.asElement(), + LanguageFeature.SuspendConversion to context.languageVersionSettings + ) + ) + } + + for ((parameter, argument) in resolvedCall.argumentMappingByOriginal) { + if (!parameter.type.isSuspendFunctionType) continue + if (argument !is ResolvedCallArgument.SimpleArgument) continue + + val callArgument = argument.callArgument + if (callArgument !is CallableReferenceKotlinCallArgument) continue + + val callableReferenceExpression = callArgument.psiExpression as? KtCallableReferenceExpression ?: continue + val argumentCall = callableReferenceExpression.callableReference.getResolvedCall(context.trace.bindingContext) ?: continue + val target = argumentCall.resultingDescriptor as? FunctionDescriptor ?: continue + if (!target.isSuspend) { + context.trace.report( + Errors.UNSUPPORTED_FEATURE.on( + callableReferenceExpression, + LanguageFeature.SuspendConversion to context.languageVersionSettings + ) + ) + } + } + } +} \ No newline at end of file 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 7f33ce68ebe..27937f708c4 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 @@ -366,10 +366,7 @@ class CallableReferencesCandidateFactory( mappedArguments val suspendConversionStrategy = - if ( - callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SuspendConversion) && - !descriptor.isSuspend && expectedType?.isSuspendFunctionType == true - ) { + if (!descriptor.isSuspend && expectedType?.isSuspendFunctionType == true) { SuspendConversionStrategy.SUSPEND_CONVERSION } else { SuspendConversionStrategy.NO_CONVERSION 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 4956899a9b0..a3e469b3a50 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 @@ -18,8 +18,6 @@ object SuspendTypeConversions : ParameterTypeConversion { argument: KotlinCallArgument, expectedParameterType: UnwrappedType ): Boolean { - if (!candidate.callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SuspendConversion)) return true - if (argument !is SimpleKotlinCallArgument) return true val argumentType = argument.receiver.stableType diff --git a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibility.fir.kt b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibility.fir.kt index b2dec0ce14f..0caf0fbc82f 100644 --- a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibility.fir.kt +++ b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibility.fir.kt @@ -25,4 +25,19 @@ object Test2 { result } } -} \ No newline at end of file +} + +object Test3 { + fun foo(f: suspend () -> T): T = TODO() + + suspend fun bar(x: Int = 42): Int = 0 + + object Scope { + fun bar(x: Int = 42): String = "" + + fun test() { + val result = foo(::bar) + result + } + } +} diff --git a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibility.kt b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibility.kt index d19968690a6..4b8790cffeb 100644 --- a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibility.kt +++ b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibility.kt @@ -25,4 +25,19 @@ object Test2 { result } } +} + +object Test3 { + fun foo(f: suspend () -> T): T = TODO() + + suspend fun bar(x: Int = 42): Int = 0 + + object Scope { + fun bar(x: Int = 42): String = "" + + fun test() { + val result = foo(::bar) + result + } + } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibility.txt b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibility.txt index c298cc48bbd..0cb22c2e490 100644 --- a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibility.txt +++ b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibility.txt @@ -34,3 +34,21 @@ public object Test2 { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } } + +public object Test3 { + private constructor Test3() + public final suspend fun bar(/*0*/ x: kotlin.Int = ...): kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun foo(/*0*/ f: suspend () -> T): T + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public object Scope { + private constructor Scope() + public final fun bar(/*0*/ x: kotlin.Int = ...): kotlin.String + 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 final fun test(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} diff --git a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibilityInDisabledMode.fir.kt b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibilityInDisabledMode.fir.kt new file mode 100644 index 00000000000..2624f705ed6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibilityInDisabledMode.fir.kt @@ -0,0 +1,36 @@ +// !LANGUAGE: -SuspendConversion +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION + +object Test1 { + fun foo(f: suspend () -> T): T = TODO() + + suspend fun bar(x: Int = 42): Int = 0 + + object Scope { + fun bar(x: Int = 42): String = "" + + fun test() { + val result = foo(::bar) + result + } + } +} + +object Test2 { + fun foo(f: suspend () -> T): T = TODO() + + suspend fun bar(): Int = 0 + + object Scope1 { + suspend fun bar(x: Int = 42): Double = 0.0 + + object Scope2 { + fun bar(x: Int = 42): String = "" + + fun test() { + val result = foo(::bar) + result + } + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibilityInDisabledMode.kt b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibilityInDisabledMode.kt new file mode 100644 index 00000000000..db3f1841414 --- /dev/null +++ b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibilityInDisabledMode.kt @@ -0,0 +1,36 @@ +// !LANGUAGE: -SuspendConversion +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION + +object Test1 { + fun foo(f: suspend () -> T): T = TODO() + + suspend fun bar(x: Int = 42): Int = 0 + + object Scope { + fun bar(x: Int = 42): String = "" + + fun test() { + val result = foo(::bar) + result + } + } +} + +object Test2 { + fun foo(f: suspend () -> T): T = TODO() + + suspend fun bar(): Int = 0 + + object Scope1 { + suspend fun bar(x: Int = 42): Double = 0.0 + + object Scope2 { + fun bar(x: Int = 42): String = "" + + fun test() { + val result = foo(::bar) + result + } + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibilityInDisabledMode.txt b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibilityInDisabledMode.txt new file mode 100644 index 00000000000..55e0e79029b --- /dev/null +++ b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibilityInDisabledMode.txt @@ -0,0 +1,45 @@ +package + +public object Test1 { + private constructor Test1() + public final suspend fun bar(/*0*/ x: kotlin.Int = ...): kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun foo(/*0*/ f: suspend () -> T): T + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public object Scope { + private constructor Scope() + public final fun bar(/*0*/ x: kotlin.Int = ...): kotlin.String + 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 final fun test(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public object Test2 { + private constructor Test2() + public final suspend fun bar(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun foo(/*0*/ f: suspend () -> T): T + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public object Scope1 { + private constructor Scope1() + public final suspend fun bar(/*0*/ x: kotlin.Int = ...): kotlin.Double + 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 + + public object Scope2 { + private constructor Scope2() + public final fun bar(/*0*/ x: kotlin.Int = ...): kotlin.String + 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 final fun test(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } +} diff --git a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.fir.kt b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.fir.kt index 7ad794fd2bc..07265c3543f 100644 --- a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.fir.kt +++ b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.fir.kt @@ -5,6 +5,8 @@ fun foo1(f: suspend () -> String) {} fun foo2(f: suspend (Int) -> String) {} fun foo3(f: suspend () -> Unit) {} +fun bar(): String = "" + fun test( f0: suspend () -> String, f1: () -> String, @@ -14,10 +16,12 @@ fun test( foo1 { "str" } foo1(f0) - foo1(f1) - foo2(f2) - foo3(f3) + foo1(f1) + foo2(f2) + foo3(f3) - foo1(f2) - foo1(f3) + foo1(::bar) + + foo1(f2) + foo1(f3) } diff --git a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.kt b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.kt index ccccead0f34..64a19857e9e 100644 --- a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.kt +++ b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.kt @@ -5,6 +5,8 @@ fun foo1(f: suspend () -> String) {} fun foo2(f: suspend (Int) -> String) {} fun foo3(f: suspend () -> Unit) {} +fun bar(): String = "" + fun test( f0: suspend () -> String, f1: () -> String, @@ -14,10 +16,12 @@ fun test( foo1 { "str" } foo1(f0) - foo1(f1) - foo2(f2) - foo3(f3) + foo1(f1) + foo2(f2) + foo3(f3) - foo1(f2) - foo1(f3) + foo1(::bar) + + foo1(f2) + foo1(f3) } diff --git a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.txt b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.txt index 7abf5398088..d5904b97f7d 100644 --- a/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.txt +++ b/compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.txt @@ -1,5 +1,6 @@ package +public fun bar(): kotlin.String public fun foo1(/*0*/ f: suspend () -> kotlin.String): kotlin.Unit public fun foo2(/*0*/ f: suspend (kotlin.Int) -> kotlin.String): kotlin.Unit public fun foo3(/*0*/ f: suspend () -> kotlin.Unit): kotlin.Unit diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/lambdaExpectedType.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/lambdaExpectedType.kt index 9f4dd77d24e..bfa44b2e1eb 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/lambdaExpectedType.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/lambdaExpectedType.kt @@ -21,7 +21,7 @@ fun foo() { builder { 1 } val x = { 1 } - builder(x) + builder(x) builder({1} as (suspend () -> Int)) var i: Int = 1 @@ -32,7 +32,7 @@ fun foo() { genericBuilder { "" } val y = { 1 } - genericBuilder(y) + genericBuilder(y) unitBuilder {} unitBuilder { 1 } diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/functionVsSuspendFunction.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/functionVsSuspendFunction.kt index 370c0e6f882..10c77618ceb 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/functionVsSuspendFunction.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/functionVsSuspendFunction.kt @@ -8,12 +8,12 @@ fun ambiguous(sfn: suspend () -> Unit) = sfn fun ambiguous(fn: () -> Unit) = fn fun test1(sfn: suspend () -> Unit) = useFn(sfn) -fun test2(fn: () -> Unit) = useSuspendFn(fn) +fun test2(fn: () -> Unit) = useSuspendFn(fn) fun test3(sfn: suspend () -> Unit) = useSuspendFn(sfn) 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 diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index fca10f8f94c..bf00191d066 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -23294,6 +23294,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibility.kt"); } + @TestMetadata("suspendConversionCompatibilityInDisabledMode.kt") + public void testSuspendConversionCompatibilityInDisabledMode() throws Exception { + runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibilityInDisabledMode.kt"); + } + @TestMetadata("suspendConversionDisabled.kt") public void testSuspendConversionDisabled() throws Exception { runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index d57498c7aeb..3cb3939c27a 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -23214,6 +23214,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibility.kt"); } + @TestMetadata("suspendConversionCompatibilityInDisabledMode.kt") + public void testSuspendConversionCompatibilityInDisabledMode() throws Exception { + runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionCompatibilityInDisabledMode.kt"); + } + @TestMetadata("suspendConversionDisabled.kt") public void testSuspendConversionDisabled() throws Exception { runTest("compiler/testData/diagnostics/tests/suspendConversion/suspendConversionDisabled.kt");