[FIR] Prohibit suspend anonymous functions in statement position

^KT-62018 Fixed
^KT-62019
This commit is contained in:
Dmitriy Novozhilov
2023-12-12 17:02:11 +02:00
committed by Space Team
parent cae6e0ee0f
commit fb00c1dfb6
23 changed files with 116 additions and 5 deletions
@@ -1691,6 +1691,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.ANONYMOUS_SUSPEND_FUNCTION) { firDiagnostic ->
AnonymousSuspendFunctionImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.VALUE_CLASS_NOT_TOP_LEVEL) { firDiagnostic ->
ValueClassNotTopLevelImpl(
firDiagnostic as KtPsiDiagnostic,
@@ -1220,6 +1220,10 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = NoExplicitReturnTypeInApiModeWarning::class
}
interface AnonymousSuspendFunction : KtFirDiagnostic<KtDeclaration> {
override val diagnosticClass get() = AnonymousSuspendFunction::class
}
interface ValueClassNotTopLevel : KtFirDiagnostic<KtDeclaration> {
override val diagnosticClass get() = ValueClassNotTopLevel::class
}
@@ -1460,6 +1460,11 @@ internal class NoExplicitReturnTypeInApiModeWarningImpl(
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtDeclaration>(firDiagnostic, token), KtFirDiagnostic.NoExplicitReturnTypeInApiModeWarning
internal class AnonymousSuspendFunctionImpl(
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtDeclaration>(firDiagnostic, token), KtFirDiagnostic.AnonymousSuspendFunction
internal class ValueClassNotTopLevelImpl(
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
@@ -2027,6 +2027,12 @@ public class DiagnosticCompilerTestFirTestdataTestGenerated extends AbstractDiag
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/supertypeInitializedWithoutPrimaryConstructor.kt");
}
@Test
@TestMetadata("suspendAnonymousFunction.kt")
public void testSuspendAnonymousFunction() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/suspendAnonymousFunction.kt");
}
@Test
@TestMetadata("testIllegalAnnotationClass.kt")
public void testTestIllegalAnnotationClass() throws Exception {
@@ -2027,6 +2027,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/supertypeInitializedWithoutPrimaryConstructor.kt");
}
@Test
@TestMetadata("suspendAnonymousFunction.kt")
public void testSuspendAnonymousFunction() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/suspendAnonymousFunction.kt");
}
@Test
@TestMetadata("testIllegalAnnotationClass.kt")
public void testTestIllegalAnnotationClass() throws Exception {
@@ -0,0 +1,13 @@
FILE: suspendAnonymousFunction.kt
public final fun take(f: R|suspend () -> kotlin/Unit|): R|kotlin/Unit| {
}
public final fun test_1(): R|kotlin/Unit| {
suspend fun <anonymous>(): R|kotlin/Unit| <inline=Unknown> {
}
}
public final fun test_2(): R|kotlin/Unit| {
R|/take<Inapplicable(INAPPLICABLE_ARGUMENTS_MAPPING_ERROR): /take>#|(<Unresolved name: suspend>#, fun <anonymous>(): R|kotlin/Unit| <inline=Unknown> {
}
)
}
@@ -0,0 +1,11 @@
// ISSUE: KT-62018, KT-62019
fun take(f: suspend () -> Unit) {}
fun test_1() {
<!ANONYMOUS_SUSPEND_FUNCTION!>suspend<!> fun() {}
}
fun test_2() {
take(<!UNRESOLVED_REFERENCE!>suspend<!><!SYNTAX!><!> <!TOO_MANY_ARGUMENTS!>fun () {}<!>)
}
@@ -2027,6 +2027,12 @@ public class FirLightTreeDiagnosticsTestGenerated extends AbstractFirLightTreeDi
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/supertypeInitializedWithoutPrimaryConstructor.kt");
}
@Test
@TestMetadata("suspendAnonymousFunction.kt")
public void testSuspendAnonymousFunction() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/suspendAnonymousFunction.kt");
}
@Test
@TestMetadata("testIllegalAnnotationClass.kt")
public void testTestIllegalAnnotationClass() throws Exception {
@@ -2027,6 +2027,12 @@ public class FirPsiDiagnosticTestGenerated extends AbstractFirPsiDiagnosticTest
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/supertypeInitializedWithoutPrimaryConstructor.kt");
}
@Test
@TestMetadata("suspendAnonymousFunction.kt")
public void testSuspendAnonymousFunction() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/suspendAnonymousFunction.kt");
}
@Test
@TestMetadata("testIllegalAnnotationClass.kt")
public void testTestIllegalAnnotationClass() throws Exception {
@@ -516,6 +516,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val NO_EXPLICIT_RETURN_TYPE_IN_API_MODE by error<KtDeclaration>(PositioningStrategy.DECLARATION_NAME)
val NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING by warning<KtDeclaration>(PositioningStrategy.DECLARATION_NAME)
val ANONYMOUS_SUSPEND_FUNCTION by error<KtDeclaration>(PositioningStrategy.SUSPEND_MODIFIER)
}
val VALUE_CLASSES by object : DiagnosticGroup("Value classes") {
@@ -66,6 +66,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
LATEINIT_MODIFIER,
INLINE_OR_VALUE_MODIFIER,
INNER_MODIFIER,
SUSPEND_MODIFIER,
SELECTOR_BY_QUALIFIED,
REFERENCE_BY_QUALIFIED,
REFERENCED_NAME_BY_QUALIFIED,
@@ -358,6 +358,7 @@ object FirErrors {
val NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING: KtDiagnosticFactory0 by warning0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_START_TO_NAME)
val NO_EXPLICIT_RETURN_TYPE_IN_API_MODE: KtDiagnosticFactory0 by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_NAME)
val NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING: KtDiagnosticFactory0 by warning0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_NAME)
val ANONYMOUS_SUSPEND_FUNCTION: KtDiagnosticFactory0 by error0<KtDeclaration>(SourceElementPositioningStrategies.SUSPEND_MODIFIER)
// Value classes
val VALUE_CLASS_NOT_TOP_LEVEL: KtDiagnosticFactory0 by error0<KtDeclaration>(SourceElementPositioningStrategies.INLINE_OR_VALUE_MODIFIER)
@@ -209,6 +209,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set<String> = setOf(
"INAPPLICABLE_OPERATOR_MODIFIER",
"NO_EXPLICIT_VISIBILITY_IN_API_MODE",
"NO_EXPLICIT_RETURN_TYPE_IN_API_MODE",
"ANONYMOUS_SUSPEND_FUNCTION",
"VALUE_CLASS_NOT_TOP_LEVEL",
"VALUE_CLASS_NOT_FINAL",
"ABSENCE_OF_PRIMARY_CONSTRUCTOR_FOR_VALUE_CLASS",
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnonymousFunctio
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirFiniteBoundRestrictionChecker
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirInlinedLambdaNonSourceAnnotationsChecker
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirMissingDependencySupertypeChecker
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirSuspendAnonymousFunctionChecker
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.*
object CommonDeclarationCheckers : DeclarationCheckers() {
@@ -195,6 +196,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirAnonymousFunctionParametersChecker,
FirInlinedLambdaNonSourceAnnotationsChecker,
FirAnonymousFunctionSyntaxChecker,
FirSuspendAnonymousFunctionChecker,
)
override val anonymousInitializerCheckers: Set<FirAnonymousInitializerChecker>
@@ -0,0 +1,22 @@
/*
* Copyright 2010-2023 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.fir.analysis.checkers.expression
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirAnonymousFunctionChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
object FirSuspendAnonymousFunctionChecker : FirAnonymousFunctionChecker() {
override fun check(declaration: FirAnonymousFunction, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isLambda && declaration.isSuspend) {
reporter.reportOn(declaration.source, FirErrors.ANONYMOUS_SUSPEND_FUNCTION, context)
}
}
}
@@ -96,6 +96,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_USED_A
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANONYMOUS_FUNCTION_PARAMETER_WITH_DEFAULT_VALUE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANONYMOUS_FUNCTION_WITH_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANONYMOUS_INITIALIZER_IN_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANONYMOUS_SUSPEND_FUNCTION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.API_NOT_AVAILABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARGUMENT_PASSED_TWICE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARGUMENT_TYPE_MISMATCH
@@ -1155,6 +1156,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(NO_EXPLICIT_RETURN_TYPE_IN_API_MODE, "Return type must be specified in explicit API mode.")
map.put(NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING, "Visibility must be specified in explicit API mode.")
map.put(NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING, "Return type must be specified in explicit API mode.")
map.put(ANONYMOUS_SUSPEND_FUNCTION, "Anonymous suspend functions are prohibited.")
map.put(INCOMPATIBLE_MODIFIERS, "Modifier ''{0}'' is incompatible with ''{1}''.", TO_STRING, TO_STRING)
map.put(REDUNDANT_OPEN_IN_INTERFACE, "Modifier 'open' is redundant for abstract interface members.")
@@ -0,0 +1,7 @@
// ISSUE: KT-57991
fun foo() {
<!ANONYMOUS_SUSPEND_FUNCTION!>suspend<!> fun() {
}
}
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// ISSUE: KT-57991
fun foo() {
@@ -4,6 +4,6 @@ fun <T> produce(arg: () -> T): T = arg()
fun main() {
produce {
<!ARGUMENT_TYPE_MISMATCH!>suspend fun() {}<!> // CCE
<!ARGUMENT_TYPE_MISMATCH!><!ANONYMOUS_SUSPEND_FUNCTION!>suspend<!> fun() {}<!> // CCE
}
}
@@ -0,0 +1,11 @@
// FIR_DUMP
fun foo() {
<!ANONYMOUS_SUSPEND_FUNCTION!>suspend<!> fun() {
bar()
}
}
suspend fun bar() {
}
@@ -1,4 +1,4 @@
FILE: suspendCallFromAnonymousSuspend.kt
FILE: suspendCallFromAnonymousSuspend.fir.kt
public final fun foo(): R|kotlin/Unit| {
suspend fun <anonymous>(): R|kotlin/Unit| <inline=Unknown> {
R|/bar|()
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// FIR_DUMP
fun foo() {
+2 -1
View File
@@ -1,4 +1,5 @@
// FIR_IDENTICAL
// IGNORE_BACKEND_K2: ANY
// Ignore reasons: anonymous suspend functions are prohibited, KT-62018
// ISSUE: KT-58332
fun foo() {