KT-30419 Box inline classes in return types of covariant overrides

Use boxed version of an inline class in return type position for
covariant and generic-specialized overrides.

Also fixes KT-35234 and KT-31585.
This commit is contained in:
Dmitry Petrov
2020-03-30 12:41:48 +03:00
parent e44f12d7b0
commit 24b8495e00
31 changed files with 1296 additions and 68 deletions
@@ -0,0 +1,24 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
inline class X(val x: Any)
interface IFoo {
fun foo(): Any
fun bar(): X
}
class TestX : IFoo {
override fun foo(): X = X("O")
override fun bar(): X = X("K")
}
fun box(): String {
val t: IFoo = TestX()
val tFoo = t.foo()
if (tFoo !is X) {
throw AssertionError("X expected: $tFoo")
}
return (t.foo() as X).x.toString() + t.bar().x.toString()
}
@@ -0,0 +1,31 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
interface IFoo {
fun foo(): String
}
inline class ICFoo(val t: IFoo): IFoo {
override fun foo(): String = t.foo()
}
interface IBar {
fun bar(): IFoo
}
object FooOK : IFoo {
override fun foo(): String = "OK"
}
class Test : IBar {
override fun bar(): ICFoo = ICFoo(FooOK)
}
fun box(): String {
val test: IBar = Test()
val bar = test.bar()
if (bar !is ICFoo) {
throw AssertionError("bar: $bar")
}
return bar.foo()
}
@@ -0,0 +1,23 @@
// IGNORE_BACKEND_FIR: JVM_IR
inline class X(val x: Char)
interface IFoo {
fun foo(): Any
fun bar(): X
}
class TestX : IFoo {
override fun foo(): X = X('O')
override fun bar(): X = X('K')
}
fun box(): String {
val t: IFoo = TestX()
val tFoo = t.foo()
if (tFoo !is X) {
throw AssertionError("X expected: $tFoo")
}
return (t.foo() as X).x.toString() + t.bar().x.toString()
}
@@ -0,0 +1,53 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME
// IGNORE_BACKEND: JVM_IR
interface IFooList {
fun foo(): List<String>
}
interface IFooMutableList {
fun foo(): MutableList<String>
}
inline class AL(val t: MutableList<String>) : MutableList<String> {
override val size: Int get() = t.size
override fun get(index: Int): String = t.get(index)
override fun set(index: Int, element: String): String = t.set(index, element)
override fun contains(element: String): Boolean = t.contains(element)
override fun containsAll(elements: Collection<String>): Boolean = t.containsAll(elements)
override fun indexOf(element: String): Int = t.indexOf(element)
override fun isEmpty(): Boolean = t.isEmpty()
override fun iterator(): MutableIterator<String> = t.iterator()
override fun lastIndexOf(element: String): Int = t.lastIndexOf(element)
override fun add(element: String): Boolean = t.add(element)
override fun add(index: Int, element: String) = t.add(index, element)
override fun addAll(index: Int, elements: Collection<String>): Boolean = t.addAll(index, elements)
override fun addAll(elements: Collection<String>): Boolean = t.addAll(elements)
override fun listIterator(): MutableListIterator<String> = t.listIterator()
override fun listIterator(index: Int): MutableListIterator<String> = t.listIterator(index)
override fun clear() { t.clear() }
override fun remove(element: String): Boolean = t.remove(element)
override fun removeAll(elements: Collection<String>): Boolean = t.removeAll(elements)
override fun removeAt(index: Int): String = t.removeAt(index)
override fun retainAll(elements: Collection<String>): Boolean = t.retainAll(elements)
override fun subList(fromIndex: Int, toIndex: Int): MutableList<String> = t.subList(fromIndex, toIndex)
}
class Test : IFooList, IFooMutableList {
val arr = arrayListOf<String>()
override fun foo() = AL(arr)
}
fun box(): String {
val t1: IFooList = Test()
val list1 = t1.foo()
if (list1 !is AL) throw AssertionError("list1: $list1")
val t2: IFooMutableList = Test()
val list2 = t2.foo()
if (list2 !is AL) throw AssertionError("list2: $list2")
return "OK"
}
@@ -0,0 +1,40 @@
// IGNORE_BACKEND_FIR: JVM_IR
interface IQ1
interface IQ2
inline class X(val x: Any): IQ1, IQ2
interface IFoo1 {
fun foo(): IQ1
}
interface IFoo2 {
fun foo(): IQ2
}
class Test : IFoo1, IFoo2 {
override fun foo() = X("OK")
}
fun box(): String {
val t1: IFoo1 = Test()
val x1 = t1.foo()
if (x1 !is X) {
throw AssertionError("x1: X expected: $x1")
}
if (x1.x != "OK") {
throw AssertionError("x1: ${x1.x}")
}
val t2: IFoo2 = Test()
val x2 = t2.foo()
if (x2 !is X) {
throw AssertionError("x2: X expected: $x2")
}
if (x2.x != "OK") {
throw AssertionError("x2: ${x2.x}")
}
return "OK"
}
@@ -0,0 +1,24 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
inline class X(val x: Any)
interface IFoo<T> {
fun foo(): T
fun bar(): X
}
class TestX : IFoo<X> {
override fun foo(): X = X("O")
override fun bar(): X = X("K")
}
fun box(): String {
val t: IFoo<X> = TestX()
val tFoo: Any = t.foo()
if (tFoo !is X) {
throw AssertionError("X expected: $tFoo")
}
return (t.foo() as X).x.toString() + t.bar().x.toString()
}
@@ -0,0 +1,46 @@
// IGNORE_BACKEND_FIR: JVM_IR
interface GFoo<out T> {
fun foo(): T
}
interface IBar {
fun bar(): String
}
interface SFooBar : GFoo<IBar>
inline class X(val x: String) : IBar {
override fun bar(): String = x
}
class Test : SFooBar {
override fun foo() = X("OK")
}
fun box(): String {
val t1: SFooBar = Test()
val foo1 = t1.foo()
if (foo1 !is X) {
throw AssertionError("foo1: $foo1")
}
val bar1 = foo1.bar()
if (bar1 != "OK") {
throw AssertionError("bar1: $bar1")
}
val t2: GFoo<Any> = Test()
val foo2 = t2.foo()
if (foo2 !is IBar) {
throw AssertionError("foo2 !is IBar: $foo2")
}
val bar2 = foo2.bar()
if (bar2 != "OK") {
throw AssertionError("bar2: $bar2")
}
if (foo2 !is X) {
throw AssertionError("foo2 !is X: $foo2")
}
return "OK"
}
@@ -0,0 +1,21 @@
// IGNORE_BACKEND_FIR: JVM_IR
inline class X(val x: String)
interface IFoo1<T> {
fun foo(x: T): X
}
interface IFoo2 {
fun foo(x: String): X
}
class Test : IFoo1<String>, IFoo2 {
override fun foo(x: String): X = X(x)
}
fun box(): String {
val t1: IFoo1<String> = Test()
val t2: IFoo2 = Test()
return t1.foo("O").x + t2.foo("K").x
}
@@ -0,0 +1,18 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
inline class ResultOrClosed(val x: Any?)
interface A<T> {
fun foo(): T
}
class B : A<ResultOrClosed> {
override fun foo(): ResultOrClosed = ResultOrClosed("OK")
}
fun box(): String {
val foo: Any = (B() as A<ResultOrClosed>).foo()
if (foo !is ResultOrClosed) throw AssertionError("foo: $foo")
return foo.x.toString()
}
@@ -0,0 +1,24 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
inline class FieldValue(val value: String)
enum class RequestFields {
ENUM_ONE
}
data class RequestInputParameters(
private val backingMap: Map<RequestFields, FieldValue>
) : Map<RequestFields, FieldValue> by backingMap
fun box(): String {
val testMap1 = mapOf(RequestFields.ENUM_ONE to FieldValue("value1"))
val test1 = testMap1[RequestFields.ENUM_ONE]!!
if (test1.value != "value1") throw AssertionError("test1: $test1")
val testMap2 = RequestInputParameters(mapOf(RequestFields.ENUM_ONE to FieldValue("value2")))
val test2 = testMap2[RequestFields.ENUM_ONE]!!
if (test2.value != "value2") throw AssertionError("test2: $test2")
return "OK"
}
@@ -0,0 +1,19 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
inline class NumberInlineClass(val value: Double)
interface TypeAdapter<FROM, TO> {
fun decode(string: FROM): TO
}
class StringToDoubleTypeAdapter : TypeAdapter<String, NumberInlineClass> {
override fun decode(string: String) = NumberInlineClass(string.toDouble())
}
fun box(): String {
val typeAdapter = StringToDoubleTypeAdapter()
val test = typeAdapter.decode("2019")
if (test.value != 2019.0) throw AssertionError("test: $test")
return "OK"
}
@@ -0,0 +1,20 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
inline class NumberInlineClass(val value: Double)
interface TypeAdapter<FROM, TO> {
fun decode(string: FROM): TO
}
class StringToDoubleTypeAdapter : TypeAdapter<String, NumberInlineClass> {
override fun decode(string: String) = NumberInlineClass(string.toDouble())
}
fun box(): String {
val string: String? = "2019"
val typeAdapter = StringToDoubleTypeAdapter()
val test = string?.let(typeAdapter::decode)!!
if (test.value != 2019.0) throw AssertionError("test: $test")
return "OK"
}
@@ -0,0 +1,53 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
interface IQ {
fun ok(): String
}
inline class X(val t: IQ): IQ {
override fun ok(): String = t.ok()
}
interface IFoo1 {
fun foo(): Any
}
interface IFoo2 {
fun foo(): IQ
}
object OK : IQ {
override fun ok(): String = "OK"
}
class Test : IFoo1, IFoo2 {
override fun foo(): X = X(OK)
}
fun box(): String {
val t1: IFoo1 = Test()
val foo1 = t1.foo()
if (foo1 !is IQ) {
throw AssertionError("foo1 !is IQ: $foo1")
}
val ok1 = foo1.ok()
if (ok1 != "OK") {
throw AssertionError("ok1: $ok1")
}
if (foo1 !is X) {
throw AssertionError("foo1 !is X: $foo1")
}
val t2: IFoo2 = Test()
val foo2 = t2.foo()
if (foo2 !is X) {
throw AssertionError("foo2 !is X: $foo2")
}
val ok2 = foo2.ok()
if (ok2 != "OK") {
throw AssertionError("ok1: $ok2")
}
return "OK"
}
@@ -0,0 +1,53 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
interface IQ {
fun ok(): String
}
inline class X(val t: IQ): IQ {
override fun ok(): String = t.ok()
}
interface IFoo1 {
fun foo(): IQ
}
interface IFoo2 {
fun foo(): Any
}
object OK : IQ {
override fun ok(): String = "OK"
}
class Test : IFoo1, IFoo2 {
override fun foo(): X = X(OK)
}
fun box(): String {
val t1: IFoo1 = Test()
val foo1 = t1.foo()
if (foo1 !is X) {
throw AssertionError("foo1 !is X: $foo1")
}
val ok1 = foo1.ok()
if (ok1 != "OK") {
throw AssertionError("ok1: $ok1")
}
val t2: IFoo2 = Test()
val foo2 = t2.foo()
if (foo2 !is IQ) {
throw AssertionError("foo2 !is IQ: $foo2")
}
val ok2 = foo2.ok()
if (ok2 != "OK") {
throw AssertionError("ok2: $ok2")
}
if (foo2 !is X) {
throw AssertionError("foo2 !is X: $foo2")
}
return "OK"
}
@@ -0,0 +1,54 @@
// IGNORE_BACKEND_FIR: JVM_IR
interface IBase
interface IQ : IBase {
fun ok(): String
}
inline class X(val t: IQ): IQ {
override fun ok(): String = t.ok()
}
interface IFoo1 {
fun foo(): Any
}
interface IFoo2<T : IBase> {
fun foo(): T
}
object OK : IQ {
override fun ok(): String = "OK"
}
class Test : IFoo1, IFoo2<IQ> {
override fun foo(): X = X(OK)
}
fun box(): String {
val t1: IFoo1 = Test()
val foo1 = t1.foo()
if (foo1 !is IQ) {
throw AssertionError("foo1 !is IQ: $foo1")
}
val ok1 = foo1.ok()
if (ok1 != "OK") {
throw AssertionError("ok1: $ok1")
}
if (foo1 !is X) {
throw AssertionError("foo1 !is X: $foo1")
}
val t2: IFoo2<IQ> = Test()
val foo2 = t2.foo()
if (foo2 !is X) {
throw AssertionError("foo2 !is X: $foo2")
}
val ok2 = foo2.ok()
if (ok2 != "OK") {
throw AssertionError("ok1: $ok2")
}
return "OK"
}
@@ -0,0 +1,54 @@
// IGNORE_BACKEND_FIR: JVM_IR
interface IBase
interface IQ : IBase {
fun ok(): String
}
inline class X(val t: IQ): IQ {
override fun ok(): String = t.ok()
}
interface IFoo1<T : IBase> {
fun foo(): T
}
interface IFoo2 {
fun foo(): Any
}
object OK : IQ {
override fun ok(): String = "OK"
}
class Test : IFoo1<IQ>, IFoo2 {
override fun foo(): X = X(OK)
}
fun box(): String {
val t1: IFoo1<IQ> = Test()
val foo1 = t1.foo()
if (foo1 !is X) {
throw AssertionError("foo1 !is X: $foo1")
}
val ok1 = foo1.ok()
if (ok1 != "OK") {
throw AssertionError("ok1: $ok1")
}
val t2: IFoo2 = Test()
val foo2 = t2.foo()
if (foo2 !is IQ) {
throw AssertionError("foo2 !is IQ: $foo2")
}
val ok2 = foo2.ok()
if (ok2 != "OK") {
throw AssertionError("ok2: $ok2")
}
if (foo2 !is X) {
throw AssertionError("foo2 !is X: $foo2")
}
return "OK"
}
@@ -0,0 +1,37 @@
// IGNORE_BACKEND_FIR: JVM_IR
interface IFoo1<out T> {
fun foo(): T
}
interface IFoo2<out T> {
fun foo(): T
}
inline class X(val x: String)
class Test : IFoo1<X>, IFoo2<X> {
override fun foo(): X = X("OK")
}
fun box(): String {
val t1: IFoo1<Any> = Test()
val foo1 = t1.foo()
if (foo1 !is X) {
throw AssertionError("foo1 !is X: $foo1")
}
if (foo1.x != "OK") {
throw AssertionError("foo1.x != 'OK': $foo1")
}
val t2: IFoo2<Any> = Test()
val foo2 = t2.foo()
if (foo2 !is X) {
throw AssertionError("foo2 !is X: $foo2")
}
if (foo2.x != "OK") {
throw AssertionError("foo2.x != 'OK': $foo2")
}
return "OK"
}