From b2ef854aa1b59c2cfecaab2bc8acc6a97a32d9b1 Mon Sep 17 00:00:00 2001 From: pyos Date: Wed, 19 May 2021 10:16:26 +0200 Subject: [PATCH] JVM_IR: support @JvmStatic transformations in LateinitLowering #KT-46759 Fixed --- .../backend/common/lower/LateinitLowering.kt | 39 ++++++++++++------- .../adaptedReferences/jvmStatic.kt | 8 ++-- .../isInitializedAndDeinitialize/jvmStatic.kt | 11 ++---- 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LateinitLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LateinitLowering.kt index 3239b43cd0e..8dcaee0c600 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LateinitLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LateinitLowering.kt @@ -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 +} diff --git a/compiler/testData/codegen/box/callableReference/adaptedReferences/jvmStatic.kt b/compiler/testData/codegen/box/callableReference/adaptedReferences/jvmStatic.kt index d3bbb65eda6..eca9a0bd901 100644 --- a/compiler/testData/codegen/box/callableReference/adaptedReferences/jvmStatic.kt +++ b/compiler/testData/codegen/box/callableReference/adaptedReferences/jvmStatic.kt @@ -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, "") diff --git a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/jvmStatic.kt b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/jvmStatic.kt index 030de8b1b94..40b3ce7052b 100644 --- a/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/jvmStatic.kt +++ b/compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/jvmStatic.kt @@ -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 -} \ No newline at end of file + return Test.value +}