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 20674d12e13..759fffebb75 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("constPropertyAccessor.kt") + public void testConstPropertyAccessor() throws Exception { + runTest("compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt"); + } + @TestMetadata("constValInAnnotationDefault.kt") public void testConstValInAnnotationDefault() throws Exception { runTest("compiler/testData/codegen/box/properties/const/constValInAnnotationDefault.kt"); diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/optimizations/PropertyAccessorInlineLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/optimizations/PropertyAccessorInlineLowering.kt index d48efb021e9..dea400679fc 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/optimizations/PropertyAccessorInlineLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/optimizations/PropertyAccessorInlineLowering.kt @@ -8,6 +8,8 @@ package org.jetbrains.kotlin.backend.common.lower.optimizations import org.jetbrains.kotlin.backend.common.BodyLoweringPass import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.ir.isTopLevel +import org.jetbrains.kotlin.backend.common.lower.createIrBuilder +import org.jetbrains.kotlin.backend.common.lower.irBlock import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.ir.declarations.* @@ -16,6 +18,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols import org.jetbrains.kotlin.ir.util.isEffectivelyExternal +import org.jetbrains.kotlin.ir.util.isPure import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid @@ -46,13 +49,25 @@ class PropertyAccessorInlineLowering(private val context: CommonBackendContext) } if (property.isEffectivelyExternal()) return expression + val backingField = property.backingField ?: return expression + if (property.isConst) { val initializer = - (property.backingField?.initializer ?: error("Constant property has to have a backing field with initializer")) - return initializer.expression.deepCopyWithSymbols() + (backingField.initializer ?: error("Constant property has to have a backing field with initializer")) + val constExpression = initializer.expression.deepCopyWithSymbols() + val receiver = expression.dispatchReceiver + if (receiver != null && !receiver.isPure(true)) { + val builder = context.createIrBuilder(expression.symbol, + expression.startOffset, expression.endOffset) + return builder.irBlock(expression) { + +receiver + +constExpression + } + } + return constExpression } - val backingField = property.backingField ?: return expression + if (property.getter === callee) { return tryInlineSimpleGetter(expression, callee, backingField) ?: expression diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt index dec10d32c08..fb41a8dc6c1 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt @@ -14,7 +14,7 @@ import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder -import org.jetbrains.kotlin.ir.backend.js.utils.isPure +import org.jetbrains.kotlin.ir.util.isPure import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PropertyLazyInitLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PropertyLazyInitLowering.kt index 3b186528117..23ef4a638dc 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PropertyLazyInitLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PropertyLazyInitLowering.kt @@ -14,7 +14,7 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.ir.JsIrArithBuilder import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder -import org.jetbrains.kotlin.ir.backend.js.utils.isPure +import org.jetbrains.kotlin.ir.util.isPure import org.jetbrains.kotlin.ir.builders.declarations.addFunction import org.jetbrains.kotlin.ir.builders.declarations.buildField import org.jetbrains.kotlin.ir.declarations.* diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt index 6d4a87f077f..314ad29428b 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.ir.JsIrArithBuilder import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder -import org.jetbrains.kotlin.ir.backend.js.utils.isPure +import org.jetbrains.kotlin.ir.util.isPure import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/cleanup/CleanupLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/cleanup/CleanupLowering.kt index caae71e2b23..4311218d931 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/cleanup/CleanupLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/cleanup/CleanupLowering.kt @@ -8,7 +8,7 @@ package org.jetbrains.kotlin.ir.backend.js.lower.cleanup import org.jetbrains.kotlin.backend.common.BodyLoweringPass import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement -import org.jetbrains.kotlin.ir.backend.js.utils.isPure +import org.jetbrains.kotlin.ir.util.isPure import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.types.isNothing diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/StateMachineBuilder.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/StateMachineBuilder.kt index 2f550983b31..b4f60caf748 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/StateMachineBuilder.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/StateMachineBuilder.kt @@ -15,7 +15,7 @@ import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder -import org.jetbrains.kotlin.ir.backend.js.utils.isPure +import org.jetbrains.kotlin.ir.util.isPure import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.expressions.* diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt index ec756c0aba6..f80c95eb6cf 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt @@ -64,41 +64,6 @@ fun List.toJsArrayLiteral(context: JsIrBackendContext, arrayType: } } -// TODO: support more cases like built-in operator call and so on - -fun IrExpression?.isPure(anyVariable: Boolean, checkFields: Boolean = true): Boolean { - if (this == null) return true - - fun IrExpression.isPureImpl(): Boolean { - return when (this) { - is IrConst<*> -> true - is IrGetValue -> { - if (anyVariable) return true - val valueDeclaration = symbol.owner - if (valueDeclaration is IrVariable) !valueDeclaration.isVar - else true - } - is IrGetObjectValue -> type.isUnit() - else -> false - } - } - - if (isPureImpl()) return true - - if (!checkFields) return false - - if (this is IrGetField) { - if (!symbol.owner.isFinal) { - if (!anyVariable) { - return false - } - } - return receiver.isPure(anyVariable) - } - - return false -} - val IrValueDeclaration.isDispatchReceiver: Boolean get() { val parent = this.parent diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmTypeOperatorLowering.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmTypeOperatorLowering.kt index d567cbb98ef..d050028358f 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmTypeOperatorLowering.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmTypeOperatorLowering.kt @@ -13,7 +13,7 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irNot import org.jetbrains.kotlin.backend.wasm.WasmBackendContext import org.jetbrains.kotlin.backend.wasm.ir2wasm.erasedUpperBound -import org.jetbrains.kotlin.ir.backend.js.utils.isPure +import org.jetbrains.kotlin.ir.util.isPure import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrTypeParameter diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index 2d65573733f..d9c8cc74742 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -570,3 +570,38 @@ val IrFunction.originalFunction: IrFunction val IrProperty.originalProperty: IrProperty get() = attributeOwnerId as? IrProperty ?: this + +// TODO: support more cases like built-in operator call and so on + +fun IrExpression?.isPure(anyVariable: Boolean, checkFields: Boolean = true): Boolean { + if (this == null) return true + + fun IrExpression.isPureImpl(): Boolean { + return when (this) { + is IrConst<*> -> true + is IrGetValue -> { + if (anyVariable) return true + val valueDeclaration = symbol.owner + if (valueDeclaration is IrVariable) !valueDeclaration.isVar + else true + } + is IrGetObjectValue -> type.isUnit() + else -> false + } + } + + if (isPureImpl()) return true + + if (!checkFields) return false + + if (this is IrGetField) { + if (!symbol.owner.isFinal) { + if (!anyVariable) { + return false + } + } + return receiver.isPure(anyVariable) + } + + return false +} diff --git a/compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt b/compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt new file mode 100644 index 00000000000..538d1ec197f --- /dev/null +++ b/compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt @@ -0,0 +1,22 @@ +// IGNORE_BACKEND: JVM_IR, JS, JS_IR_ES6 +// IGNORE_BACKEND_FIR: JVM_IR + +var a = 12 + +object C { + const val x = 42 +} + +fun getC(): C { + a = 123 + return C +} + +fun box(): String { + val field = getC().x + val expectedResult = 123 + if (a == expectedResult) + return "OK" + else + return "FAIL" +} diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 3bdffdca101..b443c0b47d6 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("constPropertyAccessor.kt") + public void testConstPropertyAccessor() throws Exception { + runTest("compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt"); + } + @TestMetadata("constValInAnnotationDefault.kt") public void testConstValInAnnotationDefault() throws Exception { runTest("compiler/testData/codegen/box/properties/const/constValInAnnotationDefault.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 488e065ea32..fde5ea803b4 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("constPropertyAccessor.kt") + public void testConstPropertyAccessor() throws Exception { + runTest("compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt"); + } + @TestMetadata("constValInAnnotationDefault.kt") public void testConstValInAnnotationDefault() throws Exception { runTest("compiler/testData/codegen/box/properties/const/constValInAnnotationDefault.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 f0f0882d326..b9587e1bd53 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("constPropertyAccessor.kt") + public void testConstPropertyAccessor() throws Exception { + runTest("compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt"); + } + @TestMetadata("constValInAnnotationDefault.kt") public void testConstValInAnnotationDefault() throws Exception { runTest("compiler/testData/codegen/box/properties/const/constValInAnnotationDefault.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index 16c667b847c..e3bbbe9f8fc 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -17735,6 +17735,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes public void testAnotherFile() throws Exception { runTest("compiler/testData/codegen/box/properties/const/anotherFile.kt"); } + + @TestMetadata("constPropertyAccessor.kt") + public void testConstPropertyAccessor() throws Exception { + runTest("compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt"); + } } @TestMetadata("compiler/testData/codegen/box/properties/lateinit") diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 50ce36ce3e7..3ab7141df36 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -17735,6 +17735,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { public void testAnotherFile() throws Exception { runTest("compiler/testData/codegen/box/properties/const/anotherFile.kt"); } + + @TestMetadata("constPropertyAccessor.kt") + public void testConstPropertyAccessor() throws Exception { + runTest("compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt"); + } } @TestMetadata("compiler/testData/codegen/box/properties/lateinit") diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index eb23ac83c59..dac1e1b5e89 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -17825,6 +17825,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { public void testAnotherFile() throws Exception { runTest("compiler/testData/codegen/box/properties/const/anotherFile.kt"); } + + @TestMetadata("constPropertyAccessor.kt") + public void testConstPropertyAccessor() throws Exception { + runTest("compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt"); + } } @TestMetadata("compiler/testData/codegen/box/properties/lateinit") diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 99bde8de4b9..0cb5cf7cafa 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -11216,6 +11216,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest public void testAnotherFile() throws Exception { runTest("compiler/testData/codegen/box/properties/const/anotherFile.kt"); } + + @TestMetadata("constPropertyAccessor.kt") + public void testConstPropertyAccessor() throws Exception { + runTest("compiler/testData/codegen/box/properties/const/constPropertyAccessor.kt"); + } } @TestMetadata("compiler/testData/codegen/box/properties/lateinit")