FIR: Make 'suspend fun', where 'suspend' is not builtin error in 1.8

#KT-49264
This commit is contained in:
Ilmir Usmanov
2022-03-30 00:37:37 +02:00
committed by teamcity
parent f75a8109d2
commit f473998e8b
9 changed files with 73 additions and 40 deletions
@@ -3872,6 +3872,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token, 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 -> add(FirErrors.RETURN_FOR_BUILT_IN_SUSPEND) { firDiagnostic ->
ReturnForBuiltInSuspendImpl( ReturnForBuiltInSuspendImpl(
firDiagnostic as KtPsiDiagnostic, firDiagnostic as KtPsiDiagnostic,
@@ -2699,6 +2699,14 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = ModifierFormForNonBuiltInSuspend::class 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>() { abstract class ReturnForBuiltInSuspend : KtFirDiagnostic<KtReturnExpression>() {
override val diagnosticClass get() = ReturnForBuiltInSuspend::class override val diagnosticClass get() = ReturnForBuiltInSuspend::class
} }
@@ -3256,6 +3256,16 @@ internal class ModifierFormForNonBuiltInSuspendImpl(
override val token: ValidityToken, override val token: ValidityToken,
) : KtFirDiagnostic.ModifierFormForNonBuiltInSuspend(), KtAbstractFirDiagnostic<PsiElement> ) : 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( internal class ReturnForBuiltInSuspendImpl(
override val firDiagnostic: KtPsiDiagnostic, override val firDiagnostic: KtPsiDiagnostic,
override val token: ValidityToken, override val token: ValidityToken,
@@ -1399,6 +1399,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) 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 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 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>() 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
import org.jetbrains.kotlin.config.LanguageFeature.ForbidExposingTypesInPrimaryConstructorProperties import org.jetbrains.kotlin.config.LanguageFeature.ForbidExposingTypesInPrimaryConstructorProperties
import org.jetbrains.kotlin.config.LanguageFeature.ForbidUsingExtensionPropertyTypeParameterInDelegate 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.ProhibitAssigningSingleElementsToVarargsInNamedForm
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitConfusingSyntaxInWhenBranches import org.jetbrains.kotlin.config.LanguageFeature.ProhibitConfusingSyntaxInWhenBranches
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitCyclesInAnnotations 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 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 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 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>() val RETURN_FOR_BUILT_IN_SUSPEND by error0<KtReturnExpression>()
// label // label
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter 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.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.StandardClassIds 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 import org.jetbrains.kotlin.utils.addToStdlib.lastIsInstanceOrNull
object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() { object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() {
@@ -81,38 +86,50 @@ object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() {
if (symbol.callableId == KOTLIN_SUSPEND_BUILT_IN_FUNCTION_CALLABLE_ID) { if (symbol.callableId == KOTLIN_SUSPEND_BUILT_IN_FUNCTION_CALLABLE_ID) {
if (reference.name != BUILTIN_SUSPEND_NAME || if (reference.name != BUILTIN_SUSPEND_NAME ||
expression.explicitReceiver != null || expression.explicitReceiver != null ||
!expression.hasFormOfSuspendModifierForLambda() expression.formOfSuspendModifierForLambdaOrFun() == null
) { ) {
reporter.reportOn(expression.source, FirErrors.NON_MODIFIER_FORM_FOR_BUILT_IN_SUSPEND, context) reporter.reportOn(expression.source, FirErrors.NON_MODIFIER_FORM_FOR_BUILT_IN_SUSPEND, context)
} }
} else { } else if (reference.name == BUILTIN_SUSPEND_NAME) {
if (reference.name == BUILTIN_SUSPEND_NAME && expression.hasFormOfSuspendModifierForLambda()) { when (expression.formOfSuspendModifierForLambdaOrFun()) {
reporter.reportOn(expression.source, FirErrors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND, context) 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 { private fun FirQualifiedAccessExpression.formOfSuspendModifierForLambdaOrFun(): SuspendCallArgumentKind? {
if (this !is FirFunctionCall) return false if (this !is FirFunctionCall) return null
val reference = this.calleeReference val reference = this.calleeReference
if (reference is FirResolvedCallableReference) return false if (reference is FirResolvedCallableReference) return null
if (typeArguments.any { it.source != null }) return false if (typeArguments.any { it.source != null }) return null
if (arguments.singleOrNull() is FirLambdaArgumentExpression) { if (arguments.singleOrNull() is FirLambdaArgumentExpression) {
// No brackets should be in a selector call // No brackets should be in a selector call
val callExpressionSource = val callExpressionSource =
if (explicitReceiver == null) source if (explicitReceiver == null) source
else source?.getChild(KtNodeTypes.CALL_EXPRESSION, index = 1, depth = 1) else source?.getChild(KtNodeTypes.CALL_EXPRESSION, index = 1, depth = 1)
if (callExpressionSource?.getChild(KtNodeTypes.VALUE_ARGUMENT_LIST, depth = 1) == null) { if (callExpressionSource?.getChild(KtNodeTypes.VALUE_ARGUMENT_LIST, depth = 1) == null) {
return true return SuspendCallArgumentKind.LAMBDA
} }
} }
if (origin == FirFunctionCallOrigin.Infix) { if (origin == FirFunctionCallOrigin.Infix) {
val lastArgument = arguments.lastOrNull() val lastArgument = arguments.lastOrNull()
if (lastArgument is FirAnonymousFunctionExpression && source?.getChild(KtNodeTypes.PARENTHESIZED, depth = 1) == null) { 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? { private fun findEnclosingSuspendFunction(context: CheckerContext): FirFunction? {
@@ -228,3 +245,7 @@ object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() {
) )
} }
} }
private enum class SuspendCallArgumentKind {
FUN, LAMBDA
}
@@ -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.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.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.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.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
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT 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, 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() { ... }''" "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") map.put(RETURN_FOR_BUILT_IN_SUSPEND, "Using implicit label for this lambda is prohibited")
// Label // Label
@@ -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) {}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// SKIP_TXT // SKIP_TXT
infix fun Int.suspend(c: () -> Unit) { c() } infix fun Int.suspend(c: () -> Unit) { c() }