JVM_IR: support @JvmStatic transformations in LateinitLowering
#KT-46759 Fixed
This commit is contained in:
+26
-13
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrSetValueImpl
|
||||
import org.jetbrains.kotlin.ir.types.isMarkedNullable
|
||||
import org.jetbrains.kotlin.ir.types.isPrimitiveType
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
@@ -180,18 +181,15 @@ class LateinitUsageLowering(val backendContext: CommonBackendContext) : BodyLowe
|
||||
|
||||
if (!Symbols.isLateinitIsInitializedPropertyGetter(expression.symbol)) return expression
|
||||
|
||||
val receiver = expression.extensionReceiver as IrPropertyReference
|
||||
|
||||
val property =
|
||||
receiver.getter?.owner?.resolveFakeOverride()?.correspondingPropertySymbol!!.owner.also { assert(it.isLateinit) }
|
||||
|
||||
val nullableField =
|
||||
backendContext.buildOrGetNullableField(
|
||||
property.backingField ?: error("Lateinit property is supposed to have backing field")
|
||||
)
|
||||
|
||||
return expression.run { backendContext.createIrBuilder(symbol, startOffset, endOffset) }.run {
|
||||
irNotEquals(irGetField(receiver.dispatchReceiver, nullableField), irNull())
|
||||
return expression.extensionReceiver!!.replaceTailExpression {
|
||||
require(it is IrPropertyReference) { "isInitialized cannot be invoked on ${it.render()}" }
|
||||
val property = it.getter?.owner?.resolveFakeOverride()?.correspondingPropertySymbol?.owner
|
||||
require(property?.isLateinit == true) { "isInitialized invoked on non-lateinit property ${property?.render()}" }
|
||||
val backingField = property?.backingField ?: error("Lateinit property is supposed to have a backing field")
|
||||
// This is not the right scope symbol, but we don't use it anyway.
|
||||
backendContext.createIrBuilder(it.symbol, expression.startOffset, expression.endOffset).run {
|
||||
irNotEquals(irGetField(it.dispatchReceiver, backendContext.buildOrGetNullableField(backingField)), irNull())
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -208,9 +206,24 @@ private fun CommonBackendContext.buildOrGetNullableField(originalField: IrField)
|
||||
}.apply {
|
||||
parent = originalField.parent
|
||||
correspondingPropertySymbol = originalField.correspondingPropertySymbol
|
||||
annotations += originalField.annotations
|
||||
annotations = originalField.annotations
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val IrProperty.isRealLateinit get() = isLateinit && !isFakeOverride
|
||||
|
||||
private inline fun IrExpression.replaceTailExpression(crossinline transform: (IrExpression) -> IrExpression): IrExpression {
|
||||
var current = this
|
||||
var block: IrContainerExpression? = null
|
||||
while (current is IrContainerExpression) {
|
||||
block = current
|
||||
current = current.statements.last() as IrExpression
|
||||
}
|
||||
current = transform(current)
|
||||
if (block == null) {
|
||||
return current
|
||||
}
|
||||
block.statements[block.statements.size - 1] = current
|
||||
return this
|
||||
}
|
||||
|
||||
+5
-3
@@ -2,11 +2,13 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
object Test {
|
||||
@JvmStatic
|
||||
fun foo(x: String, y: String = "") = x + y
|
||||
fun foo(x: String, y: String = "") = x + value
|
||||
|
||||
var value = ""
|
||||
}
|
||||
|
||||
fun callFoo(f: (String) -> String, value: String) = f(value)
|
||||
|
||||
fun test() = Test
|
||||
fun test() = Test.apply { value = "K" }
|
||||
|
||||
fun box() = callFoo(Test::foo, "O") + callFoo(test()::foo, "K")
|
||||
fun box() = callFoo(Test::foo, "O") + callFoo(test()::foo, "")
|
||||
|
||||
Vendored
+4
-7
@@ -1,10 +1,8 @@
|
||||
// WITH_RUNTIME
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
object Test {
|
||||
@JvmStatic
|
||||
lateinit var value: Any
|
||||
lateinit var value: String
|
||||
|
||||
val isInitialized
|
||||
get() = Test::value.isInitialized
|
||||
@@ -12,12 +10,11 @@ object Test {
|
||||
val isInitializedThroughFn
|
||||
get() = self()::value.isInitialized
|
||||
|
||||
fun self() = Test
|
||||
fun self() = Test.apply { value = "OK" }
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
if (Test.isInitialized) return "fail 1"
|
||||
Test.value = "OK"
|
||||
if (!Test.isInitializedThroughFn) return "fail 2"
|
||||
return Test.value as String
|
||||
}
|
||||
return Test.value
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user