From 065e8521995c04c2089bd3b2d52259113887b23d Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 17 Jun 2022 18:27:04 +0200 Subject: [PATCH] FIR: support more precise diagnostics about parameter names #KT-52762 Fixed --- .../diagnostics/KtFirDataClassConverters.kt | 6 ++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 4 + .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 5 + .../NamedParameterInConcurrentMap.fir.txt | 2 +- .../problems/NamedParameterInConcurrentMap.kt | 6 +- .../diagnostics/FirDiagnosticsList.kt | 1 + .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../diagnostics/FirErrorsDefaultMessages.kt | 6 +- .../coneDiagnosticToFirDiagnostic.kt | 3 + .../kotlin/fir/resolve/ResolveUtils.kt | 30 ++++-- .../calls/FirArgumentsToParametersMapper.kt | 99 ++++++++++++++----- .../fir/resolve/calls/ResolutionDiagnostic.kt | 6 ++ .../ambiguousNamedArguments1.fir.kt | 16 +-- .../ambiguousNamedArguments2.fir.kt | 14 +-- ...mbiguousNamedArgumentsWithGenerics1.fir.kt | 4 +- ...mbiguousNamedArgumentsWithGenerics2.fir.kt | 4 +- ...mbiguousNamedArgumentsWithGenerics3.fir.kt | 2 +- .../namedArgumentsInOverrides.fir.kt | 2 +- 18 files changed, 154 insertions(+), 57 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 b19b0c9496d..5c9569831ec 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 @@ -1482,6 +1482,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.NAME_FOR_AMBIGUOUS_PARAMETER) { firDiagnostic -> + NameForAmbiguousParameterImpl( + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.ASSIGNMENT_TYPE_MISMATCH) { firDiagnostic -> AssignmentTypeMismatchImpl( firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a), 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 0ff235f1068..ce18175d8d6 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 @@ -1063,6 +1063,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val name: String } + abstract class NameForAmbiguousParameter : KtFirDiagnostic() { + override val diagnosticClass get() = NameForAmbiguousParameter::class + } + abstract class AssignmentTypeMismatch : KtFirDiagnostic() { override val diagnosticClass get() = AssignmentTypeMismatch::class abstract val expectedType: KtType 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 97163910eba..8a3e8c146ad 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 @@ -1274,6 +1274,11 @@ internal class NamedParameterNotFoundImpl( override val token: KtLifetimeToken, ) : KtFirDiagnostic.NamedParameterNotFound(), KtAbstractFirDiagnostic +internal class NameForAmbiguousParameterImpl( + override val firDiagnostic: KtPsiDiagnostic, + override val token: KtLifetimeToken, +) : KtFirDiagnostic.NameForAmbiguousParameter(), KtAbstractFirDiagnostic + internal class AssignmentTypeMismatchImpl( override val expectedType: KtType, override val actualType: KtType, diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/NamedParameterInConcurrentMap.fir.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/NamedParameterInConcurrentMap.fir.txt index cec5aa4bdac..c2d1dd0917d 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/NamedParameterInConcurrentMap.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/NamedParameterInConcurrentMap.fir.txt @@ -1,5 +1,5 @@ FILE: NamedParameterInConcurrentMap.kt public final fun main(): R|kotlin/Unit| { lval map: R|java/util/concurrent/ConcurrentHashMap| = R|java/util/concurrent/ConcurrentHashMap.ConcurrentHashMap|() - R|/map|.#(key = String(key), value = String(value)) + R|/map|.R|SubstitutionOverride|(key = String(key), value = String(value)) } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/NamedParameterInConcurrentMap.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/NamedParameterInConcurrentMap.kt index 6fb226d5daf..c9c9683f08c 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/NamedParameterInConcurrentMap.kt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/problems/NamedParameterInConcurrentMap.kt @@ -5,7 +5,7 @@ import java.util.concurrent.ConcurrentHashMap fun main() { val map = ConcurrentHashMap() map.put( - key = "key", - value = "value" - ) + key = "key", + value = "value" + ) } 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 bef39db4de9..a4425908b2f 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 @@ -482,6 +482,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val NAMED_PARAMETER_NOT_FOUND by error(PositioningStrategy.NAME_OF_NAMED_ARGUMENT) { parameter("name") } + val NAME_FOR_AMBIGUOUS_PARAMETER by error(PositioningStrategy.NAME_OF_NAMED_ARGUMENT) val ASSIGNMENT_TYPE_MISMATCH by error { parameter("expectedType") 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 b1ce2b54f42..a221de19837 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 @@ -338,6 +338,7 @@ object FirErrors { val TOO_MANY_ARGUMENTS by error1>() val NO_VALUE_FOR_PARAMETER by error1(SourceElementPositioningStrategies.VALUE_ARGUMENTS) val NAMED_PARAMETER_NOT_FOUND by error1(SourceElementPositioningStrategies.NAME_OF_NAMED_ARGUMENT) + val NAME_FOR_AMBIGUOUS_PARAMETER by error0(SourceElementPositioningStrategies.NAME_OF_NAMED_ARGUMENT) val ASSIGNMENT_TYPE_MISMATCH by error3() val RESULT_TYPE_MISMATCH by error2() val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index f1fbcc5b092..5d63b7ce211 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -297,13 +297,14 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISPLACED_TYPE_PA import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_STDLIB_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_VAL_ON_ANNOTATION_PARAMETER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MULTIPLE_VARARG_PARAMETERS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NAMED_ARGUMENTS_NOT_ALLOWED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NAMED_PARAMETER_NOT_FOUND +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NAME_FOR_AMBIGUOUS_PARAMETER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NESTED_CLASS_NOT_ALLOWED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NEWER_VERSION_IN_SINCE_KOTLIN @@ -578,6 +579,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_MODIFIER_TA import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_SETTER_PARAMETER_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_SETTER_RETURN_TYPE +import org.jetbrains.kotlin.psi.KtReferenceExpression @Suppress("unused") object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { @@ -937,6 +939,8 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { map.put(ARGUMENT_PASSED_TWICE, "An argument is already passed for this parameter") map.put(NO_VALUE_FOR_PARAMETER, "No value passed for parameter ''{0}''", DECLARATION_NAME) map.put(NAMED_PARAMETER_NOT_FOUND, "Cannot find a parameter with this name: {0}", TO_STRING) + map.put(NAME_FOR_AMBIGUOUS_PARAMETER, "Named argument is not allowed for a parameter with an ambiguous name") + map.put(MANY_LAMBDA_EXPRESSION_ARGUMENTS, "Only one lambda expression is allowed outside a parenthesized argument list") map.put(NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, "Not enough information to infer type variable {0}", STRING) map.put(SPREAD_OF_NULLABLE, "The spread operator (*foo) may not be applied to an argument of nullable type") 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 69c5f30d60e..78ac4ed364c 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 @@ -235,6 +235,9 @@ private fun mapInapplicableCandidateError( rootCause.argument.source ?: source, rootCause.argument.name.asString() ) + is NameForAmbiguousParameter -> FirErrors.NAME_FOR_AMBIGUOUS_PARAMETER.createOn( + rootCause.argument.source ?: source + ) is UnsafeCall -> mapUnsafeCallError(diagnostic.candidate, rootCause, source, qualifiedAccessSource) is ManyLambdaExpressionArguments -> FirErrors.MANY_LAMBDA_EXPRESSION_ARGUMENTS.createOn(rootCause.argument.source ?: source) is InfixCallOfNonInfixFunction -> FirErrors.INFIX_MODIFIER_REQUIRED.createOn(source, rootCause.function) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index 2f6f9e081ed..0a565914b3c 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -34,8 +34,11 @@ import org.jetbrains.kotlin.fir.resolve.dfa.PropertyStability import org.jetbrains.kotlin.fir.resolve.diagnostics.* import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType +import org.jetbrains.kotlin.fir.scopes.FirTypeScope +import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData import org.jetbrains.kotlin.fir.scopes.impl.importedFromObjectData +import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.ensureResolved import org.jetbrains.kotlin.fir.symbols.impl.* @@ -493,7 +496,12 @@ fun FirCallableDeclaration.getContainingClass(session: FirSession): FirRegularCl session.symbolProvider.getSymbolByLookupTag(lookupTag)?.fir as? FirRegularClass } -fun FirFunction.getAsForbiddenNamedArgumentsTarget(session: FirSession): ForbiddenNamedArgumentsTarget? { +fun FirFunction.getAsForbiddenNamedArgumentsTarget( + session: FirSession, + // NB: with originScope given this function will try to find overridden declaration with allowed parameter names + // for intersection/substitution overrides + originScope: FirTypeScope? = null +): ForbiddenNamedArgumentsTarget? { if (this is FirConstructor && this.isPrimary) { this.getContainingClass(session)?.let { containingClass -> if (containingClass.classKind == ClassKind.ANNOTATION_CLASS) { @@ -506,15 +514,21 @@ fun FirFunction.getAsForbiddenNamedArgumentsTarget(session: FirSession): Forbidd FirDeclarationOrigin.Source, FirDeclarationOrigin.Precompiled, FirDeclarationOrigin.Library -> null FirDeclarationOrigin.Delegated -> delegatedWrapperData?.wrapped?.getAsForbiddenNamedArgumentsTarget(session) FirDeclarationOrigin.ImportedFromObject -> importedFromObjectData?.original?.getAsForbiddenNamedArgumentsTarget(session) - // For intersection overrides, the logic in - // org.jetbrains.kotlin.fir.scopes.impl.FirTypeIntersectionScope#selectMostSpecificMember picks the most specific one and store - // it in originalForIntersectionOverrideAttr. This follows from FE1.0 behavior which selects the most specific function - // (org.jetbrains.kotlin.resolve.OverridingUtil#selectMostSpecificMember), from which the `hasStableParameterNames` status is - // copied. - FirDeclarationOrigin.IntersectionOverride -> originalForIntersectionOverrideAttr?.getAsForbiddenNamedArgumentsTarget(session) is FirDeclarationOrigin.Java, FirDeclarationOrigin.Enhancement -> ForbiddenNamedArgumentsTarget.NON_KOTLIN_FUNCTION FirDeclarationOrigin.SamConstructor -> null - FirDeclarationOrigin.SubstitutionOverride -> originalForSubstitutionOverrideAttr?.getAsForbiddenNamedArgumentsTarget(session) + FirDeclarationOrigin.IntersectionOverride, FirDeclarationOrigin.SubstitutionOverride -> { + var result: ForbiddenNamedArgumentsTarget? = + originalIfFakeOverride()?.getAsForbiddenNamedArgumentsTarget(session) ?: return null + originScope?.processOverriddenFunctions(symbol as FirNamedFunctionSymbol) { + if (it.fir.getAsForbiddenNamedArgumentsTarget(session) == null) { + result = null + ProcessorAction.STOP + } else { + ProcessorAction.NEXT + } + } + result + } // referenced function of a Kotlin function type FirDeclarationOrigin.BuiltIns -> { if (dispatchReceiverClassOrNull()?.isBuiltinFunctionalType() == true) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirArgumentsToParametersMapper.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirArgumentsToParametersMapper.kt index 50ecdd8a181..1191fee52c4 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirArgumentsToParametersMapper.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirArgumentsToParametersMapper.kt @@ -13,10 +13,17 @@ import org.jetbrains.kotlin.fir.declarations.FirValueParameter import org.jetbrains.kotlin.fir.declarations.utils.isOperator import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.builder.buildNamedArgumentExpression +import org.jetbrains.kotlin.fir.isIntersectionOverride +import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents import org.jetbrains.kotlin.fir.resolve.defaultParameterResolver import org.jetbrains.kotlin.fir.resolve.getAsForbiddenNamedArgumentsTarget import org.jetbrains.kotlin.fir.scopes.FirScope +import org.jetbrains.kotlin.fir.scopes.FirTypeScope +import org.jetbrains.kotlin.fir.scopes.ProcessorAction +import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget import org.jetbrains.kotlin.util.OperatorNameConventions @@ -128,7 +135,7 @@ private class FirCallArgumentsProcessor( val result: LinkedHashMap = LinkedHashMap(function.valueParameters.size) val forbiddenNamedArgumentsTarget: ForbiddenNamedArgumentsTarget? by lazy { - function.getAsForbiddenNamedArgumentsTarget(useSiteSession) + function.getAsForbiddenNamedArgumentsTarget(useSiteSession, originScope as? FirTypeScope) } private enum class State { @@ -322,29 +329,75 @@ private class FirCallArgumentsProcessor( } private fun findParameterByName(argument: FirNamedArgumentExpression): FirValueParameter? { - val parameter = getParameterByName(argument.name) + var parameter = getParameterByName(argument.name) - // TODO -// if (descriptor is CallableMemberDescriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { -// if (parameter == null) { -// for (valueParameter in descriptor.valueParameters) { -// val matchedParameter = valueParameter.overriddenDescriptors.firstOrNull { -// it.containingDeclaration.hasStableParameterNames() && it.name == name -// } -// if (matchedParameter != null) { -// addDiagnostic(NamedArgumentReference(argument, valueParameter)) -// addDiagnostic(NameForAmbiguousParameter(argument, valueParameter, matchedParameter)) -// return valueParameter -// } -// } -// } else { -// parameter.getOverriddenParameterWithOtherName()?.let { -// addDiagnostic(NameForAmbiguousParameter(argument, parameter, it)) -// } -// } -// } -// - if (parameter == null) addDiagnostic(NameNotFound(argument, function)) + val symbol = function.symbol as? FirNamedFunctionSymbol + var matchedIndex = -1 + + // Note: should be called when parameter != null && matchedIndex != -1 + fun List.findAndReportValueParameterWithDifferentName(): ProcessorAction { + val someParameter = getOrNull(matchedIndex)?.fir + val someName = someParameter?.name + if (someName != null && someName != argument.name) { + addDiagnostic( + NameForAmbiguousParameter(argument, matchedParameter = parameter!!, someParameter) + ) + return ProcessorAction.STOP + } + return ProcessorAction.NEXT + } + + if (parameter == null) { + if (symbol != null && function.isSubstitutionOrIntersectionOverride) { + var allowedParameters: List? = null + (originScope as? FirTypeScope)?.processOverriddenFunctions(symbol) { + if (it.fir.getAsForbiddenNamedArgumentsTarget(useSiteSession) != null) { + return@processOverriddenFunctions ProcessorAction.NEXT + } + val someParameterSymbols = it.valueParameterSymbols + if (matchedIndex != -1) { + someParameterSymbols.findAndReportValueParameterWithDifferentName() + } else { + matchedIndex = someParameterSymbols.indexOfFirst { originalParameter -> + originalParameter.name == argument.name + } + if (matchedIndex != -1) { + parameter = parameters[matchedIndex] + val someParameter = allowedParameters?.getOrNull(matchedIndex)?.fir + if (someParameter != null) { + addDiagnostic( + NameForAmbiguousParameter(argument, matchedParameter = parameter!!, anotherParameter = someParameter) + ) + ProcessorAction.STOP + } else { + ProcessorAction.NEXT + } + } else { + allowedParameters = someParameterSymbols + ProcessorAction.NEXT + } + } + } + } + if (parameter == null) { + addDiagnostic(NameNotFound(argument, function)) + } + } else { + // TODO: should we check also substitution overrides? Performance! + if (symbol != null && function.isIntersectionOverride) { + matchedIndex = parameters.indexOfFirst { originalParameter -> + originalParameter.name == argument.name + } + if (matchedIndex != -1) { + (originScope as? FirTypeScope)?.processOverriddenFunctions(symbol) { + if (it.fir.getAsForbiddenNamedArgumentsTarget(useSiteSession) != null) { + return@processOverriddenFunctions ProcessorAction.NEXT + } + it.valueParameterSymbols.findAndReportValueParameterWithDifferentName() + } + } + } + } return parameter } diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt index c074029d8bc..f8586f96402 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt @@ -70,6 +70,12 @@ class NameNotFound( val function: FirFunction ) : ResolutionDiagnostic(INAPPLICABLE_ARGUMENTS_MAPPING_ERROR) +class NameForAmbiguousParameter( + val argument: FirNamedArgumentExpression, + val matchedParameter: FirValueParameter, + val anotherParameter: FirValueParameter +) : ResolutionDiagnostic(INAPPLICABLE_ARGUMENTS_MAPPING_ERROR) + object InapplicableCandidate : ResolutionDiagnostic(INAPPLICABLE) object HiddenCandidate : ResolutionDiagnostic(HIDDEN) diff --git a/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArguments1.fir.kt b/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArguments1.fir.kt index 5c61c7e11f1..13525c81f2d 100644 --- a/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArguments1.fir.kt +++ b/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArguments1.fir.kt @@ -10,18 +10,18 @@ interface C : A, B interface D : B, A fun foo(x : C, y : D){ - x.foo(x = 0) - x.foo(y = 0) - y.foo(x = 0) - y.foo(y = 0) + x.foo(x = 0) + x.foo(y = 0) + y.foo(x = 0) + y.foo(y = 0) } abstract class C1 : A, B abstract class D1 : A, B fun bar(x : C1, y : D1){ - x.foo(x = 0) - x.foo(y = 0) - y.foo(x = 0) - y.foo(y = 0) + x.foo(x = 0) + x.foo(y = 0) + y.foo(x = 0) + y.foo(y = 0) } diff --git a/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArguments2.fir.kt b/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArguments2.fir.kt index 08ce689b611..52195cce940 100644 --- a/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArguments2.fir.kt +++ b/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArguments2.fir.kt @@ -14,11 +14,11 @@ interface C : A, B { // Warning here, this is correct } fun test(c: C) { - c.foo(b1 = 1, b2 = 1.0) - c.foo(a1 = 1, b2 = 1.0) - c.foo(a1 = 1, a2 = 1.0) - c.foo(a1 = 1, a2 = 1.0) - c.bar(a1 = 1, a2 = 1.0, b3= "") - c.baz(a1 = 1, b2 = 1.0, a3 = "", b4 = 2, a5 = "") - c.baz(a1 = 1, a2 = 1.0, a3 = "", b4 = 2, a5 = "") + c.foo(b1 = 1, b2 = 1.0) + c.foo(a1 = 1, b2 = 1.0) + c.foo(a1 = 1, a2 = 1.0) + c.foo(a1 = 1, a2 = 1.0) + c.bar(a1 = 1, a2 = 1.0, b3= "") + c.baz(a1 = 1, b2 = 1.0, a3 = "", b4 = 2, a5 = "") + c.baz(a1 = 1, a2 = 1.0, a3 = "", b4 = 2, a5 = "") } diff --git a/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArgumentsWithGenerics1.fir.kt b/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArgumentsWithGenerics1.fir.kt index f8518920075..d28c5eb93fc 100644 --- a/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArgumentsWithGenerics1.fir.kt +++ b/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArgumentsWithGenerics1.fir.kt @@ -10,6 +10,6 @@ interface C : A, B { // Warning here, this is correct } fun test(c: C) { - c.foo(a = 1) - c.foo(b = 1) + c.foo(a = 1) + c.foo(b = 1) } diff --git a/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArgumentsWithGenerics2.fir.kt b/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArgumentsWithGenerics2.fir.kt index bb54a33c595..3fe87a19ae7 100644 --- a/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArgumentsWithGenerics2.fir.kt +++ b/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArgumentsWithGenerics2.fir.kt @@ -10,6 +10,6 @@ interface C : A, B { // Warning here, this is correct } fun test(c: C) { - c.foo(a = 1) - c.foo(b = 1) + c.foo(a = 1) + c.foo(b = 1) } diff --git a/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArgumentsWithGenerics3.fir.kt b/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArgumentsWithGenerics3.fir.kt index 966c59ad0c1..6741520e6b2 100644 --- a/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArgumentsWithGenerics3.fir.kt +++ b/compiler/testData/diagnostics/tests/namedArguments/ambiguousNamedArgumentsWithGenerics3.fir.kt @@ -11,5 +11,5 @@ interface C : A, B { // Warning here, this is correct fun test(c: C) { c.foo(a = 1) - c.foo(b = 1) + c.foo(b = 1) } diff --git a/compiler/testData/diagnostics/tests/namedArguments/namedArgumentsInOverrides.fir.kt b/compiler/testData/diagnostics/tests/namedArguments/namedArgumentsInOverrides.fir.kt index aff65f1c5d8..3b41cc7c6fe 100644 --- a/compiler/testData/diagnostics/tests/namedArguments/namedArgumentsInOverrides.fir.kt +++ b/compiler/testData/diagnostics/tests/namedArguments/namedArgumentsInOverrides.fir.kt @@ -18,5 +18,5 @@ fun test1(d: D) { } fun test2(c: C) { - c.foo(b1 = 1, b2 = 1.0) + c.foo(b1 = 1, b2 = 1.0) }