Compare commits

...

2 Commits

Author SHA1 Message Date
Leonid Startsev
cc52b38b44 Adapt serialization exceptions constructor calls in legacy JS
to signature change

(see https://github.com/Kotlin/kotlinx.serialization/pull/1054
and commit eea4ff33a0)
2020-12-16 19:24:11 +03:00
Leonid Startsev
f141ad3dee 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>)
2020-12-15 18:55:09 +03:00
4 changed files with 21 additions and 30 deletions

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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)
)
}

View File

@@ -1,17 +1,6 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlinx.serialization.compiler.backend.js
@@ -50,7 +39,8 @@ class SerializableJsTranslator(
override fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor) {
val missingExceptionClassRef = serializableDescriptor.getClassFromSerializationPackage(MISSING_FIELD_EXC)
.let { context.translateQualifiedReference(it) }
.constructors.single { it.valueParameters.size == 1 }
.let { context.getInnerNameForDescriptor(it).makeRef() }
val f = context.buildFunction(constructorDescriptor) { jsFun, context ->
val thiz = jsFun.scope.declareName(Namer.ANOTHER_THIS_PARAMETER_NAME).makeRef()
@@ -98,7 +88,7 @@ class SerializableJsTranslator(
val initExpr = Translation.translateAsExpression(initializer, context)
TranslationUtils.assignmentToBackingField(context, prop.descriptor, initExpr).makeStmt()
} else {
JsThrow(JsNew(missingExceptionClassRef, listOf(JsStringLiteral(prop.name))))
JsThrow(JsInvocation(missingExceptionClassRef, listOf(JsStringLiteral(prop.name))))
}
// (seen & 1 << i == 0) -- not seen
val notSeenTest = propNotSeenTest(seenVars[bitMaskSlotAt(index)], index)