Rework access to properties in IR plugin
use accessors instead of fields whenever possible
This commit is contained in:
+34
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
@@ -175,8 +176,35 @@ interface IrBuilderExtension {
|
||||
|
||||
fun KotlinType.toIrType() = compilerContext.typeTranslator.translateType(this)
|
||||
|
||||
// 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 IrBuilderWithScope.getProperty(receiver: IrExpression, property: IrProperty): IrExpression {
|
||||
return if (property.getter != null)
|
||||
irGet(property.getter!!.returnType, receiver, property.getter!!.symbol)
|
||||
else
|
||||
irGetField(receiver, property.backingField!!)
|
||||
}
|
||||
|
||||
fun IrBuilderWithScope.setProperty(receiver: IrExpression, property: IrProperty, value: IrExpression): IrExpression {
|
||||
return if (property.setter != null)
|
||||
irSet(property.setter!!.returnType, receiver, property.setter!!.symbol, value)
|
||||
else
|
||||
irSetField(receiver, property.backingField!!, value)
|
||||
}
|
||||
|
||||
/*
|
||||
The rest of the file is mainly copied from FunctionGenerator.
|
||||
However, I can't use it's directly because all generateSomething methods require KtProperty (psi element)
|
||||
@@ -683,4 +711,10 @@ interface IrBuilderExtension {
|
||||
return forClass.declarations.filterIsInstance<IrConstructor>().single { it.isSerializationCtor() }.symbol
|
||||
}
|
||||
|
||||
fun IrClass.getSuperClassOrAny(): IrClass {
|
||||
val superClasses = superTypes.mapNotNull { it.classOrNull }.map { it.owner }
|
||||
|
||||
return superClasses.singleOrNull { it.kind == ClassKind.CLASS } ?: compilerContext.irBuiltIns.anyClass.owner
|
||||
}
|
||||
|
||||
}
|
||||
+7
-6
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* 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.ir
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
|
||||
@@ -30,11 +35,7 @@ class SerializableIrGenerator(
|
||||
bindingContext: BindingContext
|
||||
) : SerializableCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
|
||||
|
||||
private fun IrClass.getSuperClassOrAny(): IrClass {
|
||||
val superClasses = superTypes.mapNotNull { it.classOrNull }.map { it.owner }
|
||||
|
||||
return superClasses.singleOrNull { it.kind == ClassKind.CLASS } ?: compilerContext.irBuiltIns.anyClass.owner
|
||||
}
|
||||
|
||||
private fun IrClass.hasSerializableAnnotationWithoutArgs(): Boolean {
|
||||
val annot = getAnnotation(SerializationAnnotations.serializableAnnotationFqName) ?: return false
|
||||
@@ -76,12 +77,12 @@ class SerializableIrGenerator(
|
||||
val prop = serializableProperties[index]
|
||||
val paramRef = ctor.valueParameters[index + seenVarsOffset]
|
||||
// assign this.a = a in else branch
|
||||
val assignParamExpr = irSetField(irGet(thiz), prop.irField, irGet(paramRef))
|
||||
val assignParamExpr = setProperty(irGet(thiz), prop.irProp, irGet(paramRef))
|
||||
|
||||
val ifNotSeenExpr: IrExpression = if (prop.optional) {
|
||||
val initializerBody =
|
||||
requireNotNull(transformFieldInitializer(prop.irField)) { "Optional value without an initializer" } // todo: filter abstract here
|
||||
irSetField(irGet(thiz), prop.irField, initializerBody)
|
||||
setProperty(irGet(thiz), prop.irProp, initializerBody)
|
||||
} else {
|
||||
irThrow(irInvoke(null, exceptionCtorRef, irString(prop.name), typeHint = exceptionType))
|
||||
}
|
||||
|
||||
+23
-7
@@ -13,16 +13,20 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrAnonymousInitializerImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBranchImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.mapValueParametersIndexed
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
import org.jetbrains.kotlin.ir.util.withReferenceScope
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -137,8 +141,9 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
|
||||
if (classProp.transient) continue
|
||||
+addFieldCall(classProp)
|
||||
// add property annotations
|
||||
val property = classProp.irProp
|
||||
copySerialInfoAnnotationsToDescriptor(
|
||||
classProp.irField.correspondingPropertySymbol?.owner?.annotations.orEmpty(),
|
||||
property.annotations,
|
||||
localDescriptor,
|
||||
serialDescImplClass.referenceMethod(CallingConventions.addAnnotation)
|
||||
)
|
||||
@@ -245,16 +250,27 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
|
||||
val objectToSerialize = saveFunc.valueParameters[1]
|
||||
val localOutput = irTemporary(call, "output")
|
||||
|
||||
fun SerializableProperty.irGet(): IrGetField {
|
||||
fun SerializableProperty.irGet(): IrExpression {
|
||||
val ownerType = objectToSerialize.symbol.owner.type
|
||||
return irGetField(
|
||||
return getProperty(
|
||||
irGet(
|
||||
type = ownerType,
|
||||
variable = objectToSerialize.symbol
|
||||
), irField
|
||||
), irProp
|
||||
)
|
||||
}
|
||||
|
||||
// Ignore comparing to default values of properties from superclass,
|
||||
// because we do not have access to their fields (and initializers), if superclass is in another module.
|
||||
// In future, IR analogue of JVM's write$Self should be implemented.
|
||||
val superClass = irClass.getSuperClassOrAny().descriptor
|
||||
val ignoreIndexTo = if (superClass.isInternalSerializable) {
|
||||
bindingContext.serializablePropertiesFor(superClass).size
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
|
||||
|
||||
// internal serialization via virtual calls?
|
||||
for ((index, property) in serializableProperties.filter { !it.transient }.withIndex()) {
|
||||
// output.writeXxxElementValue(classDesc, index, value)
|
||||
@@ -287,7 +303,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
|
||||
val elementCall = irInvoke(irGet(localOutput), writeFunc, typeArguments = typeArgs, valueArguments = args)
|
||||
|
||||
// check for call to .shouldEncodeElementDefault
|
||||
if (!property.optional) {
|
||||
if (!property.optional || index < ignoreIndexTo) {
|
||||
// emit call right away
|
||||
+elementCall
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user