[IR] Fix saving function calls during inlining const properties in PropertyAccessorInlineLowering (#3971)

This commit is contained in:
LepilkinaElena
2020-12-10 12:24:23 +03:00
committed by GitHub
parent dccfb33bcc
commit c8c83c04c0
18 changed files with 121 additions and 44 deletions
@@ -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");
@@ -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
@@ -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.*
@@ -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.*
@@ -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
@@ -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
@@ -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.*
@@ -64,41 +64,6 @@ fun List<IrExpression>.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
@@ -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
@@ -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
}
@@ -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"
}
@@ -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");
@@ -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");
@@ -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");
@@ -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")
@@ -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")
@@ -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")
@@ -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")