K2: Complete property-candidate before starting invoke resolution

Before this commit, for property candidates in K2 their types wasn't
inferred/susbtituted properly.

So, when candidate for fooBar.liveLoaded.invoke() was created,
the type of `fooBar.liveLoaded` was just X type parameter for which
there is no any `bar()` functions in its member scope.

While proposed semantics is a bit different from K1, where
both property and invoke candidates are united into common system,
it doesn't contradict to the specification (https://kotlinlang.org/spec/overload-resolution.html#callables-and-invoke-convention)
which says explicitly that invoke-convention should be desugared as
`r.foo.invoke()`, thus `r.foo` should be completed independently.

Also, this strategy supports some reasonable use-cases like KT-58259
while it's still a breaking change but for more artificial-looking
situations (see KT-58260) and should be passed through
the language committee.

The changes in stubTypeReceiverRestriction* tests looks consistent
because of how `genericLambda` now works
(with full completion of property call).
NB: The code is going to be red once KT-54667 is fixed and also there's
already similar diagnostic in K1 (INFERRED_INTO_DECLARED_UPPER_BOUNDS)

^KT-58142 Fixed
^KT-58259 Fixed
^KT-58260 Related
This commit is contained in:
Denis.Zharkov
2023-04-24 12:27:47 +02:00
committed by Space Team
parent 481becb342
commit 7b46c59d57
17 changed files with 191 additions and 68 deletions
@@ -63,7 +63,7 @@ fun test5() {
val <T> T.genericLambda: T.((T) -> Unit) -> Unit get() = {}
fun test6() {
b {
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>b<!> {
extension()
genericLambda { }
genericLambda { it.extension() }
@@ -64,7 +64,7 @@ fun test5() {
val <T> T.genericLambda: T.((T) -> Unit) -> Unit get() = {}
fun test6() {
b {
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>b<!> {
extension()
genericLambda { }
genericLambda { it.extension() }
@@ -0,0 +1,21 @@
// FIR_IDENTICAL
// ISSUE: KT-58142
interface XTrackableLoading {
val <X> Property<LoadingValue<X>>.liveLoaded: X
get(): X = TODO()
}
interface LoadingValue<T>
interface Property<T>
interface AsyncModule {
fun bar() {}
}
operator fun <T : AsyncModule, R> T.invoke(handler: T.() -> R): R = TODO()
fun XTrackableLoading.foo(fooBar: Property<LoadingValue<AsyncModule>>) {
fooBar.liveLoaded {
bar()
}
}
@@ -0,0 +1,20 @@
// ISSUE: KT-58259
interface Box<T> {
val value: T
}
interface Res {
operator fun invoke() {}
}
val <X> Box<X>.foo: X get() = TODO()
fun foo(p: Box<Res>) {
p.value.invoke() // OK
p.value() // OK
p.foo.invoke() // OK
// Error in K1, OK in K2
p.foo()
}
@@ -0,0 +1,20 @@
// ISSUE: KT-58259
interface Box<T> {
val value: T
}
interface Res {
operator fun invoke() {}
}
val <X> Box<X>.foo: X get() = TODO()
fun foo(p: Box<Res>) {
p.value.invoke() // OK
p.value() // OK
p.foo.invoke() // OK
// Error in K1, OK in K2
p.<!FUNCTION_EXPECTED!>foo<!>()
}
@@ -0,0 +1,17 @@
// ISSUE: KT-58260
interface Box<T>
interface Res<E>
operator fun <F> Res<F>.invoke(f: F): F = TODO()
val <X> Box<in X>.foo: Res<X> get() = TODO()
fun foo(p: Box<in Any?>) {
p.foo("").<!UNRESOLVED_REFERENCE!>length<!>
p.foo.invoke("").<!UNRESOLVED_REFERENCE!>length<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>p.foo("")<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>p.foo.invoke("")<!>
}
@@ -0,0 +1,17 @@
// ISSUE: KT-58260
interface Box<T>
interface Res<E>
operator fun <F> Res<F>.invoke(f: F): F = TODO()
val <X> Box<in X>.foo: Res<X> get() = TODO()
fun foo(p: Box<in Any?>) {
p.foo("").length
p.foo.invoke("").<!UNRESOLVED_REFERENCE!>length<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>p.foo("")<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>p.foo.invoke("")<!>
}