JVM_IR KT-43851 preserve static initialization order in const val read

This commit is contained in:
Dmitry Petrov
2020-12-10 15:43:36 +03:00
parent b0ef6ee1fc
commit 5be28520fc
7 changed files with 118 additions and 10 deletions
@@ -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");
@@ -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)
}
@@ -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"
}
@@ -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
@@ -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");
@@ -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");
@@ -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");