[FIR] Keep all failed resolution candidates and fully resolve them

Previously, when a candidate was found with an applicability that is
better than the current best applicability, all previous candidates were
thrown away. Now we keep them, unless the new applicability is
successful. If no successful candidates are found, we fully resolve all
the unsuccessful ones and select the ones with the least bad
applicability. This improves diagnostics for unresolved calls.

#KT-57844 Fixed
This commit is contained in:
Kirill Rakhman
2023-05-03 13:32:42 +02:00
committed by Space Team
parent 451daaa7c5
commit b2fa104081
44 changed files with 245 additions and 109 deletions
@@ -1,5 +1,5 @@
object A1<!CONSTRUCTOR_IN_OBJECT!>()<!> {
<!CONSTRUCTOR_IN_OBJECT!>constructor(x: Int = "", y: Int)<!> : <!NONE_APPLICABLE!>this<!>() {
<!CONSTRUCTOR_IN_OBJECT!>constructor(x: Int = "", y: Int)<!> : <!UNRESOLVED_REFERENCE!>this<!>() {
x + y
}
}
@@ -11,6 +11,6 @@ fun test() {
<!NONE_APPLICABLE!>foo<!>(1, 2)
foo(<!ARGUMENT_TYPE_MISMATCH!>""<!>)
<!NONE_APPLICABLE!>bar<!>(1, 2)
bar(1, <!TOO_MANY_ARGUMENTS!>2<!>)
<!NONE_APPLICABLE!>bar<!>()
}
@@ -94,7 +94,7 @@ fun test() {
emit(null)
val x = get()
if (x == null) {
x<!UNSAFE_CALL!>.<!>toString("")
x.<!NONE_APPLICABLE!>toString<!>("")
}
""
@@ -134,7 +134,7 @@ fun test() {
emit(null)
val x = get()
if (<!FORBIDDEN_IDENTITY_EQUALS_WARNING!>x === null<!>) {
x<!UNSAFE_CALL!>.<!>toString("")
x.<!NONE_APPLICABLE!>toString<!>("")
}
""
@@ -13,6 +13,6 @@ fun <T: Any> joinT(x: Comparable<*>, y: T): T? {
}
fun test() {
val x2 = <!NONE_APPLICABLE!>joinT<!>(Unit, "2")
val x2 = joinT(<!ARGUMENT_TYPE_MISMATCH!>Unit<!>, "2")
checkSubtype<String?>(x2)
}
@@ -274,8 +274,8 @@ fun poll76() {
}
fun poll8() {
val inv = ::<!UNRESOLVED_REFERENCE!>bar<!> <!NONE_APPLICABLE!>in<!> <!NONE_APPLICABLE!>setOf<!>(::<!UNRESOLVED_REFERENCE!>foo<!>)
<!NO_VALUE_FOR_PARAMETER!>inv()<!>
val inv = ::<!UNRESOLVED_REFERENCE!>bar<!> <!INAPPLICABLE_CANDIDATE!>in<!> <!INAPPLICABLE_CANDIDATE!>setOf<!>(::<!UNRESOLVED_REFERENCE!>foo<!>)
<!UNRESOLVED_REFERENCE!>inv<!>()
}
fun poll81() {
@@ -284,8 +284,8 @@ fun poll81() {
}
fun poll82() {
val inv = ::<!UNRESOLVED_REFERENCE!>bar3<!> <!NONE_APPLICABLE!>in<!> <!NONE_APPLICABLE!>setOf<!>(::<!UNRESOLVED_REFERENCE!>foo3<!>)
<!NO_VALUE_FOR_PARAMETER!>inv()<!>
val inv = ::<!UNRESOLVED_REFERENCE!>bar3<!> <!INAPPLICABLE_CANDIDATE!>in<!> <!INAPPLICABLE_CANDIDATE!>setOf<!>(::<!UNRESOLVED_REFERENCE!>foo3<!>)
<!UNRESOLVED_REFERENCE!>inv<!>()
}
fun poll83() {
@@ -294,7 +294,7 @@ fun poll83() {
}
fun poll84() {
val inv = ::<!UNRESOLVED_REFERENCE!>bar5<!> <!NONE_APPLICABLE!>in<!> <!NONE_APPLICABLE!>setOf<!>(::<!UNRESOLVED_REFERENCE!>foo5<!>)
val inv = ::<!UNRESOLVED_REFERENCE!>bar5<!> <!INAPPLICABLE_CANDIDATE!>in<!> <!INAPPLICABLE_CANDIDATE!>setOf<!>(::<!UNRESOLVED_REFERENCE!>foo5<!>)
inv
}
@@ -1,20 +0,0 @@
// MODULE: m1
// FILE: a.kt
package p
fun f(s: String, t: String) = s + t
// MODULE: m2
// FILE: b.kt
package p
fun f(s: String, t: String) = t + s
// MODULE: m3(m1, m2)
// FILE: c.kt
import p.f
fun test() {
// There should be no "none applicable" error here
<!NONE_APPLICABLE!>f<!>(
<!SYNTAX!><!>}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// MODULE: m1
// FILE: a.kt
package p
@@ -5,5 +5,5 @@ fun <T : Bar, T1> foo(x : Int) {}
fun <T1, T : Foo> foo(x : Long) {}
fun f(): Unit {
<!NONE_APPLICABLE!>foo<!><Int, Int>(1)
foo<<!UPPER_BOUND_VIOLATED!>Int<!>, Int>(<!ARGUMENT_TYPE_MISMATCH!>1<!>)
}
@@ -0,0 +1,27 @@
// SKIP_TXT
// FILE: MyJClass.java
public class MyJClass {
public void meth(int pathname) {}
private void meth(String pathname, int prefixLength) {}
private void meth(String child, boolean b) {}
}
// FILE: MyJClass2.java
public class MyJClass2 {
public void meth(int pathname) {}
public void meth(String pathname, int prefixLength) {}
private void meth(String child, boolean b) {}
}
// FILE: test.kt
fun test1(myJClass: MyJClass) {
myJClass.meth(<!ARGUMENT_TYPE_MISMATCH!>""<!>)
}
fun test2(myJClass: MyJClass2) {
myJClass.meth(<!ARGUMENT_TYPE_MISMATCH!>""<!>)
}
@@ -0,0 +1,27 @@
// SKIP_TXT
// FILE: MyJClass.java
public class MyJClass {
public void meth(int pathname) {}
private void meth(String pathname, int prefixLength) {}
private void meth(String child, boolean b) {}
}
// FILE: MyJClass2.java
public class MyJClass2 {
public void meth(int pathname) {}
public void meth(String pathname, int prefixLength) {}
private void meth(String child, boolean b) {}
}
// FILE: test.kt
fun test1(myJClass: MyJClass) {
myJClass.meth(<!TYPE_MISMATCH!>""<!>)
}
fun test2(myJClass: MyJClass2) {
myJClass.meth(<!TYPE_MISMATCH!>""<!>)
}
@@ -7,7 +7,7 @@ class SomeClass
fun test(identifier: SomeClass, fn: String.() -> Unit) {
<!NONE_APPLICABLE!>identifier<!>()
identifier(<!NO_VALUE_FOR_PARAMETER!>123)<!>
<!NONE_APPLICABLE!>identifier<!>(123)
identifier(1, <!TOO_MANY_ARGUMENTS!>2<!>)
<!ARGUMENT_TYPE_MISMATCH!>1<!>.fn()
}
@@ -8,6 +8,6 @@ fun overloadedFun(arg: String, vararg args: String) = X1
fun overloadedFun(arg: String, vararg args: String, flag: Boolean = true) = X2
val test1a: X1 = overloadedFun("", "")
val test1b: X1 = <!NONE_APPLICABLE!>overloadedFun<!>("", args = "")
val test1b: X1 = overloadedFun("", args = <!ARGUMENT_TYPE_MISMATCH, ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION_ERROR!>""<!>)
val test1c: X2 = overloadedFun("", "", "", flag = true)
@@ -18,7 +18,7 @@ val y2: B<Int> = B("")
val y3: B<Int> = B<Int>(1)
val y4: B<Int> = B<Int>("")
val y5: B<String> = <!NONE_APPLICABLE!>B<!><String>(1)
val y5: B<String> = B<String>(<!ARGUMENT_TYPE_MISMATCH!>1<!>)
val y6: B<String> = B<String>("")
val y7: B<String> = <!TYPE_MISMATCH, TYPE_MISMATCH!>B(1)<!>
val y8: B<String> = B("")
@@ -6,9 +6,9 @@ class A0<T1, T2> {
constructor(x: T1, y: T2, z: T2): this(x, 1) // ok, delegates to constructor(x: T1, y: Int)
constructor(x: T1, y: Int): <!NONE_APPLICABLE!>this<!>(x, "")
constructor(x: T1, y: Int): this(x, <!ARGUMENT_TYPE_MISMATCH!>""<!>)
constructor(x: T1): this(x, 1)
constructor(x: T1, y: T2, z: String): <!NONE_APPLICABLE!>this<!>(y, x)
constructor(x: T1, y: T2, z: String): this(<!ARGUMENT_TYPE_MISMATCH!>y<!>, <!ARGUMENT_TYPE_MISMATCH!>x<!>)
}
class A1<T1, T2> : B<T1, T2> {
@@ -14,7 +14,7 @@ fun bar(arg: Long?): Long {
return i<!UNSAFE_CALL!>--<!> <!UNSAFE_OPERATOR_CALL!>+<!> i
}
if (i++ == 7L) {
return i++ <!UNSAFE_OPERATOR_CALL!>+<!> i
return i++ <!NONE_APPLICABLE!>+<!> i
}
return 0L
}
@@ -18,7 +18,7 @@ fun testLong(@ImplicitIntegerCoercion x: ULong) = x
fun box(): String = when {
test(5) != 5.toUInt() -> "Fail: test(5)"
<!NONE_APPLICABLE!>test<!>(5L) != 5L.toULong() -> "Fail: test(5L)"
<!EQUALITY_NOT_APPLICABLE!>test(<!ARGUMENT_TYPE_MISMATCH!>5L<!>) != 5L.toULong()<!> -> "Fail: test(5L)"
testLong(5) != 5L.toULong() -> "Fail: test(5L)"
testLong(<!ARGUMENT_TYPE_MISMATCH!>5L<!>) != 5L.toULong() -> "Fail: test(5L)"
else -> "OK"
@@ -12,8 +12,8 @@ fun foo() {
<!NEW_INFERENCE_ERROR!>select(1, 1u)<!> checkType { <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><Comparable<*>>() }
takeUByte(<!ARGUMENT_TYPE_MISMATCH!>id(1)<!>)
1 <!NONE_APPLICABLE!>+<!> 1u
(1u <!NONE_APPLICABLE!>+<!> 1) <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>checkType<!> { _<UInt>() }
1 + <!ARGUMENT_TYPE_MISMATCH!>1u<!>
(1u + <!ARGUMENT_TYPE_MISMATCH!>1<!>) checkType { _<UInt>() }
id<UInt>(<!ARGUMENT_TYPE_MISMATCH!>1<!>)
}
@@ -9,6 +9,6 @@ fun test() {
1.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>fUShort<!>()
1.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>fULong<!>()
3000000000 <!NONE_APPLICABLE!>until<!> 3000000004UL
0 <!NONE_APPLICABLE!>until<!> 10u
3000000000 until <!ARGUMENT_TYPE_MISMATCH!>3000000004UL<!>
0 until <!ARGUMENT_TYPE_MISMATCH!>10u<!>
}
@@ -21,7 +21,7 @@ fun test() {
foo(1) checkType { _<Int>() }
foo(1u) checkType { _<String>() }
<!NONE_APPLICABLE!>foo<!>(2147483648) <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>checkType<!> { _<String>() }
foo(<!ARGUMENT_TYPE_MISMATCH!>2147483648<!>) checkType { <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><String>() }
foo(2147483647 + 1) checkType { _<Int>() }
fooByte(1) checkType { _<Int>() }