diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt index 75460a7c4ef..9b1d136ba28 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt @@ -51,14 +51,21 @@ abstract class InitializersLoweringBase(open val context: CommonBackendContext) irClass.declarations.removeAll { it is IrAnonymousInitializer && filter(it) } } + protected open fun shouldEraseFieldInitializer(irField: IrField): Boolean = true + private fun handleField(irClass: IrClass, declaration: IrField): IrStatement? = declaration.initializer?.run { val receiver = if (!declaration.isStatic) // TODO isStaticField IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol) else null - declaration.initializer = null - IrSetFieldImpl(startOffset, endOffset, declaration.symbol, receiver, expression, context.irBuiltIns.unitType) + val value = if (shouldEraseFieldInitializer(declaration)) { + declaration.initializer = null + expression + } else { + expression.deepCopyWithSymbols() + } + IrSetFieldImpl(startOffset, endOffset, declaration.symbol, receiver, value, context.irBuiltIns.unitType) } private fun handleAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement = diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 79eca13b695..f095cd0eb1f 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -173,8 +173,13 @@ private val staticInitializersPhase = makeIrFilePhase( description = "Move code from object init blocks and static field initializers to a new function" ) -private val initializersPhase = makeIrFilePhase( - ::InitializersLowering, +private val initializersPhase = makeIrFilePhase( + { context -> + object : InitializersLowering(context) { + override fun shouldEraseFieldInitializer(irField: IrField): Boolean = + irField.constantValue(context) == null + } + }, name = "Initializers", description = "Merge init blocks and field initializers into constructors", stickyPostconditions = setOf(fun(irFile: IrFile) { 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 fb627743efe..e29b4f1aa5c 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 @@ -33,12 +33,12 @@ fun IrField.constantValue(context: JvmBackendContext? = null): IrConst<*>? { // JVM has a ConstantValue attribute which does two things: // 1. allows the field to be inlined into other modules; // 2. implicitly generates an initialization of that field in - // It is only allowed on static final fields of primitive/string types. Java and Kotlin < 1.4 + // It is only allowed on final fields of primitive/string types. Java and Kotlin < 1.4 // apply it whenever possible; Kotlin >= 1.4 only applies it to `const val`s to avoid making // values part of the library's ABI unless explicitly requested by the author. val allowImplicitConst = context != null && !context.state.languageVersionSettings.supportsFeature(LanguageFeature.NoConstantValueAttributeForNonConstVals) - val implicitConst = isStatic && isFinal && (origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB || + val implicitConst = isFinal && ((isStatic && origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB) || (allowImplicitConst && (type.isPrimitiveType() || type.isStringClassType()))) return if (implicitConst || correspondingPropertySymbol?.owner?.isConst == true) value else null } diff --git a/compiler/testData/codegen/bytecodeText/constProperty/nonConstValHasNoDefaultValue_before.kt b/compiler/testData/codegen/bytecodeText/constProperty/nonConstValHasNoDefaultValue_before.kt index 86e6d0a4c27..bfeff9540ba 100644 --- a/compiler/testData/codegen/bytecodeText/constProperty/nonConstValHasNoDefaultValue_before.kt +++ b/compiler/testData/codegen/bytecodeText/constProperty/nonConstValHasNoDefaultValue_before.kt @@ -1,5 +1,4 @@ // !LANGUAGE: -NoConstantValueAttributeForNonConstVals +JvmFieldInInterface -// IGNORE_BACKEND: JVM_IR class C { val testClassVal = 100 diff --git a/compiler/testData/loadJava/compiledKotlin/prop/nonConstValWithConstantValueAttribute.kt b/compiler/testData/loadJava/compiledKotlin/prop/nonConstValWithConstantValueAttribute.kt index fa173323390..a8e1d1af963 100644 --- a/compiler/testData/loadJava/compiledKotlin/prop/nonConstValWithConstantValueAttribute.kt +++ b/compiler/testData/loadJava/compiledKotlin/prop/nonConstValWithConstantValueAttribute.kt @@ -1,5 +1,4 @@ // !LANGUAGE: -NoConstantValueAttributeForNonConstVals -// IGNORE_BACKEND: JVM_IR //ALLOW_AST_ACCESS package test