TL;DR具有具体类型的函数在生成代码时是否应该考虑类型参数的可空性?
测试用例
考虑以下 Kotlin 代码;这两种方法之间的唯一区别是类型绑定是否可以为空 ( Any?
) 或不可为 ( Any
)。
@Test
fun testNonNullableBound() {
val x: Int = nonNullableBound()
}
@Test
fun testNullableBound() {
val x: Int = nullableBound()
}
private inline fun <reified T : Any> nonNullableBound(): T {
return unsafeMethod()
}
private inline fun <reified T : Any?> nullableBound(): T {
return unsafeMethod()
}
whereunsafeMethod
通过在 Java 中定义来颠覆类型系统:
public static <T> T unsafeMethod() { return null; }
这是 Kotlin 1.1.4。
预期行为
我希望这些行为等效-类型已被具体化,因此T
已知的实际值不可为空,因此应该在return
语句之前在函数内部应用空检查。
观察到的行为
这两种情况以不同的方式失败:
testNonNullableBound
行为符合预期(由于对返回的值进行空检查而失败unsafeMethod()
)。testNullableBound
未按预期运行 - 分配给x
.
所以看起来空检查的插入是基于类型绑定的,而不是实际类型。
分析
供参考,相关字节码如下。注意添加的空检查testNonNullableBound
。
testNonNullableBound
public final testNonNullableBound()V
@Lorg/junit/Test;()
[...]
L1
LINENUMBER 28 L1
INVOKESTATIC JavaStuff.unsafeMethod ()Ljava/lang/Object;
DUP
LDC "unsafeMethod()"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkExpressionValueIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
[...]
testNullableBound
public final testNullableBound()V
@Lorg/junit/Test;()
[...]
L1
LINENUMBER 27 L1
INVOKESTATIC JavaStuff.unsafeMethod ()Ljava/lang/Object;
[...]