From 5c716ea979c46af875cf28d6d174a326f70181bb Mon Sep 17 00:00:00 2001 From: Tianyu Geng Date: Wed, 22 Sep 2021 18:37:23 -0700 Subject: [PATCH] FIR checker: report NOT_A_FUNCTION_LABEL --- .../diagnostics/KtFirDataClassConverters.kt | 6 ++++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 4 +++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 5 +++ .../diagnostics/FirDiagnosticsList.kt | 1 + .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../expression/FirReturnAllowedChecker.kt | 10 ++++-- .../diagnostics/FirDefaultErrorMessages.kt | 32 ++++++++++--------- .../coneDiagnosticToFirDiagnostic.kt | 1 + .../kotlin/fir/builder/BaseFirBuilder.kt | 6 +++- .../fir/diagnostics/ConeSimpleDiagnostic.kt | 1 + .../notAFunctionLabel_after.fir.kt | 4 +-- .../notAFunctionLabel_before.fir.kt | 4 +-- 12 files changed, 52 insertions(+), 23 deletions(-) diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 3b1f3ca2dda..f33574fd614 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -3404,6 +3404,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.NOT_A_FUNCTION_LABEL) { firDiagnostic -> + NotAFunctionLabelImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY) { firDiagnostic -> ReturnInFunctionWithExpressionBodyImpl( firDiagnostic as FirPsiDiagnostic, diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index cfe18c39331..e7233c4cd16 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -2371,6 +2371,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = ReturnNotAllowed::class } + abstract class NotAFunctionLabel : KtFirDiagnostic() { + override val diagnosticClass get() = NotAFunctionLabel::class + } + abstract class ReturnInFunctionWithExpressionBody : KtFirDiagnostic() { override val diagnosticClass get() = ReturnInFunctionWithExpressionBody::class } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 072cfe7b706..151a374d66d 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -2859,6 +2859,11 @@ internal class ReturnNotAllowedImpl( override val token: ValidityToken, ) : KtFirDiagnostic.ReturnNotAllowed(), KtAbstractFirDiagnostic +internal class NotAFunctionLabelImpl( + override val firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.NotAFunctionLabel(), KtAbstractFirDiagnostic + internal class ReturnInFunctionWithExpressionBodyImpl( override val firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken, diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 12296d44669..7a175b93c3b 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -1216,6 +1216,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val RETURNS by object : DiagnosticGroup("Returns") { val RETURN_NOT_ALLOWED by error(PositioningStrategy.RETURN_WITH_LABEL) + val NOT_A_FUNCTION_LABEL by error(PositioningStrategy.RETURN_WITH_LABEL) val RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY by error(PositioningStrategy.RETURN_WITH_LABEL) val NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY by error(PositioningStrategy.DECLARATION_WITH_BODY) diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 72db9ac9c64..86fe9e291ae 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -647,6 +647,7 @@ object FirErrors { // Returns val RETURN_NOT_ALLOWED by error0(SourceElementPositioningStrategies.RETURN_WITH_LABEL) + val NOT_A_FUNCTION_LABEL by error0(SourceElementPositioningStrategies.RETURN_WITH_LABEL) val RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY by error0(SourceElementPositioningStrategies.RETURN_WITH_LABEL) val NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY by error0(SourceElementPositioningStrategies.DECLARATION_WITH_BODY) val ANONYMOUS_INITIALIZER_IN_INTERFACE by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirReturnAllowedChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirReturnAllowedChecker.kt index 99160ec78a6..1b05504c12f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirReturnAllowedChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirReturnAllowedChecker.kt @@ -12,6 +12,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic +import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference @@ -24,9 +26,11 @@ object FirReturnAllowedChecker : FirReturnExpressionChecker() { val source = expression.source if (source?.kind == FirFakeSourceElementKind.ImplicitReturn) return - val targetSymbol = expression.target.labeledElement.symbol - - if (!isReturnAllowed(targetSymbol, context)) { + val labeledElement = expression.target.labeledElement + val targetSymbol = labeledElement.symbol + if (labeledElement is FirErrorFunction && (labeledElement.diagnostic as? ConeSimpleDiagnostic)?.kind == DiagnosticKind.NotAFunctionLabel) { + reporter.reportOn(source, FirErrors.NOT_A_FUNCTION_LABEL, context) + } else if (!isReturnAllowed(targetSymbol, context)) { reporter.reportOn(source, FirErrors.RETURN_NOT_ALLOWED, context) } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 729d61f4525..fe7ebb123d6 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -5,10 +5,10 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics -import org.jetbrains.kotlin.diagnostics.rendering.LanguageFeatureMessageRenderer import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.RENDER_POSITION_VARIANCE import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.STRING import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.commaSeparated +import org.jetbrains.kotlin.diagnostics.rendering.LanguageFeatureMessageRenderer import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.AMBIGUOUS_CALLS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.COLLECTION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.DECLARATION_NAME @@ -165,15 +165,6 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_FUNCTION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_LATEINIT_PROPERTY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_PRIVATE_DECLARATION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_PROPERTY_INITIALIZER -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_MARKER_WITH_WRONG_RETENTION -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_MARKER_WITH_WRONG_TARGET -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_USAGE -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_USAGE_ERROR -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_CAN_ONLY_BE_USED_AS_ANNOTATION -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_IS_NOT_ENABLED -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_OVERRIDE -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_OVERRIDE_ERROR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPLICIT_BACKING_FIELD_IN_ABSTRACT_PROPERTY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPLICIT_BACKING_FIELD_IN_EXTENSION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPLICIT_BACKING_FIELD_IN_INTERFACE @@ -304,6 +295,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_VARARG_SPREAD import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOTHING_TO_INLINE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOTHING_TO_OVERRIDE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_AN_ANNOTATION_CLASS +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_FUNCTION_LABEL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_LOOP_LABEL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_SUPERTYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE @@ -326,6 +318,20 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NULLABLE_TYPE_IN_ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NULLABLE_TYPE_OF_ANNOTATION_MEMBER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ONLY_ONE_CLASS_BOUND_ALLOWED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPERATOR_RENAMED_ON_IMPORT +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_ARGUMENT_IS_NOT_MARKER +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_CAN_ONLY_BE_USED_AS_ANNOTATION +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_IS_NOT_ENABLED +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_MARKER_ON_OVERRIDE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_MARKER_ON_OVERRIDE_WARNING +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_MARKER_ON_WRONG_TARGET +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_MARKER_WITH_WRONG_RETENTION +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_MARKER_WITH_WRONG_TARGET +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_OVERRIDE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_OVERRIDE_ERROR +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_USAGE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_USAGE_ERROR +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_WITHOUT_ARGUMENTS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OTHER_ERROR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OUTER_CLASS_ARGUMENTS_REQUIRED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY @@ -475,11 +481,6 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_ELVIS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_ELVIS_RIGHT_IS_NULL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_IS_CHECK import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_VARARG_ON_PARAMETER -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_ARGUMENT_IS_NOT_MARKER -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_MARKER_ON_OVERRIDE -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_MARKER_ON_OVERRIDE_WARNING -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_MARKER_ON_WRONG_TARGET -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_WITHOUT_ARGUMENTS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_CANNOT_BE_CLONEABLE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAL_OR_VAR_ON_CATCH_PARAMETER @@ -1619,6 +1620,7 @@ class FirDefaultErrorMessages { // Returns map.put(RETURN_NOT_ALLOWED, "'return' is not allowed here") + map.put(NOT_A_FUNCTION_LABEL, "Target label does not denote a function") map.put( RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY, "Returns are not allowed for functions with expression body. Use block body in '{...}'" diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index b91c8d66667..b50fc4de1ba 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -366,6 +366,7 @@ private fun ConeSimpleDiagnostic.getFactory(source: FirSourceElement): FirDiagno return when (kind) { DiagnosticKind.Syntax -> FirErrors.SYNTAX DiagnosticKind.ReturnNotAllowed -> FirErrors.RETURN_NOT_ALLOWED + DiagnosticKind.NotAFunctionLabel -> FirErrors.NOT_A_FUNCTION_LABEL DiagnosticKind.UnresolvedLabel -> FirErrors.UNRESOLVED_LABEL DiagnosticKind.NoThis -> FirErrors.NO_THIS DiagnosticKind.IllegalConstExpression -> FirErrors.ILLEGAL_CONST_EXPRESSION diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt index 0d36d052c93..9488213df89 100644 --- a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt +++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt @@ -183,7 +183,11 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte } } target = FirFunctionTarget(labelName, false).apply { - bindToErrorFunction("Cannot bind label $labelName to a function", DiagnosticKind.UnresolvedLabel) + if (context.firLabels.any { it.name == labelName } || context.firLoopTargets.any { it.labelName == labelName }) { + bindToErrorFunction("Label $labelName does not target a function", DiagnosticKind.NotAFunctionLabel) + } else { + bindToErrorFunction("Cannot bind label $labelName to a function", DiagnosticKind.UnresolvedLabel) + } } } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt index 65e7845aad4..f48161d2c9d 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt @@ -32,6 +32,7 @@ enum class DiagnosticKind { ReturnNotAllowed, UnresolvedLabel, + NotAFunctionLabel, NoThis, IllegalConstExpression, IllegalSelector, diff --git a/compiler/testData/diagnostics/tests/controlStructures/notAFunctionLabel_after.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/notAFunctionLabel_after.fir.kt index 6b7fd939a6b..564df9e4a15 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/notAFunctionLabel_after.fir.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/notAFunctionLabel_after.fir.kt @@ -31,7 +31,7 @@ fun testAnnotatedLambdaLabel() = fun testLambdaMultipleLabels1() = lambda1@ lambda2@ { - return@lambda1 + return@lambda1 } fun testLambdaMultipleLabels2() = @@ -46,7 +46,7 @@ fun testAnonymousFunctionLabel() = fun testLoopLabelInReturn(xs: List) { L@ for (x in xs) { - if (x > 0) return@L + if (x > 0) return@L } } diff --git a/compiler/testData/diagnostics/tests/controlStructures/notAFunctionLabel_before.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/notAFunctionLabel_before.fir.kt index bd3a1979a04..c609e4b9922 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/notAFunctionLabel_before.fir.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/notAFunctionLabel_before.fir.kt @@ -31,7 +31,7 @@ fun testAnnotatedLambdaLabel() = fun testLambdaMultipleLabels1() = lambda1@ lambda2@ { - return@lambda1 + return@lambda1 } fun testLambdaMultipleLabels2() = @@ -46,7 +46,7 @@ fun testAnonymousFunctionLabel() = fun testLoopLabelInReturn(xs: List) { L@ for (x in xs) { - if (x > 0) return@L + if (x > 0) return@L } }