K2: Rework scopes for types with projection arguments for Out types

The only case when behavior is change is described at
 computeNonTrivialTypeArgumentForScopeSubstitutor

The idea is to avoid depending on the presence of @UnsafeVariance
and instead approximate captured types in covariant argument positions
before building substitution scopes

It's correct because for Captured(*) <: Supertype,
Out<Captured(*)> <: Out<Supertype> and when we've got @UnsafeVariance
value parameters at Out, it's ok to allow passing Supertype there.

^KT-57602 Fixed
^KT-54894 Fixed
This commit is contained in:
Denis.Zharkov
2023-03-24 17:21:03 +01:00
committed by Space Team
parent 1cd040fd6a
commit 55a58e54fe
25 changed files with 300 additions and 79 deletions
@@ -1,11 +0,0 @@
class Foo<out T>(val baz: Baz<T>)
class Bar {
val foo: Foo<*> = TODO()
fun <T> bar(): Baz<T> {
return <!RETURN_TYPE_MISMATCH!>foo.baz<!>
}
}
typealias Baz<T> = (@UnsafeVariance T) -> Unit
@@ -1,3 +1,5 @@
// FIR_IDENTICAL
// ISSUE: KT-54894
class Foo<out T>(val baz: Baz<T>)
class Bar {
@@ -25,7 +25,7 @@ fun main() {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function1<kotlin.Nothing, kotlin.Unit>")!>getTag3().action<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function1<kotlin.Nothing, kotlin.Unit>")!>getTag4().action<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function1<kotlin.Nothing, kotlin.Any?>")!>getTag5().action<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function1<kotlin.Nothing, kotlin.Unit>")!>getTag6().action<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function1<kotlin.Nothing, kotlin.Unit>")!>getTag7().action<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function1<kotlin.Nothing, kotlin.Any?>")!>getTag8().action<!>
<!DEBUG_INFO_EXPRESSION_TYPE("Action<in kotlin.Any?>")!>getTag6().action<!>
<!DEBUG_INFO_EXPRESSION_TYPE("Action<kotlin.Any?>")!>getTag7().action<!>
<!DEBUG_INFO_EXPRESSION_TYPE("Action2<kotlin.Any?>")!>getTag8().action<!>
}
@@ -0,0 +1,13 @@
// ISSUE: KT-54764
data class Out<out T>(val prop: T)
fun foo(b: Out<*>) {
b.copy("") // error in K1, OK in K2
}
fun foo(a: Any) {
if (a is Out<*>) {
a.copy("")
}
}
@@ -0,0 +1,13 @@
// ISSUE: KT-54764
data class Out<out T>(val prop: T)
fun foo(b: Out<*>) {
b.copy(<!TYPE_MISMATCH!>""<!>) // error in K1, OK in K2
}
fun foo(a: Any) {
if (a is Out<*>) {
<!DEBUG_INFO_SMARTCAST!>a<!>.copy("")
}
}
@@ -0,0 +1,13 @@
// ISSUE: KT-54764
interface A<out T : B<F, E>, F, out E : B<T, F>> {
fun copy(t: @UnsafeVariance T, f: F, e: @UnsafeVariance E): A<T, F, E>
}
interface B<out X, out Y>
fun foo(a: A<*, String, B<*, String>>, b1: B<*, String>, b2: B<*, *>, b3: B<String, B<*, String>>) {
<!DEBUG_INFO_EXPRESSION_TYPE("A<B<kotlin.String, B<*, kotlin.String>>, kotlin.String, B<*, kotlin.String>>")!>a.copy(<!ARGUMENT_TYPE_MISMATCH!>b2<!>, "", b1)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("A<B<kotlin.String, B<*, kotlin.String>>, kotlin.String, B<*, kotlin.String>>")!>a.copy(<!ARGUMENT_TYPE_MISMATCH!>b1<!>, "", b1)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("A<B<kotlin.String, B<*, kotlin.String>>, kotlin.String, B<*, kotlin.String>>")!>a.copy(b3, "", b1)<!>
}
@@ -0,0 +1,13 @@
// ISSUE: KT-54764
interface A<out T : B<F, E>, F, out E : B<T, F>> {
fun copy(t: @UnsafeVariance T, f: F, e: @UnsafeVariance E): A<T, F, E>
}
interface B<out X, out Y>
fun foo(a: A<*, String, B<*, String>>, b1: B<*, String>, b2: B<*, *>, b3: B<String, B<*, String>>) {
<!DEBUG_INFO_EXPRESSION_TYPE("A<B<*, *>, kotlin.String, B<kotlin.Any?, kotlin.String>>")!>a.copy(b2, "", b1)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("A<B<*, *>, kotlin.String, B<kotlin.Any?, kotlin.String>>")!>a.copy(b1, "", b1)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("A<B<*, *>, kotlin.String, B<kotlin.Any?, kotlin.String>>")!>a.copy(b3, "", b1)<!>
}
@@ -0,0 +1,32 @@
// FIR_IDENTICAL
// ISSUE: KT-54764
interface Out1<out T> {
fun copy(t: @UnsafeVariance T): Out1<T>
}
fun foo1(o1: Out1<*>, o2: Out1<<!REDUNDANT_PROJECTION!>out<!> Any?>, o3: Out1<Any?>) {
<!DEBUG_INFO_EXPRESSION_TYPE("Out1<kotlin.Any?>")!>o1.copy("")<!>
<!DEBUG_INFO_EXPRESSION_TYPE("Out1<kotlin.Any?>")!>o2.copy("")<!>
<!DEBUG_INFO_EXPRESSION_TYPE("Out1<kotlin.Any?>")!>o3.copy("")<!>
}
interface Out2<out T : CharSequence> {
fun copy(t: @UnsafeVariance T): Out2<T>
}
fun foo2(o1: Out2<*>, o2: Out2<<!REDUNDANT_PROJECTION!>out<!> CharSequence>, o3: Out2<CharSequence>) {
<!DEBUG_INFO_EXPRESSION_TYPE("Out2<kotlin.CharSequence>")!>o1.copy("")<!>
<!DEBUG_INFO_EXPRESSION_TYPE("Out2<kotlin.CharSequence>")!>o2.copy("")<!>
<!DEBUG_INFO_EXPRESSION_TYPE("Out2<kotlin.CharSequence>")!>o3.copy("")<!>
}
interface Out3<out T : Out3<T>> {
fun copy(t: @UnsafeVariance T): Out3<T>
}
fun foo3(o1: Out3<*>, o2: Out3<<!REDUNDANT_PROJECTION!>out<!> Out3<*>>, o3: Out3<Out3<*>>) {
<!DEBUG_INFO_EXPRESSION_TYPE("Out3<Out3<*>>")!>o1.copy(o1)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("Out3<Out3<*>>")!>o2.copy(o1)<!>
<!DEBUG_INFO_EXPRESSION_TYPE("Out3<Out3<*>>")!>o3.copy(o1)<!>
}
@@ -99,5 +99,5 @@ FILE fqName:<root> fileName:/typeAliasWithUnsafeVariance.kt
FUN name:doAction visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
CALL 'public final fun <get-action> (): kotlin.Function1<RenderingT of <root>.Tag, kotlin.Unit> declared in <root>.Tag' type=kotlin.Function1<kotlin.Nothing, kotlin.Unit> origin=GET_PROPERTY
CALL 'public final fun <get-action> (): kotlin.Function1<RenderingT of <root>.Tag, kotlin.Unit> declared in <root>.Tag' type=kotlin.Function1<kotlin.Any?, kotlin.Unit> origin=GET_PROPERTY
$this: CALL 'public final fun getTag (): <root>.Tag<*> declared in <root>' type=<root>.Tag<*> origin=null