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 {
|
||||
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 FUNCTION_REFERENCE_IMPL : IrDeclarationOriginImpl("FUNCTION_REFERENCE_IMPL")
|
||||
object SYNTHETIC_ACCESSOR : IrDeclarationOriginImpl("SYNTHETIC_ACCESSOR", isSynthetic = true)
|
||||
|
||||
+22
@@ -156,6 +156,7 @@ class ExpressionCodegen(
|
||||
val startLabel = markNewLabel()
|
||||
val info = BlockInfo()
|
||||
val body = irFunction.body!!
|
||||
generateNonNullAssertions()
|
||||
val result = body.accept(this, info)
|
||||
// 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,
|
||||
@@ -176,6 +177,27 @@ class ExpressionCodegen(
|
||||
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) {
|
||||
if (!irFunction.isStatic) {
|
||||
mv.visitLocalVariable("this", classCodegen.type.descriptor, null, startLabel, endLabel, 0)
|
||||
|
||||
+13
-1
@@ -148,7 +148,19 @@ class JvmDeclarationFactory(
|
||||
createStaticFunctionWithReceivers(
|
||||
defaultImpls, name, interfaceFun,
|
||||
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
|
||||
// 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?> {
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<Any, Any?>>
|
||||
get() = throw UnsupportedOperationException()
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// FILE: Test.java
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
// !LANGUAGE: -NullabilityAssertionOnExtensionReceiver
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// FILE: test.kt
|
||||
// WITH_RUNTIME
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// FILE: test.kt
|
||||
// WITH_RUNTIME
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
// !LANGUAGE: -NullabilityAssertionOnExtensionReceiver
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// 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> {
|
||||
override val size: Int get() = 0
|
||||
override fun isEmpty(): Boolean = true
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
inline class AsAny(val a: Any?)
|
||||
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
fun foo(s: String) = s as CharSequence
|
||||
|
||||
// 0 IFNULL
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
fun test(s: String) = s?.length
|
||||
|
||||
// 0 IFNULL
|
||||
|
||||
Reference in New Issue
Block a user