Box/unbox nullable inline class values with null check

When we have a nullable inline class value with non-null underlying
type, corresponding value in unboxed representation is nullable. E.g.:

  inline class Str(val value: String)

  fun test(s: Str?) = listOf(s)

Here 'test(s: Str?)' accepts nullable 'java.lang.String' as a parameter.

When boxing/unboxing nullable values of such inline classes, take care
of nulls.

 #KT-26052 Fixed Target versions 1.3-M2
This commit is contained in:
Dmitry Petrov
2018-08-13 12:28:01 +03:00
parent 56ad091534
commit ebf8ec455d
12 changed files with 360 additions and 1 deletions
@@ -0,0 +1,42 @@
// !LANGUAGE: +InlineClasses
// IGNORE_BACKEND: JVM_IR
class BoxT<T>(val boxed: T)
class BoxAny(val boxed: Any?)
class BoxFoo(val boxed: IFoo?)
interface IFoo
inline class Str(val value: String) : IFoo
inline class Str2(val value: Str): IFoo
inline class StrArr(val value: Array<String>): IFoo
fun boxToTypeParameter(x: Str?) = BoxT(x)
fun boxToNullableAny(x: Str?) = BoxAny(x)
fun boxToNullableInterface(x: Str?) = BoxFoo(x)
fun box2ToTypeParameter(x: Str2?) = BoxT(x)
fun box2ToNullableAny(x: Str2?) = BoxAny(x)
fun box2ToNullableInterface(x: Str2?) = BoxFoo(x)
fun boxArrToTypeParameter(x: StrArr?) = BoxT(x)
fun boxArrToNullableAny(x: StrArr?) = BoxAny(x)
fun boxArrToNullableInterface(x: StrArr?) = BoxFoo(x)
fun box(): String {
if (boxToNullableAny(null).boxed != null) throw AssertionError()
if (boxToTypeParameter(null).boxed != null) throw AssertionError()
if (boxToNullableInterface(null).boxed != null) throw AssertionError()
if (box2ToNullableAny(null).boxed != null) throw AssertionError()
if (box2ToTypeParameter(null).boxed != null) throw AssertionError()
if (box2ToNullableInterface(null).boxed != null) throw AssertionError()
if (boxArrToNullableAny(null).boxed != null) throw AssertionError()
if (boxArrToTypeParameter(null).boxed != null) throw AssertionError()
if (boxArrToNullableInterface(null).boxed != null) throw AssertionError()
return "OK"
}
@@ -0,0 +1,22 @@
// !LANGUAGE: +InlineClasses
// IGNORE_BACKEND: JVM_IR
class BoxT<T>(val boxed: T)
class BoxAny(val boxed: Any?)
class BoxFoo(val boxed: IFoo?)
interface IFoo
inline class I32(val value: Int): IFoo
fun boxToTypeParameter(x: I32?) = BoxT(x)
fun boxToNullableAny(x: I32?) = BoxAny(x)
fun boxToNullableInterface(x: I32?) = BoxFoo(x)
fun box(): String {
if (boxToNullableAny(null).boxed != null) throw AssertionError()
if (boxToTypeParameter(null).boxed != null) throw AssertionError()
if (boxToNullableInterface(null).boxed != null) throw AssertionError()
return "OK"
}
@@ -0,0 +1,46 @@
// !LANGUAGE: +InlineClasses
// WITH_RUNTIME
// IGNORE_BACKEND: JVM_IR, JS_IR
inline class X(val x: String)
inline class Y(val y: Number)
inline class NX(val x: String?)
inline class NY(val y: Number?)
fun testNotNull(x: X?, y: Y?) {
val xs = listOf<Any?>(x)
val ys = listOf<Any?>(y)
if (!xs.contains(y)) throw AssertionError()
if (xs[0] != ys[0]) throw AssertionError()
if (xs[0] !== ys[0]) throw AssertionError()
}
fun testNullable(x: NX?, y: NY?) {
val xs = listOf<Any?>(x)
val ys = listOf<Any?>(y)
if (xs.contains(y)) throw AssertionError()
if (xs[0] == ys[0]) throw AssertionError()
if (xs[0] === ys[0]) throw AssertionError()
}
fun testNullsAsNullable(x: NX?, y: NY?) {
val xs = listOf<Any?>(x)
val ys = listOf<Any?>(y)
if (!xs.contains(y)) throw AssertionError()
if (xs[0] != ys[0]) throw AssertionError()
if (xs[0] !== ys[0]) throw AssertionError()
}
fun box(): String {
testNotNull(null, null)
testNullable(NX(null), NY(null))
testNullable(NX(null), null)
testNullable(null, NY(null))
testNullsAsNullable(null, null)
return "OK"
}
@@ -1,5 +1,5 @@
// !LANGUAGE: +InlineClasses
// IGNORE_BACKEND: JVM_IR, JS_IR, JS
// IGNORE_BACKEND: JVM_IR, JS
inline class Z(val value: Int)
@@ -0,0 +1,54 @@
// !LANGUAGE: +InlineClasses
// IGNORE_BACKEND: JVM_IR
class BoxT<T>(val boxed: T)
class BoxAny(val boxed: Any?)
class BoxFoo(val boxed: IFoo?)
interface IFoo
inline class Str(val value: String) : IFoo
inline class Str2(val value: Str): IFoo
inline class StrArr(val value: Array<String>): IFoo
fun boxToTypeParameter(x: Str?) = BoxT(x)
fun boxToNullableAny(x: Str?) = BoxAny(x)
fun boxToNullableInterface(x: Str?) = BoxFoo(x)
fun box2ToTypeParameter(x: Str2?) = BoxT(x)
fun box2ToNullableAny(x: Str2?) = BoxAny(x)
fun box2ToNullableInterface(x: Str2?) = BoxFoo(x)
fun boxArrToTypeParameter(x: StrArr?) = BoxT(x)
fun boxArrToNullableAny(x: StrArr?) = BoxAny(x)
fun boxArrToNullableInterface(x: StrArr?) = BoxFoo(x)
fun useNullableStr(x: Str?) {
if (x != null) throw AssertionError()
}
fun useNullableStr2(x: Str2?) {
if (x != null) throw AssertionError()
}
fun useNullableStrArr(x: StrArr?) {
if (x != null) throw AssertionError()
}
fun box(): String {
useNullableStr(boxToTypeParameter(null).boxed)
useNullableStr(boxToNullableAny(null).boxed as Str?)
useNullableStr(boxToNullableInterface(null).boxed as Str?)
useNullableStr2(box2ToTypeParameter(null).boxed)
useNullableStr2(box2ToNullableAny(null).boxed as Str2?)
useNullableStr2(box2ToNullableInterface(null).boxed as Str2?)
useNullableStrArr(boxArrToTypeParameter(null).boxed)
useNullableStrArr(boxArrToNullableAny(null).boxed as StrArr?)
useNullableStrArr(boxArrToNullableInterface(null).boxed as StrArr?)
return "OK"
}
@@ -0,0 +1,26 @@
// !LANGUAGE: +InlineClasses
// IGNORE_BACKEND: JVM_IR
class BoxT<T>(val boxed: T)
class BoxAny(val boxed: Any?)
class BoxFoo(val boxed: IFoo?)
interface IFoo
inline class I32(val value: Int) : IFoo
fun boxToTypeParameter(x: I32?) = BoxT(x)
fun boxToNullableAny(x: I32?) = BoxAny(x)
fun boxToNullableInterface(x: I32?) = BoxFoo(x)
fun useNullableI32(x: I32?) {
if (x != null) throw AssertionError()
}
fun box(): String {
useNullableI32(boxToTypeParameter(null).boxed)
useNullableI32(boxToNullableAny(null).boxed as I32?)
useNullableI32(boxToNullableInterface(null).boxed as I32?)
return "OK"
}