FIR: Introduce NAMED_PARAMETER_NOT_FOUND diagnostic

This commit is contained in:
Denis.Zharkov
2021-04-02 13:37:59 +03:00
committed by TeamCityServer
parent 2d42e64c17
commit 0637748f10
31 changed files with 103 additions and 66 deletions
@@ -571,6 +571,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/namedArrayInAnnotation.kt");
}
@TestMetadata("noParameterForName.kt")
public void testNoParameterForName() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/noParameterForName.kt");
}
@TestMetadata("operatorsOverLiterals.kt")
public void testOperatorsOverLiterals() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/operatorsOverLiterals.kt");
@@ -0,0 +1,6 @@
FILE: noParameterForName.kt
public final fun foo(x: R|kotlin/Int|): R|kotlin/Unit| {
}
public final fun bar(): R|kotlin/Unit| {
<Inapplicable(INAPPLICABLE_ARGUMENTS_MAPPING_ERROR): /foo>#(y = Int(1))
}
@@ -0,0 +1,5 @@
fun foo(x: Int) {}
fun bar() {
foo(<!NAMED_PARAMETER_NOT_FOUND!>y<!> = 1<!NO_VALUE_FOR_PARAMETER!>)<!>
}
@@ -13,5 +13,5 @@ fun test() {
foo(second = 0.0, first = 0, fourth = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
<!INAPPLICABLE_CANDIDATE!>foo<!>(first = 0.0, second = 0, third = "", fourth = false)
foo(first = 0, second = 0.0, third = false, fourth = "", <!ARGUMENT_PASSED_TWICE!>first<!> = 1)
foo(0, 0.0, false, foth = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
foo(0, 0.0, false, <!NAMED_PARAMETER_NOT_FOUND!>foth<!> = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
}
@@ -671,6 +671,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/namedArrayInAnnotation.kt");
}
@Test
@TestMetadata("noParameterForName.kt")
public void testNoParameterForName() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/noParameterForName.kt");
}
@Test
@TestMetadata("operatorsOverLiterals.kt")
public void testOperatorsOverLiterals() throws Exception {
@@ -675,6 +675,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/namedArrayInAnnotation.kt");
}
@Test
@TestMetadata("noParameterForName.kt")
public void testNoParameterForName() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/noParameterForName.kt");
}
@Test
@TestMetadata("operatorsOverLiterals.kt")
public void testOperatorsOverLiterals() throws Exception {
@@ -233,6 +233,10 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val NO_VALUE_FOR_PARAMETER by error<FirSourceElement, KtElement>(PositioningStrategy.VALUE_ARGUMENTS) {
parameter<FirValueParameter>("violatedParameter")
}
val NAMED_PARAMETER_NOT_FOUND by error<FirSourceElement, KtValueArgument>(PositioningStrategy.NAME_OF_NAMED_ARGUMENT) {
parameter<String>("name")
}
}
val AMBIGUITY by object : DiagnosticGroup("Ambiguity") {
@@ -187,6 +187,7 @@ object FirErrors {
val ARGUMENT_PASSED_TWICE by error0<FirSourceElement, KtValueArgument>(SourceElementPositioningStrategies.NAME_OF_NAMED_ARGUMENT)
val TOO_MANY_ARGUMENTS by error1<FirSourceElement, PsiElement, FirCallableDeclaration<*>>()
val NO_VALUE_FOR_PARAMETER by error1<FirSourceElement, KtElement, FirValueParameter>(SourceElementPositioningStrategies.VALUE_ARGUMENTS)
val NAMED_PARAMETER_NOT_FOUND by error1<FirSourceElement, KtValueArgument, String>(SourceElementPositioningStrategies.NAME_OF_NAMED_ARGUMENT)
// Ambiguity
val OVERLOAD_RESOLUTION_AMBIGUITY by error1<FirSourceElement, PsiElement, Collection<AbstractFirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -131,6 +131,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MULTIPLE_VARARG_P
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.NESTED_CLASS_NOT_ALLOWED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NONE_APPLICABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY
@@ -394,6 +395,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
map.put(TOO_MANY_ARGUMENTS, "Too many arguments for {0}", FQ_NAMES_IN_TYPES)
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}''", NAME)
map.put(NAMED_PARAMETER_NOT_FOUND, "Cannot find a parameter with this name: {0}", TO_STRING)
// Ambiguity
map.put(OVERLOAD_RESOLUTION_AMBIGUITY, "Overload resolution ambiguity between candidates: {0}", SYMBOLS)
@@ -141,6 +141,10 @@ private fun mapInapplicableCandidateError(
is ArgumentPassedTwice -> FirErrors.ARGUMENT_PASSED_TWICE.on(rootCause.argument.source)
is TooManyArguments -> FirErrors.TOO_MANY_ARGUMENTS.on(rootCause.argument.source ?: source, rootCause.function)
is NoValueForParameter -> FirErrors.NO_VALUE_FOR_PARAMETER.on(qualifiedAccessSource ?: source, rootCause.valueParameter)
is NameNotFound -> FirErrors.NAMED_PARAMETER_NOT_FOUND.on(
rootCause.argument.source ?: source,
rootCause.argument.name.asString()
)
else -> null
}
}.ifEmpty { listOf(FirErrors.INAPPLICABLE_CANDIDATE.on(source, diagnostic.candidate.symbol)) }
@@ -120,10 +120,8 @@ private class FirCallArgumentsProcessor(
fun processArgumentsInParenthesis(arguments: List<FirExpression>) {
for (argument in arguments) {
val argumentName = argument.argumentName
// process position argument
if (argumentName == null) {
if (argument !is FirNamedArgumentExpression) {
if (processPositionArgument(argument)) {
state = State.VARARG_POSITION
}
@@ -134,7 +132,7 @@ private class FirCallArgumentsProcessor(
completeVarargPositionArguments()
}
processNamedArgument(argument, argumentName)
processNamedArgument(argument)
}
}
if (state == State.VARARG_POSITION) {
@@ -168,14 +166,14 @@ private class FirCallArgumentsProcessor(
}
}
private fun processNamedArgument(argument: FirExpression, name: Name) {
private fun processNamedArgument(argument: FirNamedArgumentExpression) {
forbiddenNamedArgumentsTarget?.let {
addDiagnostic(NamedArgumentNotAllowed(argument, function, it))
}
val stateAllowsMixedNamedAndPositionArguments = state != State.NAMED_ONLY_ARGUMENTS
state = State.NAMED_ONLY_ARGUMENTS
val parameter = findParameterByName(argument, name) ?: return
val parameter = findParameterByName(argument) ?: return
result[parameter]?.let {
addDiagnostic(ArgumentPassedTwice(argument, parameter, it))
@@ -257,8 +255,8 @@ private class FirCallArgumentsProcessor(
return nameToParameter!![name]
}
private fun findParameterByName(argument: FirExpression, name: Name): FirValueParameter? {
val parameter = getParameterByName(name)
private fun findParameterByName(argument: FirNamedArgumentExpression): FirValueParameter? {
val parameter = getParameterByName(argument.name)
// TODO
// if (descriptor is CallableMemberDescriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirNamedArgumentExpression
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability.*
@@ -51,9 +52,9 @@ class NoValueForParameter(
) : ResolutionDiagnostic(INAPPLICABLE_ARGUMENTS_MAPPING_ERROR)
class NameNotFound(
override val argument: FirExpression,
val argument: FirNamedArgumentExpression,
val function: FirFunction<*>
) : InapplicableArgumentDiagnostic()
) : ResolutionDiagnostic(INAPPLICABLE_ARGUMENTS_MAPPING_ERROR)
object InapplicableCandidate : ResolutionDiagnostic(INAPPLICABLE)
@@ -15,7 +15,7 @@ fun test() {
foo("", 1, <!TOO_MANY_ARGUMENTS, UNRESOLVED_REFERENCE!>xx<!>)
<!INAPPLICABLE_CANDIDATE!>foo<!>(r = <!UNRESOLVED_REFERENCE!>xx<!>, i = "", s = "")
foo(<!NAMED_PARAMETER_NOT_FOUND!>r<!> = <!UNRESOLVED_REFERENCE!>xx<!>, i = "", s = "")
foo(i = 1, <!ARGUMENT_PASSED_TWICE!>i<!> = 1, s = 11)
@@ -11,8 +11,8 @@ interface D : B, A
fun foo(x : C, y : D){
x.foo(x = 0)
x.foo(y = 0<!NO_VALUE_FOR_PARAMETER!>)<!>
y.foo(x = 0<!NO_VALUE_FOR_PARAMETER!>)<!>
x.foo(<!NAMED_PARAMETER_NOT_FOUND!>y<!> = 0<!NO_VALUE_FOR_PARAMETER!>)<!>
y.foo(<!NAMED_PARAMETER_NOT_FOUND!>x<!> = 0<!NO_VALUE_FOR_PARAMETER!>)<!>
y.foo(y = 0)
}
@@ -21,7 +21,7 @@ abstract class D1 : A, B
fun bar(x : C1, y : D1){
x.foo(x = 0)
x.foo(y = 0<!NO_VALUE_FOR_PARAMETER!>)<!>
x.foo(<!NAMED_PARAMETER_NOT_FOUND!>y<!> = 0<!NO_VALUE_FOR_PARAMETER!>)<!>
y.foo(x = 0)
y.foo(y = 0<!NO_VALUE_FOR_PARAMETER!>)<!>
y.foo(<!NAMED_PARAMETER_NOT_FOUND!>y<!> = 0<!NO_VALUE_FOR_PARAMETER!>)<!>
}
@@ -14,11 +14,11 @@ interface C : A, B { // Warning here, this is correct
}
fun test(c: C) {
c.foo(b1 = 1, b2 = 1.0<!NO_VALUE_FOR_PARAMETER, NO_VALUE_FOR_PARAMETER!>)<!>
c.foo(a1 = 1, b2 = 1.0<!NO_VALUE_FOR_PARAMETER!>)<!>
c.foo(<!NAMED_PARAMETER_NOT_FOUND!>b1<!> = 1, <!NAMED_PARAMETER_NOT_FOUND!>b2<!> = 1.0<!NO_VALUE_FOR_PARAMETER, NO_VALUE_FOR_PARAMETER!>)<!>
c.foo(a1 = 1, <!NAMED_PARAMETER_NOT_FOUND!>b2<!> = 1.0<!NO_VALUE_FOR_PARAMETER!>)<!>
c.foo(a1 = 1, a2 = 1.0)
c.foo(a1 = 1, a2 = 1.0)
c.bar(a1 = 1, a2 = 1.0, b3= ""<!NO_VALUE_FOR_PARAMETER!>)<!>
c.baz(a1 = 1, b2 = 1.0, a3 = "", b4 = 2, a5 = ""<!NO_VALUE_FOR_PARAMETER, NO_VALUE_FOR_PARAMETER!>)<!>
c.baz(a1 = 1, a2 = 1.0, a3 = "", b4 = 2, a5 = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
c.bar(a1 = 1, a2 = 1.0, <!NAMED_PARAMETER_NOT_FOUND!>b3<!>= ""<!NO_VALUE_FOR_PARAMETER!>)<!>
c.baz(a1 = 1, <!NAMED_PARAMETER_NOT_FOUND!>b2<!> = 1.0, a3 = "", <!NAMED_PARAMETER_NOT_FOUND!>b4<!> = 2, a5 = ""<!NO_VALUE_FOR_PARAMETER, NO_VALUE_FOR_PARAMETER!>)<!>
c.baz(a1 = 1, a2 = 1.0, a3 = "", <!NAMED_PARAMETER_NOT_FOUND!>b4<!> = 2, a5 = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
}
@@ -11,5 +11,5 @@ interface C : A<Int>, B { // Warning here, this is correct
fun test(c: C) {
c.foo(a = 1)
c.foo(b = 1<!NO_VALUE_FOR_PARAMETER!>)<!>
c.foo(<!NAMED_PARAMETER_NOT_FOUND!>b<!> = 1<!NO_VALUE_FOR_PARAMETER!>)<!>
}
@@ -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<!NO_VALUE_FOR_PARAMETER!>)<!>
c.foo(<!NAMED_PARAMETER_NOT_FOUND!>b<!> = 1<!NO_VALUE_FOR_PARAMETER!>)<!>
}
@@ -11,5 +11,5 @@ interface C<U> : A<U>, B<U> { // Warning here, this is correct
fun test(c: C<Int>) {
c.foo(a = 1)
c.foo(b = 1<!NO_VALUE_FOR_PARAMETER!>)<!>
c.foo(<!NAMED_PARAMETER_NOT_FOUND!>b<!> = 1<!NO_VALUE_FOR_PARAMETER!>)<!>
}
@@ -21,7 +21,7 @@ class KotlinSubSubClass : KotlinSubClass() {
fun viaRealOverride() = KotlinSubSubClass().foo(kotlinName = 3)
fun unresolvedParameter() = JavaSuperClass(<!NO_VALUE_FOR_PARAMETER!>)<!>.foo(nonexistentName = 4)
fun unresolvedParameter() = JavaSuperClass(<!NO_VALUE_FOR_PARAMETER!>)<!>.foo(<!NAMED_PARAMETER_NOT_FOUND!>nonexistentName<!> = 4)
fun multipleParameters() = JavaSuperClass().multipleParameters(<!NAMED_ARGUMENTS_NOT_ALLOWED!>first<!> = 1, <!NAMED_ARGUMENTS_NOT_ALLOWED!>second<!> = 2L, <!NAMED_ARGUMENTS_NOT_ALLOWED!>third<!> = "3")
@@ -21,7 +21,7 @@ fun test() {
bar(1, z = "")
bar(1, z = "", y = 2)
<!INAPPLICABLE_CANDIDATE!>bar<!>(z = "", 1)
bar(1, zz = "",
bar(1, <!NAMED_PARAMETER_NOT_FOUND!>zz<!> = "",
<!UNRESOLVED_REFERENCE!>zz<!>.foo
<!NO_VALUE_FOR_PARAMETER!>)<!>
}
@@ -18,5 +18,5 @@ fun test1(d: D) {
}
fun test2(c: C) {
c.foo(b1 = 1, b2 = 1.0<!NO_VALUE_FOR_PARAMETER, NO_VALUE_FOR_PARAMETER!>)<!>
c.foo(<!NAMED_PARAMETER_NOT_FOUND!>b1<!> = 1, <!NAMED_PARAMETER_NOT_FOUND!>b2<!> = 1.0<!NO_VALUE_FOR_PARAMETER, NO_VALUE_FOR_PARAMETER!>)<!>
}
@@ -4,24 +4,24 @@ class Function1Impl : (String) -> Unit {
fun test1(f: Function1Impl) {
f("")
f(p0 = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
f(<!NAMED_PARAMETER_NOT_FOUND!>p0<!> = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
f(myParamName = "")
f.invoke("")
f.invoke(p0 = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
f.invoke(<!NAMED_PARAMETER_NOT_FOUND!>p0<!> = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
f.invoke(myParamName = "")
}
fun test2(f: (String) -> Unit) {
f("")
f(p0 = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
f(myParamName = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
f(<!NAMED_PARAMETER_NOT_FOUND!>p0<!> = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
f(<!NAMED_PARAMETER_NOT_FOUND!>myParamName<!> = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
f.invoke("")
f.invoke(p0 = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
f.invoke(myParamName = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
f.invoke(<!NAMED_PARAMETER_NOT_FOUND!>p0<!> = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
f.invoke(<!NAMED_PARAMETER_NOT_FOUND!>myParamName<!> = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
}
fun test3(f: String.(String) -> Unit) {
"".f("")
"".f(p0 = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
"".f(zzz = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
"".f(<!NAMED_PARAMETER_NOT_FOUND!>p0<!> = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
"".f(<!NAMED_PARAMETER_NOT_FOUND!>zzz<!> = ""<!NO_VALUE_FOR_PARAMETER!>)<!>
}
@@ -1,9 +0,0 @@
package c
fun test() {
with (1) l@ {
<!INAPPLICABLE_CANDIDATE!>foo<!>(1, zz = { this@l } )
}
}
fun foo(x: Int) = x
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
package c
fun test() {
@@ -1,14 +0,0 @@
package c
fun zzz(i: Int, f: (Int) -> Int) { throw Exception("$i $f")}
fun test() {
fun foo(): Int = 42
fun bar(i: Int) = i
bar(<!INAPPLICABLE_CANDIDATE!>foo<!>(xx = zzz(11) { j: Int -> j + 7 }))
bar(zz = <!INAPPLICABLE_CANDIDATE!>foo<!>(
xx = zzz(12) { i: Int -> i + i })<!NO_VALUE_FOR_PARAMETER!>)<!>
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
package c
fun zzz(i: Int, f: (Int) -> Int) { throw Exception("$i $f")}
@@ -53,8 +53,8 @@ fun testMany(a: Any) {
manyFoo(s = "")
<!NONE_APPLICABLE!>manyFoo<!>(a)
<!NONE_APPLICABLE!>manyFoo<!>(v = a)
<!NONE_APPLICABLE!>manyFoo<!>(s = a)
<!NONE_APPLICABLE!>manyFoo<!>(v = a as Int)
<!NONE_APPLICABLE!>manyFoo<!>(s = a as String)
<!INAPPLICABLE_CANDIDATE!>manyFoo<!>(v = a)
<!INAPPLICABLE_CANDIDATE!>manyFoo<!>(s = a)
<!INAPPLICABLE_CANDIDATE!>manyFoo<!>(v = a as Int)
<!INAPPLICABLE_CANDIDATE!>manyFoo<!>(s = a as String)
}
@@ -53,8 +53,8 @@ fun testMany(a: Any) {
manyFoo(s = "")
<!NONE_APPLICABLE!>manyFoo<!>(a)
<!NONE_APPLICABLE!>manyFoo<!>(v = a)
<!NONE_APPLICABLE!>manyFoo<!>(s = a)
<!NONE_APPLICABLE!>manyFoo<!>(v = a as Int)
<!NONE_APPLICABLE!>manyFoo<!>(s = a as String)
<!INAPPLICABLE_CANDIDATE!>manyFoo<!>(v = a)
<!INAPPLICABLE_CANDIDATE!>manyFoo<!>(s = a)
<!INAPPLICABLE_CANDIDATE!>manyFoo<!>(v = a as Int)
<!INAPPLICABLE_CANDIDATE!>manyFoo<!>(s = a as String)
}
@@ -726,6 +726,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.NAMED_PARAMETER_NOT_FOUND) { firDiagnostic ->
NamedParameterNotFoundImpl(
firDiagnostic.a,
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY) { firDiagnostic ->
OverloadResolutionAmbiguityImpl(
firDiagnostic.a.map { abstractFirBasedSymbol ->
@@ -523,6 +523,11 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val violatedParameter: KtSymbol
}
abstract class NamedParameterNotFound : KtFirDiagnostic<KtValueArgument>() {
override val diagnosticClass get() = NamedParameterNotFound::class
abstract val name: String
}
abstract class OverloadResolutionAmbiguity : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = OverloadResolutionAmbiguity::class
abstract val candidates: List<KtSymbol>
@@ -836,6 +836,14 @@ internal class NoValueForParameterImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class NamedParameterNotFoundImpl(
override val name: String,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.NamedParameterNotFound(), KtAbstractFirDiagnostic<KtValueArgument> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class OverloadResolutionAmbiguityImpl(
override val candidates: List<KtSymbol>,
firDiagnostic: FirPsiDiagnostic<*>,