Add deprecation warning for false-negative TYPE_MISMATCH

See KT-49404 for details

In K1, within SubstitutingScope we approximate almost all the types
containing captured types are being approximated to either a lower or
an upper bound.

While mostly, it's being done correctly there are some problems with
approximations for flexible types

So, the parameter's type of A<in Any>::foo is approximated to Inv<in Any!>,
thus allowing to use Inv<*>, while it's obviously unsound.

NB: For the similar example, in B, there are regular TYPE_MISMATCH
because parameter for B<in Any>::foo is approximated to Nothing

Also, it's important to say that
- in K2 everything works because we don't use type approximation there
- approximation algorithm that works incorrectly is only being used in K1

^KT-54332 Fixed
This commit is contained in:
Denis.Zharkov
2022-10-06 13:08:37 +02:00
committed by Space Team
parent 4b455c0e51
commit 31ba1f1534
13 changed files with 384 additions and 1 deletions
@@ -0,0 +1,43 @@
// ISSUE: KT-49404
// SKIP_TXT
// FILE: A.java
public class A<T> implements WithExtension<T> {
public void foo(Inv<T> w) {}
public void ext(Inv<T> t) {}
}
// FILE: main.kt
class Inv<T>(var t: T)
interface WithExtension<F> {
fun Inv<F>.ext() {}
}
class B<E> : WithExtension<E> {
fun foo(w: Inv<E>) {}
}
fun withInvStar(i: Inv<*>.() -> Unit) {}
fun bar1(a: A<in Any>, i: Inv<*>) {
a.foo(<!ARGUMENT_TYPE_MISMATCH!>i<!>)
}
fun bar2(b: B<in Any>, i: Inv<*>) {
b.foo(<!ARGUMENT_TYPE_MISMATCH!>i<!>)
}
fun A<in Any>.bar3(i: Inv<*>) {
i.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>ext<!>()
withInvStar {
<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>ext<!>()
}
}
fun B<in Any>.bar4(i: Inv<*>) {
i.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>ext<!>()
withInvStar {
<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>ext<!>()
}
}
@@ -0,0 +1,43 @@
// ISSUE: KT-49404
// SKIP_TXT
// FILE: A.java
public class A<T> implements WithExtension<T> {
public void foo(Inv<T> w) {}
public void ext(Inv<T> t) {}
}
// FILE: main.kt
class Inv<T>(var t: T)
interface WithExtension<F> {
fun Inv<F>.ext() {}
}
class B<E> : WithExtension<E> {
fun foo(w: Inv<E>) {}
}
fun withInvStar(i: Inv<*>.() -> Unit) {}
fun bar1(a: A<in Any>, i: Inv<*>) {
a.foo(<!TYPE_MISMATCH_WARNING_FOR_INCORRECT_CAPTURE_APPROXIMATION!>i<!>)
}
fun bar2(b: B<in Any>, i: Inv<*>) {
b.foo(<!TYPE_MISMATCH!>i<!>)
}
fun A<in Any>.bar3(i: Inv<*>) {
<!RECEIVER_TYPE_MISMATCH_WARNING_FOR_INCORRECT_CAPTURE_APPROXIMATION!>i<!>.ext()
withInvStar {
<!RECEIVER_TYPE_MISMATCH_WARNING_FOR_INCORRECT_CAPTURE_APPROXIMATION!>ext<!>()
}
}
fun B<in Any>.bar4(i: Inv<*>) {
i.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>ext<!>()
withInvStar {
<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>ext<!>()
}
}
@@ -0,0 +1,9 @@
// SKIP_TXT
interface Comp<T> {
fun foo(t: T)
}
fun <E : Any> foo(c: Comp<in E>, e: E?) {
if (e == null) return
c.foo(e)
}
@@ -0,0 +1,9 @@
// SKIP_TXT
interface Comp<T> {
fun foo(t: T)
}
fun <E : Any> foo(c: Comp<in E>, e: E?) {
if (e == null) return
c.foo(<!DEBUG_INFO_SMARTCAST!>e<!>)
}
@@ -0,0 +1,17 @@
// FIR_IDENTICAL
// SKIP_TXT
// FILE: TaskProvider.java
public interface TaskProvider<T extends CharSequence> {
void configure(Action<? super T> a);
}
// FILE: main.kt
fun interface Action<E> {
fun E.exec()
}
fun foo(tp: TaskProvider<out CharSequence>) {
tp.configure {
length
}
}