JVM_IR KT-43851 preserve static initialization order in const val read
This commit is contained in:
Generated
+5
@@ -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");
|
||||
|
||||
+18
-8
@@ -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
|
||||
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user