JVM_IR: generate non-null assertions for arguments
This commit is contained in:
@@ -23,7 +23,9 @@ import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
|
|||||||
|
|
||||||
interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
|
interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
|
||||||
object CLASS_STATIC_INITIALIZER : IrDeclarationOriginImpl("CLASS_STATIC_INITIALIZER")
|
object CLASS_STATIC_INITIALIZER : IrDeclarationOriginImpl("CLASS_STATIC_INITIALIZER")
|
||||||
object DEFAULT_IMPLS : IrDeclarationOriginImpl("DEFAULT_IMPL")
|
object DEFAULT_IMPLS : IrDeclarationOriginImpl("DEFAULT_IMPLS")
|
||||||
|
object DEFAULT_IMPLS_BRIDGE : IrDeclarationOriginImpl("DEFAULT_IMPLS_BRIDGE")
|
||||||
|
object DEFAULT_IMPLS_BRIDGE_TO_SYNTHETIC : IrDeclarationOriginImpl("DEFAULT_IMPLS_BRIDGE_TO_SYNTHETIC", isSynthetic = true)
|
||||||
object FIELD_FOR_OUTER_THIS : IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS")
|
object FIELD_FOR_OUTER_THIS : IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS")
|
||||||
object FUNCTION_REFERENCE_IMPL : IrDeclarationOriginImpl("FUNCTION_REFERENCE_IMPL")
|
object FUNCTION_REFERENCE_IMPL : IrDeclarationOriginImpl("FUNCTION_REFERENCE_IMPL")
|
||||||
object SYNTHETIC_ACCESSOR : IrDeclarationOriginImpl("SYNTHETIC_ACCESSOR", isSynthetic = true)
|
object SYNTHETIC_ACCESSOR : IrDeclarationOriginImpl("SYNTHETIC_ACCESSOR", isSynthetic = true)
|
||||||
|
|||||||
+22
@@ -156,6 +156,7 @@ class ExpressionCodegen(
|
|||||||
val startLabel = markNewLabel()
|
val startLabel = markNewLabel()
|
||||||
val info = BlockInfo()
|
val info = BlockInfo()
|
||||||
val body = irFunction.body!!
|
val body = irFunction.body!!
|
||||||
|
generateNonNullAssertions()
|
||||||
val result = body.accept(this, info)
|
val result = body.accept(this, info)
|
||||||
// If this function has an expression body, return the result of that expression.
|
// If this function has an expression body, return the result of that expression.
|
||||||
// Otherwise, if it does not end in a return statement, it must be void-returning,
|
// Otherwise, if it does not end in a return statement, it must be void-returning,
|
||||||
@@ -176,6 +177,27 @@ class ExpressionCodegen(
|
|||||||
mv.visitEnd()
|
mv.visitEnd()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun generateNonNullAssertions() {
|
||||||
|
val isSyntheticOrBridge = irFunction.origin.isSynthetic ||
|
||||||
|
// Although these are accessible from Java, the functions they bridge to already have the assertions.
|
||||||
|
irFunction.origin == IrDeclarationOrigin.BRIDGE_SPECIAL ||
|
||||||
|
irFunction.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE ||
|
||||||
|
irFunction.origin == JvmLoweredDeclarationOrigin.JVM_STATIC_WRAPPER
|
||||||
|
if (!isInlineLambda && !isSyntheticOrBridge && !Visibilities.isPrivate(irFunction.visibility)) {
|
||||||
|
irFunction.extensionReceiverParameter?.let { generateNonNullAssertion(it) }
|
||||||
|
irFunction.valueParameters.forEach(::generateNonNullAssertion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateNonNullAssertion(param: IrValueParameter) {
|
||||||
|
val asmType = param.type.asmType
|
||||||
|
if (!param.type.isNullable() && !isPrimitive(asmType)) {
|
||||||
|
mv.load(findLocalIndex(param.symbol), asmType)
|
||||||
|
mv.aconst(param.name.asString())
|
||||||
|
mv.invokestatic("kotlin/jvm/internal/Intrinsics", "checkParameterIsNotNull", "(Ljava/lang/Object;Ljava/lang/String;)V", false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun writeParameterInLocalVariableTable(startLabel: Label, endLabel: Label) {
|
private fun writeParameterInLocalVariableTable(startLabel: Label, endLabel: Label) {
|
||||||
if (!irFunction.isStatic) {
|
if (!irFunction.isStatic) {
|
||||||
mv.visitLocalVariable("this", classCodegen.type.descriptor, null, startLabel, endLabel, 0)
|
mv.visitLocalVariable("this", classCodegen.type.descriptor, null, startLabel, endLabel, 0)
|
||||||
|
|||||||
+13
-1
@@ -148,7 +148,19 @@ class JvmDeclarationFactory(
|
|||||||
createStaticFunctionWithReceivers(
|
createStaticFunctionWithReceivers(
|
||||||
defaultImpls, name, interfaceFun,
|
defaultImpls, name, interfaceFun,
|
||||||
dispatchReceiverType = parent.defaultType,
|
dispatchReceiverType = parent.defaultType,
|
||||||
origin = JvmLoweredDeclarationOrigin.DEFAULT_IMPLS
|
// If `interfaceFun` is not a real implementation, then we're generating stubs in a descendant
|
||||||
|
// interface's DefaultImpls. For example,
|
||||||
|
//
|
||||||
|
// interface I1 { fun f() { ... } }
|
||||||
|
// interface I2 : I1
|
||||||
|
//
|
||||||
|
// is supposed to allow using `I2.DefaultImpls.f` as if it was inherited from `I1.DefaultImpls`.
|
||||||
|
// The classes are not actually related and `I2.DefaultImpls.f` is not a fake override but a bridge.
|
||||||
|
origin = when {
|
||||||
|
interfaceFun.origin != IrDeclarationOrigin.FAKE_OVERRIDE -> interfaceFun.origin
|
||||||
|
interfaceFun.resolveFakeOverride()!!.origin.isSynthetic -> JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE_TO_SYNTHETIC
|
||||||
|
else -> JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -3,6 +3,10 @@
|
|||||||
// FULL_JDK
|
// FULL_JDK
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
// Bridges are not generated because their signatures would conflict. The logic
|
||||||
|
// should be inserted directly into existing methods, but this is not implemented.
|
||||||
|
// IGNORE_BACKEND: JVM_IR
|
||||||
|
|
||||||
class A : MutableMap<Any, Any?> {
|
class A : MutableMap<Any, Any?> {
|
||||||
override val entries: MutableSet<MutableMap.MutableEntry<Any, Any?>>
|
override val entries: MutableSet<MutableMap.MutableEntry<Any, Any?>>
|
||||||
get() = throw UnsupportedOperationException()
|
get() = throw UnsupportedOperationException()
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
|
||||||
// FILE: Test.java
|
// FILE: Test.java
|
||||||
|
|||||||
-1
@@ -1,5 +1,4 @@
|
|||||||
// !LANGUAGE: -NullabilityAssertionOnExtensionReceiver
|
// !LANGUAGE: -NullabilityAssertionOnExtensionReceiver
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// FILE: test.kt
|
// FILE: test.kt
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// FILE: test.kt
|
// FILE: test.kt
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|||||||
-1
@@ -1,5 +1,4 @@
|
|||||||
// !LANGUAGE: -NullabilityAssertionOnExtensionReceiver
|
// !LANGUAGE: -NullabilityAssertionOnExtensionReceiver
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// FILE: test.kt
|
// FILE: test.kt
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
// Bridges are not generated because their signatures would conflict. The logic
|
||||||
|
// should be inserted directly into existing methods, but this is not implemented.
|
||||||
|
// IGNORE_BACKEND: JVM_IR
|
||||||
|
|
||||||
private object EmptyMap : Map<Any, Nothing> {
|
private object EmptyMap : Map<Any, Nothing> {
|
||||||
override val size: Int get() = 0
|
override val size: Int get() = 0
|
||||||
override fun isEmpty(): Boolean = true
|
override fun isEmpty(): Boolean = true
|
||||||
|
|||||||
+1
@@ -1,4 +1,5 @@
|
|||||||
// !LANGUAGE: +InlineClasses
|
// !LANGUAGE: +InlineClasses
|
||||||
|
// IGNORE_BACKEND: JVM_IR
|
||||||
|
|
||||||
inline class AsAny(val a: Any?)
|
inline class AsAny(val a: Any?)
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
fun foo(s: String) = s as CharSequence
|
fun foo(s: String) = s as CharSequence
|
||||||
|
|
||||||
// 0 IFNULL
|
// 0 IFNULL
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
fun test(s: String) = s?.length
|
fun test(s: String) = s?.length
|
||||||
|
|
||||||
// 0 IFNULL
|
// 0 IFNULL
|
||||||
|
|||||||
Reference in New Issue
Block a user