From 18e7a1485c0a7fd423e3beee9362c00f6ae78b92 Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Tue, 15 Dec 2020 18:32:32 +0300 Subject: [PATCH] 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 ) --- .../compiler/backend/ir/GeneratorHelpers.kt | 19 +++++++++---------- .../backend/ir/SerializableIrGenerator.kt | 8 +++++--- .../backend/ir/SerializerIrGenerator.kt | 4 ++-- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt index 9f8c2ec00c1..aa5f80cfd1e 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt @@ -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) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableIrGenerator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableIrGenerator.kt index 96c7de0d3df..bd2a5650413 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableIrGenerator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableIrGenerator.kt @@ -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) { diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt index ad297605d38..fc2efe10b0d 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt @@ -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) ) }