JVM_IR: do not erase constant non-static field initializers...

...unless in 1.4 mode.
This commit is contained in:
pyos
2019-11-25 12:13:09 +01:00
committed by Alexander Udalov
parent fc6b03b08f
commit e4b1599457
5 changed files with 18 additions and 8 deletions
@@ -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 =
@@ -173,8 +173,13 @@ private val staticInitializersPhase = makeIrFilePhase(
description = "Move code from object init blocks and static field initializers to a new <clinit> function"
)
private val initializersPhase = makeIrFilePhase(
::InitializersLowering,
private val initializersPhase = makeIrFilePhase<JvmBackendContext>(
{ 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) {
@@ -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 <clinit>
// 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
}
@@ -1,5 +1,4 @@
// !LANGUAGE: -NoConstantValueAttributeForNonConstVals +JvmFieldInInterface
// IGNORE_BACKEND: JVM_IR
class C {
val testClassVal = 100
@@ -1,5 +1,4 @@
// !LANGUAGE: -NoConstantValueAttributeForNonConstVals
// IGNORE_BACKEND: JVM_IR
//ALLOW_AST_ACCESS
package test