[K2] Disallow named functions as expressions

^KT-62573 Fixed
^KT-59945 Fixed
This commit is contained in:
Alejandro Serrano Mena
2023-10-13 12:42:46 +02:00
committed by Space Team
parent aaf7ccbebd
commit f227447837
18 changed files with 112 additions and 4 deletions
@@ -3056,6 +3056,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token, token,
) )
} }
add(FirErrors.SINGLE_ANONYMOUS_FUNCTION_WITH_NAME.errorFactory) { firDiagnostic ->
SingleAnonymousFunctionWithNameErrorImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.SINGLE_ANONYMOUS_FUNCTION_WITH_NAME.warningFactory) { firDiagnostic ->
SingleAnonymousFunctionWithNameWarningImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.ANONYMOUS_FUNCTION_PARAMETER_WITH_DEFAULT_VALUE) { firDiagnostic -> add(FirErrors.ANONYMOUS_FUNCTION_PARAMETER_WITH_DEFAULT_VALUE) { firDiagnostic ->
AnonymousFunctionParameterWithDefaultValueImpl( AnonymousFunctionParameterWithDefaultValueImpl(
firDiagnostic as KtPsiDiagnostic, firDiagnostic as KtPsiDiagnostic,
@@ -2164,6 +2164,14 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = AnonymousFunctionWithName::class override val diagnosticClass get() = AnonymousFunctionWithName::class
} }
interface SingleAnonymousFunctionWithNameError : KtFirDiagnostic<KtFunction> {
override val diagnosticClass get() = SingleAnonymousFunctionWithNameError::class
}
interface SingleAnonymousFunctionWithNameWarning : KtFirDiagnostic<KtFunction> {
override val diagnosticClass get() = SingleAnonymousFunctionWithNameWarning::class
}
interface AnonymousFunctionParameterWithDefaultValue : KtFirDiagnostic<KtParameter> { interface AnonymousFunctionParameterWithDefaultValue : KtFirDiagnostic<KtParameter> {
override val diagnosticClass get() = AnonymousFunctionParameterWithDefaultValue::class override val diagnosticClass get() = AnonymousFunctionParameterWithDefaultValue::class
} }
@@ -2592,6 +2592,16 @@ internal class AnonymousFunctionWithNameImpl(
token: KtLifetimeToken, token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtFunction>(firDiagnostic, token), KtFirDiagnostic.AnonymousFunctionWithName ) : KtAbstractFirDiagnostic<KtFunction>(firDiagnostic, token), KtFirDiagnostic.AnonymousFunctionWithName
internal class SingleAnonymousFunctionWithNameErrorImpl(
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtFunction>(firDiagnostic, token), KtFirDiagnostic.SingleAnonymousFunctionWithNameError
internal class SingleAnonymousFunctionWithNameWarningImpl(
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtFunction>(firDiagnostic, token), KtFirDiagnostic.SingleAnonymousFunctionWithNameWarning
internal class AnonymousFunctionParameterWithDefaultValueImpl( internal class AnonymousFunctionParameterWithDefaultValueImpl(
firDiagnostic: KtPsiDiagnostic, firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken, token: KtLifetimeToken,
@@ -9212,6 +9212,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
runTest("compiler/testData/diagnostics/tests/declarationChecks/kt2643MultiDeclInControlFlow.kt"); runTest("compiler/testData/diagnostics/tests/declarationChecks/kt2643MultiDeclInControlFlow.kt");
} }
@Test
@TestMetadata("kt47245.kt")
public void testKt47245() throws Exception {
runTest("compiler/testData/diagnostics/tests/declarationChecks/kt47245.kt");
}
@Test @Test
@TestMetadata("kt559.kt") @TestMetadata("kt559.kt")
public void testKt559() throws Exception { public void testKt559() throws Exception {
@@ -9212,6 +9212,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
runTest("compiler/testData/diagnostics/tests/declarationChecks/kt2643MultiDeclInControlFlow.kt"); runTest("compiler/testData/diagnostics/tests/declarationChecks/kt2643MultiDeclInControlFlow.kt");
} }
@Test
@TestMetadata("kt47245.kt")
public void testKt47245() throws Exception {
runTest("compiler/testData/diagnostics/tests/declarationChecks/kt47245.kt");
}
@Test @Test
@TestMetadata("kt559.kt") @TestMetadata("kt559.kt")
public void testKt559() throws Exception { public void testKt559() throws Exception {
@@ -9206,6 +9206,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/declarationChecks/kt2643MultiDeclInControlFlow.kt"); runTest("compiler/testData/diagnostics/tests/declarationChecks/kt2643MultiDeclInControlFlow.kt");
} }
@Test
@TestMetadata("kt47245.kt")
public void testKt47245() throws Exception {
runTest("compiler/testData/diagnostics/tests/declarationChecks/kt47245.kt");
}
@Test @Test
@TestMetadata("kt559.kt") @TestMetadata("kt559.kt")
public void testKt559() throws Exception { public void testKt559() throws Exception {
@@ -9212,6 +9212,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/declarationChecks/kt2643MultiDeclInControlFlow.kt"); runTest("compiler/testData/diagnostics/tests/declarationChecks/kt2643MultiDeclInControlFlow.kt");
} }
@Test
@TestMetadata("kt47245.kt")
public void testKt47245() throws Exception {
runTest("compiler/testData/diagnostics/tests/declarationChecks/kt47245.kt");
}
@Test @Test
@TestMetadata("kt559.kt") @TestMetadata("kt559.kt")
public void testKt559() throws Exception { public void testKt559() throws Exception {
@@ -1096,6 +1096,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val FUNCTION_DECLARATION_WITH_NO_NAME by error<KtFunction>(PositioningStrategy.DECLARATION_SIGNATURE) val FUNCTION_DECLARATION_WITH_NO_NAME by error<KtFunction>(PositioningStrategy.DECLARATION_SIGNATURE)
val ANONYMOUS_FUNCTION_WITH_NAME by error<KtFunction>() val ANONYMOUS_FUNCTION_WITH_NAME by error<KtFunction>()
val SINGLE_ANONYMOUS_FUNCTION_WITH_NAME by deprecationError<KtFunction>(LanguageFeature.ProhibitSingleNamedFunctionAsExpression)
// TODO: val ANONYMOUS_FUNCTION_WITH_NAME by error1<PsiElement, Name>(SourceElementPositioningStrategies.DECLARATION_NAME) // TODO: val ANONYMOUS_FUNCTION_WITH_NAME by error1<PsiElement, Name>(SourceElementPositioningStrategies.DECLARATION_NAME)
val ANONYMOUS_FUNCTION_PARAMETER_WITH_DEFAULT_VALUE by error<KtParameter>(PositioningStrategy.PARAMETER_DEFAULT_VALUE) val ANONYMOUS_FUNCTION_PARAMETER_WITH_DEFAULT_VALUE by error<KtParameter>(PositioningStrategy.PARAMETER_DEFAULT_VALUE)
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.config.LanguageFeature.ProhibitInlineModifierOnPrima
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitInvisibleAbstractMethodsInSuperclasses import org.jetbrains.kotlin.config.LanguageFeature.ProhibitInvisibleAbstractMethodsInSuperclasses
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitNonReifiedArraysAsReifiedTypeArguments import org.jetbrains.kotlin.config.LanguageFeature.ProhibitNonReifiedArraysAsReifiedTypeArguments
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitScriptTopLevelInnerClasses import org.jetbrains.kotlin.config.LanguageFeature.ProhibitScriptTopLevelInnerClasses
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitSingleNamedFunctionAsExpression
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitUseSiteTargetAnnotationsOnSuperTypes import org.jetbrains.kotlin.config.LanguageFeature.ProhibitUseSiteTargetAnnotationsOnSuperTypes
import org.jetbrains.kotlin.config.LanguageFeature.RestrictRetentionForExpressionAnnotations import org.jetbrains.kotlin.config.LanguageFeature.RestrictRetentionForExpressionAnnotations
import org.jetbrains.kotlin.config.LanguageFeature.RestrictionOfValReassignmentViaBackingField import org.jetbrains.kotlin.config.LanguageFeature.RestrictionOfValReassignmentViaBackingField
@@ -551,6 +552,7 @@ object FirErrors {
val NON_MEMBER_FUNCTION_NO_BODY by error1<KtFunction, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) val NON_MEMBER_FUNCTION_NO_BODY by error1<KtFunction, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
val FUNCTION_DECLARATION_WITH_NO_NAME by error0<KtFunction>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) val FUNCTION_DECLARATION_WITH_NO_NAME by error0<KtFunction>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
val ANONYMOUS_FUNCTION_WITH_NAME by error0<KtFunction>() val ANONYMOUS_FUNCTION_WITH_NAME by error0<KtFunction>()
val SINGLE_ANONYMOUS_FUNCTION_WITH_NAME by deprecationError0<KtFunction>(ProhibitSingleNamedFunctionAsExpression)
val ANONYMOUS_FUNCTION_PARAMETER_WITH_DEFAULT_VALUE by error0<KtParameter>(SourceElementPositioningStrategies.PARAMETER_DEFAULT_VALUE) val ANONYMOUS_FUNCTION_PARAMETER_WITH_DEFAULT_VALUE by error0<KtParameter>(SourceElementPositioningStrategies.PARAMETER_DEFAULT_VALUE)
val USELESS_VARARG_ON_PARAMETER by warning0<KtParameter>() val USELESS_VARARG_ON_PARAMETER by warning0<KtParameter>()
val MULTIPLE_VARARG_PARAMETERS by error0<KtParameter>(SourceElementPositioningStrategies.PARAMETER_VARARG_MODIFIER) val MULTIPLE_VARARG_PARAMETERS by error0<KtParameter>(SourceElementPositioningStrategies.PARAMETER_VARARG_MODIFIER)
@@ -129,7 +129,8 @@ object CommonExpressionCheckers : ExpressionCheckers() {
override val blockCheckers: Set<FirBlockChecker> override val blockCheckers: Set<FirBlockChecker>
get() = setOf( get() = setOf(
FirForLoopChecker, FirForLoopChecker,
FirConflictsExpressionChecker FirConflictsExpressionChecker,
FirSingleNamedFunctionChecker
) )
override val checkNotNullCallCheckers: Set<FirCheckNotNullCallChecker> override val checkNotNullCallCheckers: Set<FirCheckNotNullCallChecker>
@@ -0,0 +1,27 @@
/*
* 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.config.LanguageFeature
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.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
object FirSingleNamedFunctionChecker : FirBlockChecker() {
override fun check(expression: FirBlock, context: CheckerContext, reporter: DiagnosticReporter) {
if (expression is FirSingleExpressionBlock && expression.statement is FirSimpleFunction) {
reporter.reportOn(
expression.statement.source,
FirErrors.SINGLE_ANONYMOUS_FUNCTION_WITH_NAME,
context
)
}
}
}
@@ -570,6 +570,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SENSELESS_NULL_IN
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SETTER_PROJECTED_OUT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SETTER_PROJECTED_OUT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SINGLETON_IN_SUPERTYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SINGLETON_IN_SUPERTYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SINGLE_ANONYMOUS_FUNCTION_WITH_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SMARTCAST_IMPOSSIBLE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SMARTCAST_IMPOSSIBLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SPREAD_OF_NULLABLE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SPREAD_OF_NULLABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUBCLASS_OPT_IN_INAPPLICABLE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUBCLASS_OPT_IN_INAPPLICABLE
@@ -1783,6 +1784,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(NON_MEMBER_FUNCTION_NO_BODY, "Function ''{0}'' must have a body.", DECLARATION_NAME) map.put(NON_MEMBER_FUNCTION_NO_BODY, "Function ''{0}'' must have a body.", DECLARATION_NAME)
map.put(FUNCTION_DECLARATION_WITH_NO_NAME, "Function declaration must have a name.") map.put(FUNCTION_DECLARATION_WITH_NO_NAME, "Function declaration must have a name.")
map.put(ANONYMOUS_FUNCTION_WITH_NAME, "Anonymous functions with names are prohibited.") map.put(ANONYMOUS_FUNCTION_WITH_NAME, "Anonymous functions with names are prohibited.")
map.put(SINGLE_ANONYMOUS_FUNCTION_WITH_NAME, "Anonymous functions with names are prohibited.")
map.put( map.put(
ANONYMOUS_FUNCTION_PARAMETER_WITH_DEFAULT_VALUE, ANONYMOUS_FUNCTION_PARAMETER_WITH_DEFAULT_VALUE,
@@ -0,0 +1,6 @@
// !COMPILER_VERSION 2.0
// SKIP_KT_DUMP
fun test() {
for (i in 0..0) <!SINGLE_ANONYMOUS_FUNCTION_WITH_NAME_WARNING!>fun x() {}<!>
}
@@ -0,0 +1,6 @@
// !COMPILER_VERSION 2.0
// SKIP_KT_DUMP
fun test() {
for (i in 0..0) fun x() {}
}
@@ -1,5 +1,6 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER -UNUSED_VARIABLE // !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER -UNUSED_VARIABLE
// !CHECK_TYPE // !CHECK_TYPE
// !COMPILER_VERSION 2.0
fun foo(block: () -> (() -> Int)) {} fun foo(block: () -> (() -> Int)) {}
fun test() { fun test() {
@@ -26,15 +27,15 @@ fun test() {
<!SYNTAX!><!>fun named7() = 1 <!SYNTAX!><!>fun named7() = 1
val x3 = when (1) { val x3 = when (1) {
0 -> fun named8(): Int {return 1} 0 -> <!SINGLE_ANONYMOUS_FUNCTION_WITH_NAME_WARNING!>fun named8(): Int {return 1}<!>
else -> fun named9() = 1 else -> <!SINGLE_ANONYMOUS_FUNCTION_WITH_NAME_WARNING!>fun named9() = 1<!>
} }
val x31 = when (1) { val x31 = when (1) {
0 -> { 0 -> {
fun named10(): Int {return 1} fun named10(): Int {return 1}
} }
else -> fun named11() = 1 else -> <!SINGLE_ANONYMOUS_FUNCTION_WITH_NAME_WARNING!>fun named11() = 1<!>
} }
val x4 = { val x4 = {
@@ -1,5 +1,6 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER -UNUSED_VARIABLE // !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER -UNUSED_VARIABLE
// !CHECK_TYPE // !CHECK_TYPE
// !COMPILER_VERSION 2.0
fun foo(block: () -> (() -> Int)) {} fun foo(block: () -> (() -> Int)) {}
fun test() { fun test() {
@@ -9212,6 +9212,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/declarationChecks/kt2643MultiDeclInControlFlow.kt"); runTest("compiler/testData/diagnostics/tests/declarationChecks/kt2643MultiDeclInControlFlow.kt");
} }
@Test
@TestMetadata("kt47245.kt")
public void testKt47245() throws Exception {
runTest("compiler/testData/diagnostics/tests/declarationChecks/kt47245.kt");
}
@Test @Test
@TestMetadata("kt559.kt") @TestMetadata("kt559.kt")
public void testKt559() throws Exception { public void testKt559() throws Exception {
@@ -314,6 +314,7 @@ enum class LanguageFeature(
ProhibitImplementingVarByInheritedVal(KOTLIN_2_1, kind = BUG_FIX), // KT-56779 ProhibitImplementingVarByInheritedVal(KOTLIN_2_1, kind = BUG_FIX), // KT-56779
PrioritizedEnumEntries(KOTLIN_2_1, kind = UNSTABLE_FEATURE), // KT-58920 PrioritizedEnumEntries(KOTLIN_2_1, kind = UNSTABLE_FEATURE), // KT-58920
ProhibitInlineModifierOnPrimaryConstructorParameters(KOTLIN_2_1, kind = BUG_FIX), // KT-59664 ProhibitInlineModifierOnPrimaryConstructorParameters(KOTLIN_2_1, kind = BUG_FIX), // KT-59664
ProhibitSingleNamedFunctionAsExpression(KOTLIN_2_1, kind = BUG_FIX), // KT-62573
// End of 2.* language features -------------------------------------------------- // End of 2.* language features --------------------------------------------------