Kx-serialization: support SerialInfo annotations from dependencies in JVM IR
Also handle call sites correctly, by generating an instance of the Impl class instead of trying to create the annotation. #KT-42976 Fixed
This commit is contained in:
+3
-3
@@ -228,7 +228,7 @@ interface IrBuilderExtension {
|
||||
val irPropertySymbol = compilerContext.symbolTable.referenceProperty(propertyDescriptor)
|
||||
assert(irPropertySymbol.isBound || declare)
|
||||
|
||||
if (declare) {
|
||||
if (!irPropertySymbol.isBound) {
|
||||
with(propertyDescriptor) {
|
||||
propertyParent.factory.createProperty(
|
||||
propertyParent.startOffset, propertyParent.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, irPropertySymbol,
|
||||
@@ -270,7 +270,7 @@ interface IrBuilderExtension {
|
||||
}
|
||||
}
|
||||
|
||||
fun generatePropertyAccessor(
|
||||
private fun generatePropertyAccessor(
|
||||
property: IrProperty,
|
||||
descriptor: PropertyAccessorDescriptor,
|
||||
fieldSymbol: IrFieldSymbol,
|
||||
@@ -279,7 +279,7 @@ interface IrBuilderExtension {
|
||||
val symbol = compilerContext.symbolTable.referenceSimpleFunction(descriptor)
|
||||
assert(symbol.isBound || declare)
|
||||
|
||||
if (declare) {
|
||||
if (!symbol.isBound) {
|
||||
with(descriptor) {
|
||||
property.factory.createFunction(
|
||||
fieldSymbol.owner.startOffset, fieldSymbol.owner.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, symbol,
|
||||
|
||||
+15
-11
@@ -15,17 +15,17 @@ import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
|
||||
|
||||
// This doesn't support annotation arguments of type KClass and Array<KClass> because the codegen doesn't compute JVM signatures for
|
||||
// such cases correctly (because inheriting from annotation classes is prohibited in Kotlin).
|
||||
// Currently it results in an "accidental override" error where a method with return type KClass conflicts with the one with Class.
|
||||
// TODO: support annotation properties of types KClass<...> and Array<KClass<...>>.
|
||||
class SerialInfoImplJvmIrGenerator(
|
||||
private val irClass: IrClass,
|
||||
private val context: SerializationPluginContext,
|
||||
) : IrBuilderExtension {
|
||||
override val compilerContext: SerializationPluginContext
|
||||
@@ -33,7 +33,18 @@ class SerialInfoImplJvmIrGenerator(
|
||||
|
||||
private val jvmNameClass = context.referenceClass(DescriptorUtils.JVM_NAME)!!.owner
|
||||
|
||||
private fun generate() {
|
||||
private val implGenerated = mutableSetOf<IrClass>()
|
||||
private val annotationToImpl = mutableMapOf<IrClass, IrClass>()
|
||||
|
||||
fun getImplClass(serialInfoAnnotationClass: IrClass): IrClass =
|
||||
annotationToImpl.getOrPut(serialInfoAnnotationClass) {
|
||||
val implClassSymbol = context.referenceClass(serialInfoAnnotationClass.kotlinFqName.child(SerialEntityNames.IMPL_NAME))
|
||||
implClassSymbol!!.owner.apply(this::generate)
|
||||
}
|
||||
|
||||
fun generate(irClass: IrClass) {
|
||||
if (!implGenerated.add(irClass)) return
|
||||
|
||||
val properties = irClass.declarations.filterIsInstance<IrProperty>()
|
||||
if (properties.isEmpty()) return
|
||||
|
||||
@@ -54,7 +65,7 @@ class SerialInfoImplJvmIrGenerator(
|
||||
ctor.body = ctorBody
|
||||
|
||||
for (property in properties) {
|
||||
generateSimplePropertyWithBackingField(property.descriptor, irClass, false, Name.identifier("_" + property.name.asString()))
|
||||
generateSimplePropertyWithBackingField(property.descriptor, irClass, true, Name.identifier("_" + property.name.asString()))
|
||||
|
||||
val getter = property.getter!!
|
||||
getter.origin = SERIALIZABLE_SYNTHETIC_ORIGIN
|
||||
@@ -84,11 +95,4 @@ class SerialInfoImplJvmIrGenerator(
|
||||
).apply {
|
||||
putValueArgument(0, IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.stringType, name))
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun generate(irClass: IrClass, context: SerializationPluginContext) {
|
||||
if (KSerializerDescriptorResolver.isSerialInfoImpl(irClass.descriptor))
|
||||
SerialInfoImplJvmIrGenerator(irClass, context).generate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-4
@@ -27,10 +27,9 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
class SerializerForEnumsGenerator(
|
||||
irClass: IrClass,
|
||||
compilerContext: SerializationPluginContext,
|
||||
bindingContext: BindingContext
|
||||
) :
|
||||
SerializerIrGenerator(irClass, compilerContext, bindingContext, null) {
|
||||
|
||||
bindingContext: BindingContext,
|
||||
serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
|
||||
) : SerializerIrGenerator(irClass, compilerContext, bindingContext, null, serialInfoJvmGenerator) {
|
||||
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc ->
|
||||
fun irThis(): IrExpression =
|
||||
IrGetValueImpl(startOffset, endOffset, saveFunc.dispatchReceiverParameter!!.symbol)
|
||||
|
||||
+28
-17
@@ -14,18 +14,14 @@ import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
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.impl.*
|
||||
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.constructors
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
import org.jetbrains.kotlin.ir.util.withReferenceScope
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
@@ -50,10 +46,9 @@ open class SerializerIrGenerator(
|
||||
val irClass: IrClass,
|
||||
final override val compilerContext: SerializationPluginContext,
|
||||
bindingContext: BindingContext,
|
||||
metadataPlugin: SerializationDescriptorSerializerPlugin?
|
||||
) :
|
||||
SerializerCodegen(irClass.descriptor, bindingContext, metadataPlugin), IrBuilderExtension {
|
||||
|
||||
metadataPlugin: SerializationDescriptorSerializerPlugin?,
|
||||
private val serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
|
||||
) : SerializerCodegen(irClass.descriptor, bindingContext, metadataPlugin), IrBuilderExtension {
|
||||
protected val serializableIrClass = compilerContext.symbolTable.referenceClass(serializableDescriptor).owner
|
||||
protected val irAnySerialDescProperty = anySerialDescProperty?.let { compilerContext.symbolTable.referenceProperty(it) }
|
||||
|
||||
@@ -160,9 +155,24 @@ open class SerializerIrGenerator(
|
||||
receiver: IrVariable,
|
||||
method: IrFunctionSymbol
|
||||
) {
|
||||
annotations.forEach { annotationCall ->
|
||||
if ((annotationCall.symbol.descriptor as? ClassConstructorDescriptor)?.constructedClass?.isSerialInfoAnnotation == true)
|
||||
+irInvoke(irGet(receiver), method, annotationCall.deepCopyWithVariables())
|
||||
for (annotationCall in annotations) {
|
||||
val annotationClass = annotationCall.symbol.owner.parentAsClass
|
||||
if (!annotationClass.descriptor.isSerialInfoAnnotation) continue
|
||||
|
||||
val createAnnotation = if (compilerContext.platform.isJvm()) {
|
||||
val implClass = serialInfoJvmGenerator.getImplClass(annotationClass)
|
||||
val ctor = implClass.constructors.singleOrNull { it.valueParameters.size == annotationCall.valueArgumentsCount }
|
||||
?: error("No constructor args found for SerialInfo annotation Impl class: ${implClass.render()}")
|
||||
irCall(ctor).apply {
|
||||
for (i in 0 until annotationCall.valueArgumentsCount) {
|
||||
putValueArgument(i, annotationCall.getValueArgument(i)!!.deepCopyWithVariables())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
annotationCall.deepCopyWithVariables()
|
||||
}
|
||||
|
||||
+irInvoke(irGet(receiver), method, createAnnotation)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,13 +506,14 @@ open class SerializerIrGenerator(
|
||||
irClass: IrClass,
|
||||
context: SerializationPluginContext,
|
||||
bindingContext: BindingContext,
|
||||
metadataPlugin: SerializationDescriptorSerializerPlugin?
|
||||
metadataPlugin: SerializationDescriptorSerializerPlugin?,
|
||||
serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
|
||||
) {
|
||||
val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return
|
||||
if (serializableDesc.isSerializableEnum()) {
|
||||
SerializerForEnumsGenerator(irClass, context, bindingContext).generate()
|
||||
SerializerForEnumsGenerator(irClass, context, bindingContext, serialInfoJvmGenerator).generate()
|
||||
} else {
|
||||
SerializerIrGenerator(irClass, context, bindingContext, metadataPlugin).generate()
|
||||
SerializerIrGenerator(irClass, context, bindingContext, metadataPlugin, serialInfoJvmGenerator).generate()
|
||||
}
|
||||
irClass.patchDeclarationParents(irClass.parent)
|
||||
}
|
||||
|
||||
+7
-5
@@ -22,6 +22,7 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerialInfoImplJvm
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializableCompanionIrGenerator
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializableIrGenerator
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializerIrGenerator
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
|
||||
|
||||
/**
|
||||
* Copy of [runOnFilePostfix], but this implementation first lowers declaration, then its children.
|
||||
@@ -44,15 +45,16 @@ typealias SerializationPluginContext = IrPluginContext
|
||||
private class SerializerClassLowering(
|
||||
val context: SerializationPluginContext,
|
||||
val metadataPlugin: SerializationDescriptorSerializerPlugin?
|
||||
) :
|
||||
IrElementTransformerVoid(), ClassLoweringPass {
|
||||
) : IrElementTransformerVoid(), ClassLoweringPass {
|
||||
private val serialInfoJvmGenerator = SerialInfoImplJvmIrGenerator(context)
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
SerializableIrGenerator.generate(irClass, context, context.bindingContext)
|
||||
SerializerIrGenerator.generate(irClass, context, context.bindingContext, metadataPlugin)
|
||||
SerializerIrGenerator.generate(irClass, context, context.bindingContext, metadataPlugin, serialInfoJvmGenerator)
|
||||
SerializableCompanionIrGenerator.generate(irClass, context, context.bindingContext)
|
||||
|
||||
if (context.platform.isJvm()) {
|
||||
SerialInfoImplJvmIrGenerator.generate(irClass, context)
|
||||
if (context.platform.isJvm() && KSerializerDescriptorResolver.isSerialInfoImpl(irClass.descriptor)) {
|
||||
serialInfoJvmGenerator.generate(irClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user