diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index a502cd5e763..fdc2916d89b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -1176,6 +1176,7 @@ public interface Errors { DiagnosticFactory0 NON_MODIFIER_FORM_FOR_BUILT_IN_SUSPEND = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 RETURN_FOR_BUILT_IN_SUSPEND = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN = DiagnosticFactory0.create(WARNING); DiagnosticFactory1> PLUGIN_ERROR = DiagnosticFactory1.create(ERROR); DiagnosticFactory1> PLUGIN_WARNING = DiagnosticFactory1.create(WARNING); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 8a41f22ca8b..e262dfc7924 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -1069,6 +1069,7 @@ public class DefaultErrorMessages { MAP.put(IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE, "Returning type parameter has been inferred to Nothing implicitly because Nothing is more specific than specified expected type. Please specify type arguments explicitly in accordance with expected type to hide this warning. Nothing can produce an exception at runtime. See KT-36776 for more details."); MAP.put(RETURN_FOR_BUILT_IN_SUSPEND, "Using implicit label for this lambda is prohibited"); MAP.put(MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND, "Calls having a form of ''suspend {}'' are deprecated because ''suspend'' in the context will have a meaning of a modifier. Add empty argument list to the call: ''suspend() { ... }''"); + MAP.put(MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN, "Calls having a form of ''suspend fun'' are deprecated because ''suspend'' in the context will have a meaning of a modifier. Surround the argument of the call with parens: ''suspend(fun() { ... })''"); MAP.put(PLUGIN_ERROR, "{0}", (d, c) -> d.getText()); MAP.put(PLUGIN_WARNING, "{0}", (d, c) -> d.getText()); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/LambdaWithSuspendModifierCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/LambdaWithSuspendModifierCallChecker.kt index 4e0bf1fb0e0..7c42fdcac14 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/LambdaWithSuspendModifierCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/LambdaWithSuspendModifierCallChecker.kt @@ -34,7 +34,12 @@ object LambdaWithSuspendModifierCallChecker : CallChecker { } else -> { if ((calleeName == "suspend" || variableCalleeName == "suspend") && call.hasFormOfSuspendModifierForLambdaOrFun()) { - context.trace.report(Errors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND.on(reportOn)) + if (call.hasNoArgumentListButDanglingLambdas() || call.isInfixWithRightLambda()) { + context.trace.report(Errors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND.on(reportOn)) + } else { + require(call.isInfixWithRightFun()) + context.trace.report(Errors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN.on(reportOn)) + } } } } @@ -43,7 +48,7 @@ object LambdaWithSuspendModifierCallChecker : CallChecker { private fun Call.hasFormOfSuspendModifierForLambdaOrFun() = !isCallableReference() && typeArguments.isEmpty() - && (hasNoArgumentListButDanglingLambdas() || isInfixWithRightLambdaOrFun()) + && (hasNoArgumentListButDanglingLambdas() || isInfixWithRightLambda() || isInfixWithRightFun()) private fun Call.referencedName() = calleeExpression?.safeAs()?.getReferencedName() @@ -51,7 +56,11 @@ object LambdaWithSuspendModifierCallChecker : CallChecker { private fun Call.hasNoArgumentListButDanglingLambdas() = valueArgumentList?.leftParenthesis == null && functionLiteralArguments.isNotEmpty() - private fun Call.isInfixWithRightLambdaOrFun() = + private fun Call.isInfixWithRightLambda() = isInfixCall(this) - && callElement.safeAs()?.right.let { it is KtLambdaExpression || it is KtNamedFunction } + && callElement.safeAs()?.right is KtLambdaExpression + + private fun Call.isInfixWithRightFun() = + isInfixCall(this) + && callElement.safeAs()?.right is KtNamedFunction } diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/nonModifierFormForBuiltInWithFun.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/nonModifierFormForBuiltInWithFun.fir.kt new file mode 100644 index 00000000000..bdb68ef8e77 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/nonModifierFormForBuiltInWithFun.fir.kt @@ -0,0 +1,29 @@ +// SKIP_TXT + +infix fun Int.suspend(c: () -> Unit) { c() } + +fun bar() { + 1 suspend fun() { + println() + } + + 1 @Ann suspend fun() { + println() + } + + 1 suspend @Ann fun() { + println() + } +} + +@Target(AnnotationTarget.EXPRESSION) +@Retention(AnnotationRetention.SOURCE) +annotation class Ann + +fun main(suspend: WLambdaInvoke) { + 1 suspend fun() {} +} + +class WLambdaInvoke { + operator fun Int.invoke(l: () -> Unit) {} +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/nonModifierFormForBuiltInWithFun.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/nonModifierFormForBuiltInWithFun.kt index c37c7714e36..8bc1d3a4f33 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/nonModifierFormForBuiltInWithFun.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/nonModifierFormForBuiltInWithFun.kt @@ -1,10 +1,9 @@ -// FIR_IDENTICAL // SKIP_TXT infix fun Int.suspend(c: () -> Unit) { c() } fun bar() { - 1 suspend fun() { + 1 suspend fun() { println() } @@ -12,7 +11,7 @@ fun bar() { println() } - 1 suspend @Ann fun() { + 1 suspend @Ann fun() { println() } } @@ -22,7 +21,7 @@ fun bar() { annotation class Ann fun main(suspend: WLambdaInvoke) { - 1 suspend fun() {} + 1 suspend fun() {} } class WLambdaInvoke {