b6b132a9a3
The idea is that when we have successful candidates both from smart cast and original type, we should discriminate in the favor of former ones. While this problem (see kt55722.kt) existed before this branch is merged, initially it was recognized on FP Ultimate when we stopped assuming captured types from the same projections as equal (see kt55722Initial.kt). ^KT-55722 Fixed ^KT-55024 Fixed ^KT-56283 Related ^KT-56310 Related
56 lines
2.1 KiB
Kotlin
Vendored
56 lines
2.1 KiB
Kotlin
Vendored
// SKIP_TXT
|
|
// FIR_DUMP
|
|
// ISSUE: KT-56310
|
|
|
|
interface Base
|
|
interface Derived : Base
|
|
|
|
interface M1 {
|
|
val success: Boolean
|
|
}
|
|
interface M1Sub : M1
|
|
|
|
open class A {
|
|
open protected fun baz(a: Derived): M1 = TODO()
|
|
open protected fun foo(a: Derived): M1 = TODO()
|
|
|
|
fun f(a: A, b: B, d: Derived) {
|
|
a.baz(d).success // OK in K1 and K2
|
|
a.foo(d).success // OK in K1 and K2
|
|
|
|
// Both K1 and K2 resolves calls to B's members with String return type because other's members in B type are invisible
|
|
b.baz(d).length
|
|
b.foo(d).length
|
|
|
|
when (a) {
|
|
is B -> {
|
|
// OK in K1 because `a.baz(d)` resolved to String returning methid (just as `b.baz(d)`)
|
|
<!DEBUG_INFO_SMARTCAST!>a<!>.baz(d).length
|
|
// OK in K2, because we have two visible candidates:
|
|
// - A::baz from original (after unwrapping smart cast) receiver
|
|
// - B::baz that returns String
|
|
// But the first one is more specific via its parameter types
|
|
<!DEBUG_INFO_SMARTCAST!>a<!>.baz(d).<!UNRESOLVED_REFERENCE!>success<!> // Unresolved reference in K1, going to be OK in K2
|
|
|
|
// Works in K2 for the same reasons as `a.baz(d)`
|
|
// In K1, works by coincidence because we bind override groups for members from original and smart cast receiver,
|
|
// and as return type from B is the same (not more specific), we choose the member from A as a group representative.
|
|
// Thus, we have successful candidates
|
|
// - A::foo
|
|
// - B::foo returning String
|
|
// But A::foo is more specific, so we choose it
|
|
a.foo(d).success
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class B : A() {
|
|
override fun baz(a: Derived): M1Sub = TODO()
|
|
public fun baz(a: Base): String = TODO()
|
|
|
|
// The only difference between `baz` and `foo` is that the former has more specific covariant return type (M1Sub)
|
|
override fun foo(a: Derived): M1 = TODO()
|
|
public fun foo(a: Base): String = TODO()
|
|
}
|