diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 759fffebb75..4dad0e4eac1 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -21575,6 +21575,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/properties/const/constFlags.kt"); } + @TestMetadata("constInObjectWithInit.kt") + public void testConstInObjectWithInit() throws Exception { + runTest("compiler/testData/codegen/box/properties/const/constInObjectWithInit.kt"); + } + @TestMetadata("constPropertyAccessor.kt") public void testConstPropertyAccessor() throws Exception { runTest("compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt"); diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstLowering.kt index 1acdba35f4d..ed42b23eba1 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstLowering.kt @@ -13,10 +13,8 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction -import org.jetbrains.kotlin.ir.expressions.IrCall -import org.jetbrains.kotlin.ir.expressions.IrConst -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.IrGetField +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl import org.jetbrains.kotlin.ir.types.isPrimitiveType import org.jetbrains.kotlin.ir.types.isStringClassType @@ -46,21 +44,33 @@ fun IrField.constantValue(context: JvmBackendContext? = null): IrConst<*>? { class ConstLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass { override fun lower(irFile: IrFile) = irFile.transformChildrenVoid() - private fun IrExpression.lowerConstRead(field: IrField?): IrExpression? { + private fun IrExpression.lowerConstRead(receiver: IrExpression?, field: IrField?): IrExpression? { val value = field?.constantValue() ?: return null - return if (context.state.shouldInlineConstVals) + val resultExpression = if (context.state.shouldInlineConstVals) value.copyWithOffsets(startOffset, endOffset) else IrGetFieldImpl(startOffset, endOffset, field.symbol, field.type) + + return if (receiver == null || receiver.shouldDropConstReceiver()) + resultExpression + else + IrCompositeImpl( + startOffset, endOffset, resultExpression.type, null, + listOf(receiver, resultExpression) + ) } + + private fun IrExpression.shouldDropConstReceiver() = + this is IrConst<*> || this is IrGetValue || + this is IrGetObjectValue override fun visitCall(expression: IrCall): IrExpression { val function = (expression.symbol.owner as? IrSimpleFunction) ?: return super.visitCall(expression) val property = function.correspondingPropertySymbol?.owner ?: return super.visitCall(expression) // If `constantValue` is not null, `function` can only be the getter because the property is immutable. - return expression.lowerConstRead(property.backingField) ?: super.visitCall(expression) + return expression.lowerConstRead(expression.dispatchReceiver, property.backingField) ?: super.visitCall(expression) } override fun visitGetField(expression: IrGetField): IrExpression = - expression.lowerConstRead(expression.symbol.owner) ?: super.visitGetField(expression) + expression.lowerConstRead(expression.receiver, expression.symbol.owner) ?: super.visitGetField(expression) } diff --git a/compiler/testData/codegen/box/properties/const/constInObjectWithInit.kt b/compiler/testData/codegen/box/properties/const/constInObjectWithInit.kt new file mode 100644 index 00000000000..bd4bdb72755 --- /dev/null +++ b/compiler/testData/codegen/box/properties/const/constInObjectWithInit.kt @@ -0,0 +1,79 @@ +// TARGET_BACKEND: JVM +// This test checks that JVM-specific static initialization behavior is preserved in JVM_IR. + +var testObjectInit = false +var testClassCompanionInit = false +var testInterfaceCompanionInit = false + +fun use(x: Int) {} + +object TestObject { + init { + testObjectInit = true + } + const val x = 42 +} + +fun getTestObject() = TestObject + +class TestClassCompanion { + companion object { + init { + testClassCompanionInit = true + } + const val x = 42 + } +} + +fun getTestClassCompanion() = TestClassCompanion + +class TestInterfaceCompanion { + companion object { + init { + testInterfaceCompanionInit = true + } + const val x = 42 + } +} + +fun getInterfaceCompanion() = TestInterfaceCompanion + +fun box(): String { + use(TestObject.x) + if (testObjectInit) + throw Exception("use(TestObject.x)") + + use((TestObject).x) + if (testObjectInit) + throw Exception("use((TestObject).x)") + + use(getTestObject().x) + if (!testObjectInit) + throw Exception("use(getTestObject().x)") + + use(TestClassCompanion.x) + if (testClassCompanionInit) + throw Exception("use(TestClassCompanion.x)") + + use((TestClassCompanion).x) + if (testClassCompanionInit) + throw Exception("use((TestClassCompanion).x)") + + use(getTestClassCompanion().x) + if (!testClassCompanionInit) + throw Exception("use(getTestClassCompanion().x)") + + use(TestInterfaceCompanion.x) + if (testInterfaceCompanionInit) + throw Exception("use(TestInterfaceCompanion.x)") + + use((TestInterfaceCompanion).x) + if (testInterfaceCompanionInit) + throw Exception("use((TestInterfaceCompanion).x)") + + use(getInterfaceCompanion().x) + if (!testInterfaceCompanionInit) + throw Exception("use(getInterfaceCompanion().x)") + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt b/compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt index 538d1ec197f..7306a92bb07 100644 --- a/compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt +++ b/compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt @@ -1,5 +1,4 @@ -// IGNORE_BACKEND: JVM_IR, JS, JS_IR_ES6 -// IGNORE_BACKEND_FIR: JVM_IR +// IGNORE_BACKEND: JS, JS_IR_ES6 var a = 12 diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index b443c0b47d6..4c23c7115b6 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -21941,6 +21941,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/properties/const/constFlags.kt"); } + @TestMetadata("constInObjectWithInit.kt") + public void testConstInObjectWithInit() throws Exception { + runTest("compiler/testData/codegen/box/properties/const/constInObjectWithInit.kt"); + } + @TestMetadata("constPropertyAccessor.kt") public void testConstPropertyAccessor() throws Exception { runTest("compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index fde5ea803b4..4e9d7f19813 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -21941,6 +21941,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/properties/const/constFlags.kt"); } + @TestMetadata("constInObjectWithInit.kt") + public void testConstInObjectWithInit() throws Exception { + runTest("compiler/testData/codegen/box/properties/const/constInObjectWithInit.kt"); + } + @TestMetadata("constPropertyAccessor.kt") public void testConstPropertyAccessor() throws Exception { runTest("compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index b9587e1bd53..71a78e1ba65 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -21575,6 +21575,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/properties/const/constFlags.kt"); } + @TestMetadata("constInObjectWithInit.kt") + public void testConstInObjectWithInit() throws Exception { + runTest("compiler/testData/codegen/box/properties/const/constInObjectWithInit.kt"); + } + @TestMetadata("constPropertyAccessor.kt") public void testConstPropertyAccessor() throws Exception { runTest("compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt");