From 20f74c22d721750b908d1deb63f3efad466c66f6 Mon Sep 17 00:00:00 2001 From: "Evgeniy.Zhelenskiy" Date: Fri, 15 Dec 2023 21:00:01 +0000 Subject: [PATCH] [FIR] Support redeclaration diagnostics for different levels of destructured parameters #KT-59875 #KT-59898 --- .../fir/analysis/checkers/FirConflictsHelpers.kt | 15 +++++++++++++++ .../declaration/FirConflictsDeclarationChecker.kt | 14 +++++++++++++- .../expression/FirConflictsExpressionChecker.kt | 10 +++++++++- .../destructuringInLambdas/redeclaration.fir.kt | 4 ++-- 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt index 2f82d76efdf..aa9558aa02a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt @@ -16,11 +16,15 @@ import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirNameConflictsTr import org.jetbrains.kotlin.fir.analysis.checkers.declaration.isEffectivelyFinal import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.FirValueParameter import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl.Companion.DEFAULT_STATUS_FOR_STATUSLESS_DECLARATIONS import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl.Companion.DEFAULT_STATUS_FOR_SUSPEND_MAIN_FUNCTION import org.jetbrains.kotlin.fir.declarations.impl.modifiersRepresentation import org.jetbrains.kotlin.fir.declarations.utils.nameOrSpecialName import org.jetbrains.kotlin.fir.expressions.FirBlock +import org.jetbrains.kotlin.fir.expressions.FirComponentCall +import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression +import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.outerType import org.jetbrains.kotlin.fir.resolve.providers.firProvider @@ -514,6 +518,17 @@ private fun FirDeclarationCollector<*>.areNonConflictingCallables( return session.declarationOverloadabilityHelper.isOverloadable(declaration, conflicting) } +@OptIn(SymbolInternals::class) +internal fun FirVariable.getDestructuredParameter(): FirValueParameter? { + val initializer = initializer + if (initializer !is FirComponentCall) return null + if (initializer.source?.kind !is KtFakeSourceElementKind.DesugaredComponentFunctionCall) return null + val receiver = initializer.dispatchReceiver ?: initializer.extensionReceiver ?: return null + if (receiver !is FirPropertyAccessExpression) return null + val calleeReference = receiver.calleeReference as? FirResolvedNamedReference ?: return null + return calleeReference.resolvedSymbol.fir as? FirValueParameter +} + /** Checks for redeclarations of value and type parameters, and local variables. */ fun checkForLocalRedeclarations(elements: List, context: CheckerContext, reporter: DiagnosticReporter) { if (elements.size <= 1) return diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictsDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictsDeclarationChecker.kt index a98202767d2..037242eb00f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictsDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictsDeclarationChecker.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.typeAliasForConstructor import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.utils.SmartSet object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() { @@ -41,7 +42,8 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() { else -> { if (declaration.source?.kind !is KtFakeSourceElementKind && declaration is FirTypeParameterRefsOwner) { if (declaration is FirFunction) { - checkForLocalRedeclarations(declaration.valueParameters, context, reporter) + val destructuredParameters = getDestructuredParameters(declaration) + checkForLocalRedeclarations(destructuredParameters, context, reporter) } checkForLocalRedeclarations(declaration.typeParameters, context, reporter) } @@ -49,6 +51,16 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() { } } + private fun getDestructuredParameters(function: FirFunction): List { + if (function.valueParameters.none { it.name == SpecialNames.DESTRUCT }) return function.valueParameters + val destructuredParametersBoxes = function.valueParameters.filterTo(mutableSetOf()) { it.name == SpecialNames.DESTRUCT } + + return function.body?.statements.orEmpty().mapNotNullTo(function.valueParameters.toMutableList()) { + val destructuredParameter = (it as? FirVariable)?.getDestructuredParameter() ?: return@mapNotNullTo null + if (destructuredParameter in destructuredParametersBoxes) it else null + } + } + private fun reportConflicts( reporter: DiagnosticReporter, context: CheckerContext, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirConflictsExpressionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirConflictsExpressionChecker.kt index e54f953d4f7..0075a821346 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirConflictsExpressionChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirConflictsExpressionChecker.kt @@ -10,12 +10,20 @@ import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.checkers.checkForLocalRedeclarations import org.jetbrains.kotlin.fir.analysis.checkers.collectConflictingLocalFunctionsFrom import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.getDestructuredParameter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.declarations.FirVariable import org.jetbrains.kotlin.fir.expressions.FirBlock +import org.jetbrains.kotlin.fir.expressions.FirStatement object FirConflictsExpressionChecker : FirBlockChecker() { + private fun FirStatement.isDestructuredParameter() = this is FirVariable && getDestructuredParameter() != null + override fun check(expression: FirBlock, context: CheckerContext, reporter: DiagnosticReporter) { - checkForLocalRedeclarations(expression.statements, context, reporter) + val elements = + if (expression.statements.none { it.isDestructuredParameter() }) expression.statements // optimization + else expression.statements.filterNot { it.isDestructuredParameter() } + checkForLocalRedeclarations(elements, context, reporter) checkForLocalConflictingFunctions(expression, context, reporter) } diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/redeclaration.fir.kt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/redeclaration.fir.kt index 1bfee1c3e1e..ded979500a3 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/redeclaration.fir.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/redeclaration.fir.kt @@ -11,12 +11,12 @@ fun bar() { b checkType { _() } } - foo { (a, b), a -> + foo { (a, b), a -> a checkType { _() } b checkType { _() } } - foo { a, (a, b) -> + foo { a, (a, b) -> a checkType { _() } b checkType { _() } }