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.isMarkedNullable
|
||||||
import org.jetbrains.kotlin.ir.types.isPrimitiveType
|
import org.jetbrains.kotlin.ir.types.isPrimitiveType
|
||||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
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.util.resolveFakeOverride
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
@@ -180,18 +181,15 @@ class LateinitUsageLowering(val backendContext: CommonBackendContext) : BodyLowe
|
|||||||
|
|
||||||
if (!Symbols.isLateinitIsInitializedPropertyGetter(expression.symbol)) return expression
|
if (!Symbols.isLateinitIsInitializedPropertyGetter(expression.symbol)) return expression
|
||||||
|
|
||||||
val receiver = expression.extensionReceiver as IrPropertyReference
|
return expression.extensionReceiver!!.replaceTailExpression {
|
||||||
|
require(it is IrPropertyReference) { "isInitialized cannot be invoked on ${it.render()}" }
|
||||||
val property =
|
val property = it.getter?.owner?.resolveFakeOverride()?.correspondingPropertySymbol?.owner
|
||||||
receiver.getter?.owner?.resolveFakeOverride()?.correspondingPropertySymbol!!.owner.also { assert(it.isLateinit) }
|
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")
|
||||||
val nullableField =
|
// This is not the right scope symbol, but we don't use it anyway.
|
||||||
backendContext.buildOrGetNullableField(
|
backendContext.createIrBuilder(it.symbol, expression.startOffset, expression.endOffset).run {
|
||||||
property.backingField ?: error("Lateinit property is supposed to have backing field")
|
irNotEquals(irGetField(it.dispatchReceiver, backendContext.buildOrGetNullableField(backingField)), irNull())
|
||||||
)
|
}
|
||||||
|
|
||||||
return expression.run { backendContext.createIrBuilder(symbol, startOffset, endOffset) }.run {
|
|
||||||
irNotEquals(irGetField(receiver.dispatchReceiver, nullableField), irNull())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -208,9 +206,24 @@ private fun CommonBackendContext.buildOrGetNullableField(originalField: IrField)
|
|||||||
}.apply {
|
}.apply {
|
||||||
parent = originalField.parent
|
parent = originalField.parent
|
||||||
correspondingPropertySymbol = originalField.correspondingPropertySymbol
|
correspondingPropertySymbol = originalField.correspondingPropertySymbol
|
||||||
annotations += originalField.annotations
|
annotations = originalField.annotations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val IrProperty.isRealLateinit get() = isLateinit && !isFakeOverride
|
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
|
// TARGET_BACKEND: JVM
|
||||||
object Test {
|
object Test {
|
||||||
@JvmStatic
|
@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 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
|
// WITH_RUNTIME
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
object Test {
|
object Test {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
lateinit var value: Any
|
lateinit var value: String
|
||||||
|
|
||||||
val isInitialized
|
val isInitialized
|
||||||
get() = Test::value.isInitialized
|
get() = Test::value.isInitialized
|
||||||
@@ -12,12 +10,11 @@ object Test {
|
|||||||
val isInitializedThroughFn
|
val isInitializedThroughFn
|
||||||
get() = self()::value.isInitialized
|
get() = self()::value.isInitialized
|
||||||
|
|
||||||
fun self() = Test
|
fun self() = Test.apply { value = "OK" }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
if (Test.isInitialized) return "fail 1"
|
if (Test.isInitialized) return "fail 1"
|
||||||
Test.value = "OK"
|
|
||||||
if (!Test.isInitializedThroughFn) return "fail 2"
|
if (!Test.isInitializedThroughFn) return "fail 2"
|
||||||
return Test.value as String
|
return Test.value
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user