K1: add diagnostic BUILDER_INFERENCE_STUB_RECEIVER

It's reported on receivers in extension function calls with stub type,
as such calls can shadow members of finalized stub types causing
change of resolve when corresponding type argument specified explicitly

It works by checking extension receiver during call resolution parts run
That way we can easily detect if we found an extension applicable to
stub receiver and report call diagnostic for it

KT-53739
This commit is contained in:
Simon Ogorodnik
2022-08-26 16:23:01 +02:00
committed by teamcity
parent 105358dcf6
commit 154e53c701
18 changed files with 428 additions and 44 deletions
@@ -12,7 +12,7 @@ fun main() {
buildList {
add(Bar())
this.get(0).test() // resolved to Any?.test
<!BUILDER_INFERENCE_STUB_RECEIVER!>this.get(0)<!>.test() // resolved to Any?.test
}
buildList<Bar> {
add(Bar())
@@ -1,4 +1,5 @@
// WITH_STDLIB
// SKIP_TXT
fun test() {
foo(
flow { emit(0) }
@@ -3,7 +3,7 @@
fun test() {
foo(
flow { emit(0) }
) <!BUILDER_INFERENCE_MULTI_LAMBDA_RESTRICTION!>{ it.collect <!TOO_MANY_ARGUMENTS!>{}<!> }<!>
) <!BUILDER_INFERENCE_MULTI_LAMBDA_RESTRICTION!>{ <!BUILDER_INFERENCE_STUB_RECEIVER!>it<!>.collect <!TOO_MANY_ARGUMENTS!>{}<!> }<!>
// 0. Initial
// W <: Any / declared upper bound
@@ -20,9 +20,9 @@ fun test() {
val ret1 = build {
emit(1)
emit(null)
get()?.test()
get()?.test2()
get().test2()
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test()
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test2()
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>.test2()
get()?.hashCode()
get()?.equals(1)
// there is `String?.equals` extension
@@ -31,9 +31,9 @@ fun test() {
val ret2 = build {
emit(1)
emit(null)
get()?.test()
get()?.test2()
get().test2()
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test()
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test2()
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>.test2()
get()?.hashCode()
get()?.equals(1)
val x = get()
@@ -44,9 +44,9 @@ fun test() {
val ret3 = build {
emit(1)
emit(null)
get()?.test()
get()?.test2()
get().test2()
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test()
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test2()
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>.test2()
get()?.hashCode()
get()?.equals(1)
val x = get()
@@ -62,9 +62,9 @@ fun test() {
x.equals("")
x.hashCode()
x.toString()
x.test()
x<!UNNECESSARY_SAFE_CALL!>?.<!>test2()
x.test2()
<!BUILDER_INFERENCE_STUB_RECEIVER!>x<!>.test()
<!BUILDER_INFERENCE_STUB_RECEIVER!>x<!><!UNNECESSARY_SAFE_CALL!>?.<!>test2()
<!BUILDER_INFERENCE_STUB_RECEIVER!>x<!>.test2()
}
""
@@ -104,7 +104,7 @@ fun test() {
emit(null)
val x = get()
if (x == null) {
<!TYPE_MISMATCH("Any; Nothing?")!>x<!>.test()
<!BUILDER_INFERENCE_STUB_RECEIVER, TYPE_MISMATCH("Any; Nothing?")!>x<!>.test()
}
""
@@ -144,7 +144,7 @@ fun test() {
emit(null)
val x = get()
if (x === null) {
<!TYPE_MISMATCH("Any; Nothing?")!>x<!>.test()
<!BUILDER_INFERENCE_STUB_RECEIVER, TYPE_MISMATCH("Any; Nothing?")!>x<!>.test()
}
""
@@ -153,16 +153,16 @@ fun test() {
emit(1)
emit(null)
val x = get()
<!TYPE_MISMATCH("Any; Nothing?")!>x<!>.test()
<!BUILDER_INFERENCE_STUB_RECEIVER, TYPE_MISMATCH("Any; Nothing?")!>x<!>.test()
""
}
val ret41 = build {
emit(1)
emit(null)
get()?.test()
get()?.test2()
get().test2()
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test()
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test2()
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>.test2()
get()?.hashCode()
get()?.equals(1)
val x = get()
@@ -181,11 +181,11 @@ fun test() {
}
if (x == null) {
<!DEBUG_INFO_CONSTANT!>x<!>?.test2()
<!BUILDER_INFERENCE_STUB_RECEIVER, DEBUG_INFO_CONSTANT!>x<!>?.test2()
}
if (x == null) {
x.test2()
<!BUILDER_INFERENCE_STUB_RECEIVER!>x<!>.test2()
}
if (x === null) {
@@ -197,11 +197,11 @@ fun test() {
}
if (x === null) {
<!DEBUG_INFO_CONSTANT!>x<!>?.test2()
<!BUILDER_INFERENCE_STUB_RECEIVER, DEBUG_INFO_CONSTANT!>x<!>?.test2()
}
if (x === null) {
x.test2()
<!BUILDER_INFERENCE_STUB_RECEIVER!>x<!>.test2()
}
""
@@ -239,7 +239,7 @@ fun test() {
emit(null)
val x = get()
if (x == null) {
<!TYPE_MISMATCH("Any; Nothing?")!>x<!>.test()
<!BUILDER_INFERENCE_STUB_RECEIVER, TYPE_MISMATCH("Any; Nothing?")!>x<!>.test()
}
""
}
@@ -276,7 +276,7 @@ fun test() {
emit(null)
val x = get()
if (x === null) {
<!TYPE_MISMATCH("Any; Nothing?")!>x<!>.test()
<!BUILDER_INFERENCE_STUB_RECEIVER, TYPE_MISMATCH("Any; Nothing?")!>x<!>.test()
}
""
}
@@ -284,15 +284,15 @@ fun test() {
emit(1)
emit(null)
val x = get()
<!TYPE_MISMATCH("Any; Nothing?")!>x<!>.test()
<!BUILDER_INFERENCE_STUB_RECEIVER, TYPE_MISMATCH("Any; Nothing?")!>x<!>.test()
""
}
val ret51 = build {
emit(1)
emit(null)
get()?.test()
get()?.test2()
get().test2()
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test()
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test2()
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>.test2()
get()?.hashCode()
get()?.equals(1)
val x = get()
@@ -305,8 +305,8 @@ fun test() {
if (x == null) {
<!DEBUG_INFO_CONSTANT!>x<!>?.hashCode()
<!DEBUG_INFO_CONSTANT!>x<!>?.equals(1)
<!DEBUG_INFO_CONSTANT!>x<!>?.test2()
x.test2()
<!BUILDER_INFERENCE_STUB_RECEIVER, DEBUG_INFO_CONSTANT!>x<!>?.test2()
<!BUILDER_INFERENCE_STUB_RECEIVER!>x<!>.test2()
}
""
@@ -0,0 +1,72 @@
// WITH_STDLIB
// SKIP_TXT
fun <R> a(lambda: List<R>.(R) -> Unit) {}
fun <T> T.extension() {}
fun use(p: Any?) {}
fun test1() {
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>a<!> {
this.get(0).extension()
use(this.get(0)::extension)
use(it::extension)
}
}
fun test2() {
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>a<!> {
val v = this.get(0)
v.extension()
use(v::extension)
use(it::extension)
}
}
fun test3() {
operator fun <T> T.getValue(thisRef: Any?, prop: Any?): T = this
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>a<!> {
val v by this.get(0)
v.extension()
use(v::extension)
use(it::extension)
}
}
class Box<TIn>(val t: TIn)
fun test4() {
operator fun <T> T.provideDelegate(thisRef: Any?, prop: Any?): Box<T> = Box(this)
operator fun <T> Box<T>.getValue(thisRef: Any?, prop: Any?): T = this.t
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>a<!> {
val v by this.get(0)
v.extension()
use(v::extension)
use(it::extension)
}
}
fun <R> b(lambda: R.(List<R>) -> Unit) {}
fun test5() {
operator fun <T> T.invoke(): T = this
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>b<!> {
extension()
this().extension()
use(::extension)
}
}
val <T> T.genericLambda: T.((T) -> Unit) -> Unit get() = {}
fun test6() {
b {
extension()
genericLambda { }
genericLambda { it.extension() }
use(::extension)
}
}
@@ -0,0 +1,72 @@
// WITH_STDLIB
// SKIP_TXT
fun <R> a(lambda: List<R>.(R) -> Unit) {}
fun <T> T.extension() {}
fun use(p: Any?) {}
fun test1() {
<!INFERRED_INTO_DECLARED_UPPER_BOUNDS!>a<!> {
<!BUILDER_INFERENCE_STUB_RECEIVER("R; a")!>this.get(0)<!>.extension()
use(<!BUILDER_INFERENCE_STUB_RECEIVER("R; a")!>this.get(0)<!>::extension)
use(<!BUILDER_INFERENCE_STUB_RECEIVER("R; a")!>it<!>::extension)
}
}
fun test2() {
<!INFERRED_INTO_DECLARED_UPPER_BOUNDS!>a<!> {
val v = this.get(0)
<!BUILDER_INFERENCE_STUB_RECEIVER("R; a")!>v<!>.extension()
use(<!BUILDER_INFERENCE_STUB_RECEIVER("R; a")!>v<!>::extension)
use(<!BUILDER_INFERENCE_STUB_RECEIVER("R; a")!>it<!>::extension)
}
}
fun test3() {
operator fun <T> T.getValue(thisRef: Any?, prop: Any?): T = this
<!INFERRED_INTO_DECLARED_UPPER_BOUNDS!>a<!> {
val v by <!BUILDER_INFERENCE_STUB_RECEIVER("R; a")!>this.get(0)<!>
<!BUILDER_INFERENCE_STUB_RECEIVER("R; a")!>v<!>.extension()
use(<!BUILDER_INFERENCE_STUB_RECEIVER("R; a")!>v<!>::extension)
use(<!BUILDER_INFERENCE_STUB_RECEIVER("R; a")!>it<!>::extension)
}
}
class Box<TIn>(val t: TIn)
fun test4() {
operator fun <T> T.provideDelegate(thisRef: Any?, prop: Any?): Box<T> = Box(this)
operator fun <T> Box<T>.getValue(thisRef: Any?, prop: Any?): T = this.t
<!INFERRED_INTO_DECLARED_UPPER_BOUNDS!>a<!> {
val v by <!BUILDER_INFERENCE_STUB_RECEIVER("R; a")!>this.get(0)<!>
<!BUILDER_INFERENCE_STUB_RECEIVER("R; a")!>v<!>.extension()
use(<!BUILDER_INFERENCE_STUB_RECEIVER("R; a")!>v<!>::extension)
use(<!BUILDER_INFERENCE_STUB_RECEIVER("R; a")!>it<!>::extension)
}
}
fun <R> b(lambda: R.(List<R>) -> Unit) {}
fun test5() {
operator fun <T> T.invoke(): T = this
<!INFERRED_INTO_DECLARED_UPPER_BOUNDS!>b<!> {
<!BUILDER_INFERENCE_STUB_RECEIVER("R; b")!>extension()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER("R; b")!><!BUILDER_INFERENCE_STUB_RECEIVER("R; b")!>this<!>()<!>.extension()
<!BUILDER_INFERENCE_STUB_RECEIVER("R; b")!>use(::extension)<!>
}
}
val <T> T.genericLambda: T.((T) -> Unit) -> Unit get() = {}
fun test6() {
<!INFERRED_INTO_DECLARED_UPPER_BOUNDS!>b<!> {
<!BUILDER_INFERENCE_STUB_RECEIVER("R; b")!>extension()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER("R; b")!>genericLambda<!> { }
<!BUILDER_INFERENCE_STUB_RECEIVER("R; b")!>genericLambda<!> { <!BUILDER_INFERENCE_STUB_RECEIVER("R; b")!>it<!>.extension() }
<!BUILDER_INFERENCE_STUB_RECEIVER("R; b")!>use(::extension)<!>
}
}
@@ -0,0 +1,73 @@
// WITH_STDLIB
// LANGUAGE: +NoBuilderInferenceWithoutAnnotationRestriction
// SKIP_TXT
fun <R> a(lambda: List<R>.(R) -> Unit) {}
fun <T> T.extension() {}
fun use(p: Any?) {}
fun test1() {
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>a<!> {
this.get(0).extension()
use(this.get(0)::extension)
use(it::extension)
}
}
fun test2() {
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>a<!> {
val v = this.get(0)
v.extension()
use(v::extension)
use(it::extension)
}
}
fun test3() {
operator fun <T> T.getValue(thisRef: Any?, prop: Any?): T = this
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>a<!> {
val v by this.get(0)
v.extension()
use(v::extension)
use(it::extension)
}
}
class Box<TIn>(val t: TIn)
fun test4() {
operator fun <T> T.provideDelegate(thisRef: Any?, prop: Any?): Box<T> = Box(this)
operator fun <T> Box<T>.getValue(thisRef: Any?, prop: Any?): T = this.t
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>a<!> {
val v by this.get(0)
v.extension()
use(v::extension)
use(it::extension)
}
}
fun <R> b(lambda: R.(List<R>) -> Unit) {}
fun test5() {
operator fun <T> T.invoke(): T = this
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>b<!> {
extension()
this().extension()
use(::extension)
}
}
val <T> T.genericLambda: T.((T) -> Unit) -> Unit get() = {}
fun test6() {
b {
extension()
genericLambda { }
genericLambda { it.extension() }
use(::extension)
}
}
@@ -0,0 +1,73 @@
// WITH_STDLIB
// LANGUAGE: +NoBuilderInferenceWithoutAnnotationRestriction
// SKIP_TXT
fun <R> a(lambda: List<R>.(R) -> Unit) {}
fun <T> T.extension() {}
fun use(p: Any?) {}
fun test1() {
<!INFERRED_INTO_DECLARED_UPPER_BOUNDS!>a<!> {
this.get(0).extension()
use(this.get(0)::extension)
use(it::extension)
}
}
fun test2() {
<!INFERRED_INTO_DECLARED_UPPER_BOUNDS!>a<!> {
val v = this.get(0)
v.extension()
use(v::extension)
use(it::extension)
}
}
fun test3() {
operator fun <T> T.getValue(thisRef: Any?, prop: Any?): T = this
<!INFERRED_INTO_DECLARED_UPPER_BOUNDS!>a<!> {
val v by this.get(0)
v.extension()
use(v::extension)
use(it::extension)
}
}
class Box<TIn>(val t: TIn)
fun test4() {
operator fun <T> T.provideDelegate(thisRef: Any?, prop: Any?): Box<T> = Box(this)
operator fun <T> Box<T>.getValue(thisRef: Any?, prop: Any?): T = this.t
<!INFERRED_INTO_DECLARED_UPPER_BOUNDS!>a<!> {
val v by this.get(0)
v.extension()
use(v::extension)
use(it::extension)
}
}
fun <R> b(lambda: R.(List<R>) -> Unit) {}
fun test5() {
operator fun <T> T.invoke(): T = this
<!INFERRED_INTO_DECLARED_UPPER_BOUNDS!>b<!> {
extension()
this().extension()
use(::extension)
}
}
val <T> T.genericLambda: T.((T) -> Unit) -> Unit get() = {}
fun test6() {
<!INFERRED_INTO_DECLARED_UPPER_BOUNDS!>b<!> {
extension()
genericLambda { }
genericLambda { it.extension() }
use(::extension)
}
}