Fir2Ir, JVM IR: support flexible Array types loaded from Java
We don't have true flexible types in the IR, but we approximate it with internal type annotations, such as FlexibleNullability, FlexibleMutability, RawType. These annotations are then handled specially in JvmIrTypeSystemContext, which can construct a fake flexible type so that type checker on IR types would behave exactly as on frontend types. As shown in KT-63441, one instance of flexible types where flexibility was lost during conversion to IR is Java array/vararg types. It's necessary to support it so that IR fake overrides could be constructed correctly, because IR fake override checker requires parameter types to be equal. So this change introduces another internal type annotation, FlexibleArrayElementVariance, which is only applicable to types with classifier kotlin/Array, and which signifies that the annotated type `Array<X>` should rather be seen as `Array<X>..Array<out X>`. #KT-63441 Fixed #KT-63446 Fixed
This commit is contained in:
committed by
Space Team
parent
e98902ce74
commit
ee8d42532b
@@ -0,0 +1,37 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// FILE: J.java
|
||||
|
||||
interface J {
|
||||
String foo(String[] a);
|
||||
}
|
||||
|
||||
// FILE: 1.kt
|
||||
|
||||
class Inv : J {
|
||||
override fun foo(a: Array<String>): String = a[0]
|
||||
}
|
||||
|
||||
class Out : J {
|
||||
override fun foo(a: Array<out String>): String = a[0]
|
||||
}
|
||||
|
||||
class Vararg : J {
|
||||
override fun foo(vararg a: String): String = a[0]
|
||||
}
|
||||
|
||||
class InvNullableElement : J {
|
||||
override fun foo(a: Array<String?>): String = a[0] ?: "Fail"
|
||||
}
|
||||
|
||||
class InvNullableArray : J {
|
||||
override fun foo(a: Array<String>?): String = a?.get(0) ?: "Fail"
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
if (Inv().foo(arrayOf("OK")) != "OK") return "Fail Inv"
|
||||
if (Out().foo(arrayOf("OK")) != "OK") return "Fail Out"
|
||||
if (Vararg().foo("OK") != "OK") return "Fail Vararg"
|
||||
if (InvNullableElement().foo(arrayOf("OK")) != "OK") return "Fail InvNullableElement"
|
||||
if (InvNullableArray().foo(arrayOf("OK")) != "OK") return "Fail InvNullableArray"
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// FILE: J.java
|
||||
|
||||
import java.util.List;
|
||||
|
||||
// This is a bit more elaborate version of overrideWithArrayParameterType.kt, which also checks interaction of:
|
||||
// flexible nullability, flexible mutability, raw types, varargs.
|
||||
interface J {
|
||||
List<String>[] foo(List... a);
|
||||
}
|
||||
|
||||
// FILE: 1.kt
|
||||
|
||||
class C1 : J {
|
||||
override fun foo(vararg a: MutableList<Any?>?): Array<out MutableList<String>>? = null
|
||||
}
|
||||
class C2 : J {
|
||||
override fun foo(vararg a: List<Any?>): Array<MutableList<out String>>? = null
|
||||
}
|
||||
class C3 : J {
|
||||
override fun foo(vararg a: List<*>): Array<List<String>?>? = null
|
||||
}
|
||||
class C4 : J {
|
||||
override fun foo(vararg a: MutableList<out Any?>): Array<out List<String?>>? = null
|
||||
}
|
||||
class C5 : J {
|
||||
override fun foo(a: Array<List<Any?>>): Array<MutableList<String>>? = null
|
||||
}
|
||||
class C6 : J {
|
||||
override fun foo(a: Array<out MutableList<Any?>?>): Array<out MutableList<String>>? = null
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
C1().foo()
|
||||
C2().foo()
|
||||
C3().foo()
|
||||
C4().foo()
|
||||
C5().foo(emptyArray())
|
||||
C6().foo(emptyArray())
|
||||
return "OK"
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// FILE: J.java
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
interface J {
|
||||
String foo(@NotNull String[] a);
|
||||
}
|
||||
|
||||
// FILE: 1.kt
|
||||
|
||||
class Inv : J {
|
||||
override fun foo(a: Array<String>): String = a[0]
|
||||
}
|
||||
|
||||
class Out : J {
|
||||
override fun foo(a: Array<out String>): String = a[0]
|
||||
}
|
||||
|
||||
class Vararg : J {
|
||||
override fun foo(vararg a: String): String = a[0]
|
||||
}
|
||||
|
||||
class InvNullableElement : J {
|
||||
override fun foo(a: Array<String?>): String = a[0] ?: "Fail"
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
if (Inv().foo(arrayOf("OK")) != "OK") return "Fail Inv"
|
||||
if (Out().foo(arrayOf("OK")) != "OK") return "Fail Out"
|
||||
if (Vararg().foo("OK") != "OK") return "Fail Vararg"
|
||||
if (InvNullableElement().foo(arrayOf("OK")) != "OK") return "Fail InvNullableElement"
|
||||
return "OK"
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// FILE: J.java
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface J<T> {
|
||||
String foo(T t, List<T[]> list);
|
||||
}
|
||||
|
||||
// FILE: 1.kt
|
||||
|
||||
class A
|
||||
|
||||
class C : J<A> {
|
||||
override fun foo(a: A, list: List<Array<A>>?): String = "OK"
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val c: J<A> = C()
|
||||
return c.foo(A(), null)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// FILE: J.java
|
||||
|
||||
interface J {
|
||||
String foo(String... a);
|
||||
}
|
||||
|
||||
// FILE: 1.kt
|
||||
|
||||
class Inv : J {
|
||||
override fun foo(a: Array<String>): String = a[0]
|
||||
}
|
||||
|
||||
class Out : J {
|
||||
override fun foo(a: Array<out String>): String = a[0]
|
||||
}
|
||||
|
||||
class Vararg : J {
|
||||
override fun foo(vararg a: String): String = a[0]
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
if (Inv().foo(arrayOf("OK")) != "OK") return "Fail Inv"
|
||||
if (Out().foo(arrayOf("OK")) != "OK") return "Fail Out"
|
||||
if (Vararg().foo("OK") != "OK") return "Fail Vararg"
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user