FIR: Make 'suspend fun', where 'suspend' is not builtin error in 1.8
#KT-49264
This commit is contained in:
+12
@@ -3872,6 +3872,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN.errorFactory) { firDiagnostic ->
|
||||
ModifierFormForNonBuiltInSuspendFunErrorImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN.warningFactory) { firDiagnostic ->
|
||||
ModifierFormForNonBuiltInSuspendFunWarningImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.RETURN_FOR_BUILT_IN_SUSPEND) { firDiagnostic ->
|
||||
ReturnForBuiltInSuspendImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
|
||||
+8
@@ -2699,6 +2699,14 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = ModifierFormForNonBuiltInSuspend::class
|
||||
}
|
||||
|
||||
abstract class ModifierFormForNonBuiltInSuspendFunError : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = ModifierFormForNonBuiltInSuspendFunError::class
|
||||
}
|
||||
|
||||
abstract class ModifierFormForNonBuiltInSuspendFunWarning : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = ModifierFormForNonBuiltInSuspendFunWarning::class
|
||||
}
|
||||
|
||||
abstract class ReturnForBuiltInSuspend : KtFirDiagnostic<KtReturnExpression>() {
|
||||
override val diagnosticClass get() = ReturnForBuiltInSuspend::class
|
||||
}
|
||||
|
||||
+10
@@ -3256,6 +3256,16 @@ internal class ModifierFormForNonBuiltInSuspendImpl(
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.ModifierFormForNonBuiltInSuspend(), KtAbstractFirDiagnostic<PsiElement>
|
||||
|
||||
internal class ModifierFormForNonBuiltInSuspendFunErrorImpl(
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.ModifierFormForNonBuiltInSuspendFunError(), KtAbstractFirDiagnostic<PsiElement>
|
||||
|
||||
internal class ModifierFormForNonBuiltInSuspendFunWarningImpl(
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.ModifierFormForNonBuiltInSuspendFunWarning(), KtAbstractFirDiagnostic<PsiElement>
|
||||
|
||||
internal class ReturnForBuiltInSuspendImpl(
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
|
||||
+3
@@ -1399,6 +1399,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val NON_MODIFIER_FORM_FOR_BUILT_IN_SUSPEND by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN by deprecationError<PsiElement>(
|
||||
LanguageFeature.ModifierNonBuiltinSuspendFunError, PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED
|
||||
)
|
||||
val RETURN_FOR_BUILT_IN_SUSPEND by error<KtReturnExpression>()
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ForbidExposingTypesInPrimaryConstructorProperties
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ForbidUsingExtensionPropertyTypeParameterInDelegate
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ModifierNonBuiltinSuspendFunError
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitConfusingSyntaxInWhenBranches
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitCyclesInAnnotations
|
||||
@@ -726,6 +727,7 @@ object FirErrors {
|
||||
val ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val NON_MODIFIER_FORM_FOR_BUILT_IN_SUSPEND by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN by deprecationError0<PsiElement>(ModifierNonBuiltinSuspendFunError, SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val RETURN_FOR_BUILT_IN_SUSPEND by error0<KtReturnExpression>()
|
||||
|
||||
// label
|
||||
|
||||
+32
-11
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
@@ -30,8 +31,12 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.psi
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.lastIsInstanceOrNull
|
||||
|
||||
object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() {
|
||||
@@ -81,38 +86,50 @@ object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() {
|
||||
if (symbol.callableId == KOTLIN_SUSPEND_BUILT_IN_FUNCTION_CALLABLE_ID) {
|
||||
if (reference.name != BUILTIN_SUSPEND_NAME ||
|
||||
expression.explicitReceiver != null ||
|
||||
!expression.hasFormOfSuspendModifierForLambda()
|
||||
expression.formOfSuspendModifierForLambdaOrFun() == null
|
||||
) {
|
||||
reporter.reportOn(expression.source, FirErrors.NON_MODIFIER_FORM_FOR_BUILT_IN_SUSPEND, context)
|
||||
}
|
||||
} else {
|
||||
if (reference.name == BUILTIN_SUSPEND_NAME && expression.hasFormOfSuspendModifierForLambda()) {
|
||||
reporter.reportOn(expression.source, FirErrors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND, context)
|
||||
} else if (reference.name == BUILTIN_SUSPEND_NAME) {
|
||||
when (expression.formOfSuspendModifierForLambdaOrFun()) {
|
||||
SuspendCallArgumentKind.FUN -> {
|
||||
reporter.reportOn(expression.source, FirErrors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN, context)
|
||||
}
|
||||
SuspendCallArgumentKind.LAMBDA -> {
|
||||
reporter.reportOn(expression.source, FirErrors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND, context)
|
||||
}
|
||||
null -> {
|
||||
// Nothing to do
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirQualifiedAccessExpression.hasFormOfSuspendModifierForLambda(): Boolean {
|
||||
if (this !is FirFunctionCall) return false
|
||||
private fun FirQualifiedAccessExpression.formOfSuspendModifierForLambdaOrFun(): SuspendCallArgumentKind? {
|
||||
if (this !is FirFunctionCall) return null
|
||||
val reference = this.calleeReference
|
||||
if (reference is FirResolvedCallableReference) return false
|
||||
if (typeArguments.any { it.source != null }) return false
|
||||
if (reference is FirResolvedCallableReference) return null
|
||||
if (typeArguments.any { it.source != null }) return null
|
||||
if (arguments.singleOrNull() is FirLambdaArgumentExpression) {
|
||||
// No brackets should be in a selector call
|
||||
val callExpressionSource =
|
||||
if (explicitReceiver == null) source
|
||||
else source?.getChild(KtNodeTypes.CALL_EXPRESSION, index = 1, depth = 1)
|
||||
if (callExpressionSource?.getChild(KtNodeTypes.VALUE_ARGUMENT_LIST, depth = 1) == null) {
|
||||
return true
|
||||
return SuspendCallArgumentKind.LAMBDA
|
||||
}
|
||||
}
|
||||
if (origin == FirFunctionCallOrigin.Infix) {
|
||||
val lastArgument = arguments.lastOrNull()
|
||||
if (lastArgument is FirAnonymousFunctionExpression && source?.getChild(KtNodeTypes.PARENTHESIZED, depth = 1) == null) {
|
||||
return true
|
||||
return if (lastArgument.source?.lighterASTNode?.tokenType == KtStubElementTypes.FUNCTION) {
|
||||
SuspendCallArgumentKind.FUN
|
||||
} else {
|
||||
SuspendCallArgumentKind.LAMBDA
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
return null
|
||||
}
|
||||
|
||||
private fun findEnclosingSuspendFunction(context: CheckerContext): FirFunction? {
|
||||
@@ -228,3 +245,7 @@ object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private enum class SuspendCallArgumentKind {
|
||||
FUN, LAMBDA
|
||||
}
|
||||
+5
@@ -296,6 +296,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_STDLIB_CL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_VAL_ON_ANNOTATION_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MULTIPLE_VARARG_PARAMETERS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT
|
||||
@@ -1987,6 +1988,10 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
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(RETURN_FOR_BUILT_IN_SUSPEND, "Using implicit label for this lambda is prohibited")
|
||||
|
||||
// Label
|
||||
|
||||
Vendored
-29
@@ -1,29 +0,0 @@
|
||||
// SKIP_TXT
|
||||
|
||||
infix fun Int.suspend(c: () -> Unit) { c() }
|
||||
|
||||
fun bar() {
|
||||
1 <!MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND!>suspend<!> fun() {
|
||||
println()
|
||||
}
|
||||
|
||||
1 <!SYNTAX!>@Ann suspend fun()<!> {
|
||||
println()
|
||||
}
|
||||
|
||||
1 <!MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND!>suspend<!> @Ann fun() {
|
||||
println()
|
||||
}
|
||||
}
|
||||
|
||||
@Target(AnnotationTarget.EXPRESSION)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class Ann
|
||||
|
||||
fun main(suspend: WLambdaInvoke) {
|
||||
1 <!MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND!>suspend<!> fun() {}
|
||||
}
|
||||
|
||||
class WLambdaInvoke {
|
||||
operator fun Int.invoke(l: () -> Unit) {}
|
||||
}
|
||||
Vendored
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// SKIP_TXT
|
||||
|
||||
infix fun Int.suspend(c: () -> Unit) { c() }
|
||||
|
||||
Reference in New Issue
Block a user