Additional fix for Compose:

directly search for fields in IR class w/o using the symbol table.
Because Compose copies whole IR, fields got referenced incorrectly.
In the end, bytecode generator thinks that this is a field from other
class and creates a synthetic setter, which is prohibited in Java 9+
(Update to non-static final field ... attempted from a different method than <init>)
This commit is contained in:
Leonid Startsev
2020-12-15 18:32:32 +03:00
parent f922ebbfc3
commit 18e7a1485c
3 changed files with 16 additions and 15 deletions
@@ -214,17 +214,16 @@ interface IrBuilderExtension {
// note: this method should be used only for properties from current module. Fields from other modules are private and inaccessible.
val SerializableProperty.irField: IrField get() = compilerContext.symbolTable.referenceField(this.descriptor).owner
val SerializableProperty.irProp: IrProperty
get() {
val desc = this.descriptor
// this API is used to reference both current module descriptors and external ones (because serializable class can be in any of them),
// so we use descriptor api for current module because it is not possible to obtain FQname for e.g. local classes.
return if (desc.module == compilerContext.moduleDescriptor) {
compilerContext.symbolTable.referenceProperty(desc).owner
} else {
compilerContext.referenceProperties(this.descriptor.fqNameSafe).single().owner
}
fun SerializableProperty.getIrPropertyFrom(thisClass: IrClass): IrProperty {
val desc = this.descriptor
// this API is used to reference both current module descriptors and external ones (because serializable class can be in any of them),
// so we use descriptor api for current module because it is not possible to obtain FQname for e.g. local classes.
return thisClass.searchForDeclaration(desc) ?: if (desc.module == compilerContext.moduleDescriptor) {
compilerContext.symbolTable.referenceProperty(desc).owner
} else {
compilerContext.referenceProperties(desc.fqNameSafe).single().owner
}
}
fun IrBuilderWithScope.getProperty(receiver: IrExpression, property: IrProperty): IrExpression {
return if (property.getter != null)
@@ -99,13 +99,15 @@ class SerializableIrGenerator(
for (index in startPropOffset until serializableProperties.size) {
val prop = serializableProperties[index]
val paramRef = ctor.valueParameters[index + seenVarsOffset]
// assign this.a = a in else branch
val assignParamExpr = setProperty(irGet(thiz), prop.irProp, irGet(paramRef))
// Assign this.a = a in else branch
// Set field directly w/o setter to match behavior of old backend plugin
val backingFieldToAssign = prop.getIrPropertyFrom(irClass).backingField!!
val assignParamExpr = irSetField(irGet(thiz), backingFieldToAssign, irGet(paramRef))
val ifNotSeenExpr: IrExpression = if (prop.optional) {
val initializerBody =
requireNotNull(transformFieldInitializer(prop.irField)) { "Optional value without an initializer" } // todo: filter abstract here
setProperty(irGet(thiz), prop.irProp, initializerBody)
irSetField(irGet(thiz), backingFieldToAssign, initializerBody)
} else {
// property required
if (useFieldMissingOptimization) {
@@ -138,7 +138,7 @@ open class SerializerIrGenerator(
if (classProp.transient) continue
+addFieldCall(classProp)
// add property annotations
val property = classProp.irProp
val property = classProp.getIrPropertyFrom(serializableIrClass)
copySerialInfoAnnotationsToDescriptor(
property.annotations,
localDescriptor,
@@ -268,7 +268,7 @@ open class SerializerIrGenerator(
irGet(
type = ownerType,
variable = objectToSerialize.symbol
), irProp
), getIrPropertyFrom(serializableIrClass)
)
}