[FIR] Support redeclaration diagnostics for different levels of destructured parameters
#KT-59875 #KT-59898
This commit is contained in:
committed by
Space Team
parent
6161f44d91
commit
20f74c22d7
+15
@@ -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
|
||||
|
||||
+13
-1
@@ -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,
|
||||
|
||||
+9
-1
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -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>() }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user