[FIR] Support redeclaration diagnostics for different levels of destructured parameters

#KT-59875 #KT-59898
This commit is contained in:
Evgeniy.Zhelenskiy
2023-12-15 21:00:01 +00:00
committed by Space Team
parent 6161f44d91
commit 20f74c22d7
4 changed files with 39 additions and 4 deletions
@@ -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<FirElement>, context: CheckerContext, reporter: DiagnosticReporter) {
if (elements.size <= 1) return
@@ -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<FirVariable> {
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,
@@ -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)
}
@@ -11,12 +11,12 @@ fun bar() {
b checkType { <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><String>() }
}
foo { (a, b), a ->
foo { (<!REDECLARATION!>a<!>, b), <!REDECLARATION!>a<!> ->
a checkType { _<Int>() }
b checkType { _<String>() }
}
foo { a, (a, b) ->
foo { <!REDECLARATION!>a<!>, (<!REDECLARATION!>a<!>, b) ->
a checkType { <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><Int>() }
b checkType { <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><String>() }
}