From 768ddea18ffa41bf63e6217fab682fd575de1a3f Mon Sep 17 00:00:00 2001 From: Tianyu Geng Date: Tue, 22 Jun 2021 15:35:15 -0700 Subject: [PATCH] FIR checker: ILLEGAL_DECLARATION_IN_WHEN_SUBJECT --- .../diagnostics/FirDiagnosticsList.kt | 3 ++ .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../checkers/CommonExpressionCheckers.kt | 1 + .../expression/FirWhenSubjectChecker.kt | 37 +++++++++++++++++++ ...edVariableDeclarationsInWhenSubject.fir.kt | 6 +-- .../diagnostics/KtFirDataClassConverters.kt | 9 ++++- .../api/fir/diagnostics/KtFirDiagnostics.kt | 5 +++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 12 +++++- 8 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirWhenSubjectChecker.kt 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 e1343173f38..5a17c9f4a61 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 @@ -873,6 +873,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { } val INVALID_IF_AS_EXPRESSION by error(PositioningStrategy.IF_EXPRESSION) val ELSE_MISPLACED_IN_WHEN by error(PositioningStrategy.ELSE_ENTRY) + val ILLEGAL_DECLARATION_IN_WHEN_SUBJECT by error { + parameter("illegalReason") + } } val CONTEXT_TRACKING by object : DiagnosticGroup("Context tracking") { 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 0b2efc3cc5c..b82971f30a0 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 @@ -480,6 +480,7 @@ object FirErrors { val NO_ELSE_IN_WHEN by error1>(SourceElementPositioningStrategies.WHEN_EXPRESSION) val INVALID_IF_AS_EXPRESSION by error0(SourceElementPositioningStrategies.IF_EXPRESSION) val ELSE_MISPLACED_IN_WHEN by error0(SourceElementPositioningStrategies.ELSE_ENTRY) + val ILLEGAL_DECLARATION_IN_WHEN_SUBJECT by error1() // Context tracking val TYPE_PARAMETER_IS_NOT_AN_EXPRESSION by error1() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt index bb7334c0c7a..6317702ab15 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt @@ -61,6 +61,7 @@ object CommonExpressionCheckers : ExpressionCheckers() { get() = setOf( FirExhaustiveWhenChecker, FirWhenConditionChecker, + FirWhenSubjectChecker, ) override val loopExpressionCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirWhenSubjectChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirWhenSubjectChecker.kt new file mode 100644 index 00000000000..ae54cf2ee44 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirWhenSubjectChecker.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2010-2021 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.KtNodeTypes +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +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.analysis.getChild +import org.jetbrains.kotlin.fir.expressions.FirWhenExpression +import org.jetbrains.kotlin.lexer.KtTokens + +object FirWhenSubjectChecker : FirWhenExpressionChecker() { + override fun check(expression: FirWhenExpression, context: CheckerContext, reporter: DiagnosticReporter) { + val subject = expression.subject + val subjectVariable = expression.subjectVariable + val source = (subjectVariable ?: subject)?.source ?: return + when { + subject?.source?.elementType == KtNodeTypes.DESTRUCTURING_DECLARATION -> { + reporter.reportOn(source, FirErrors.ILLEGAL_DECLARATION_IN_WHEN_SUBJECT, "destructuring declaration", context) + } + subjectVariable?.source?.getChild(KtTokens.VAR_KEYWORD) != null -> { + reporter.reportOn(source, FirErrors.ILLEGAL_DECLARATION_IN_WHEN_SUBJECT, "var", context) + } + subjectVariable?.source?.getChild(KtNodeTypes.PROPERTY_DELEGATE) != null -> { + reporter.reportOn(source, FirErrors.ILLEGAL_DECLARATION_IN_WHEN_SUBJECT, "delegated property", context) + } + subjectVariable != null && subjectVariable.initializer == null -> { + reporter.reportOn(source, FirErrors.ILLEGAL_DECLARATION_IN_WHEN_SUBJECT, "variable without initializer", context) + } + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/when/withSubjectVariable/unsupportedVariableDeclarationsInWhenSubject.fir.kt b/compiler/testData/diagnostics/tests/when/withSubjectVariable/unsupportedVariableDeclarationsInWhenSubject.fir.kt index e620befb326..514c5237438 100644 --- a/compiler/testData/diagnostics/tests/when/withSubjectVariable/unsupportedVariableDeclarationsInWhenSubject.fir.kt +++ b/compiler/testData/diagnostics/tests/when/withSubjectVariable/unsupportedVariableDeclarationsInWhenSubject.fir.kt @@ -11,18 +11,18 @@ fun testSimpleValInWhenSubject() { } fun testValWithoutInitializerWhenSubject() { - when (val y: Any) { + when (val y: Any) { is String -> y.length } } fun testVarInWhenSubject() { - when (var y = foo()) { + when (var y = foo()) { is String -> y.length } } fun testDelegatedValInWhenSubject() { - when (val y by lazy { 42 }) { + when (val y by lazy { 42 }) { } } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index 4d4a71a6d03..4d9da975684 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -2379,7 +2379,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert } add(FirErrors.EXPECTED_CONDITION) { firDiagnostic -> ExpectedConditionImpl( - firDiagnostic as FirPsiDiagnostic<*>, + firDiagnostic as FirPsiDiagnostic, token, ) } @@ -2404,6 +2404,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.ILLEGAL_DECLARATION_IN_WHEN_SUBJECT) { firDiagnostic -> + IllegalDeclarationInWhenSubjectImpl( + firDiagnostic.a, + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION) { firDiagnostic -> TypeParameterIsNotAnExpressionImpl( firSymbolBuilder.classifierBuilder.buildTypeParameterSymbol(firDiagnostic.a.fir), diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index b6b9cab418a..51e4df33a89 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -1693,6 +1693,11 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = ElseMisplacedInWhen::class } + abstract class IllegalDeclarationInWhenSubject : KtFirDiagnostic() { + override val diagnosticClass get() = IllegalDeclarationInWhenSubject::class + abstract val illegalReason: String + } + abstract class TypeParameterIsNotAnExpression : KtFirDiagnostic() { override val diagnosticClass get() = TypeParameterIsNotAnExpression::class abstract val typeParameter: KtTypeParameterSymbol diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index dff5807e5fe..f6188d23da5 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -2710,10 +2710,10 @@ internal class UselessIsCheckImpl( } internal class ExpectedConditionImpl( - firDiagnostic: FirPsiDiagnostic<*>, + firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken, ) : KtFirDiagnostic.ExpectedCondition(), KtAbstractFirDiagnostic { - override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } internal class NoElseInWhenImpl( @@ -2738,6 +2738,14 @@ internal class ElseMisplacedInWhenImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class IllegalDeclarationInWhenSubjectImpl( + override val illegalReason: String, + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.IllegalDeclarationInWhenSubject(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class TypeParameterIsNotAnExpressionImpl( override val typeParameter: KtTypeParameterSymbol, firDiagnostic: FirPsiDiagnostic,