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)
|
val irPropertySymbol = compilerContext.symbolTable.referenceProperty(propertyDescriptor)
|
||||||
assert(irPropertySymbol.isBound || declare)
|
assert(irPropertySymbol.isBound || declare)
|
||||||
|
|
||||||
if (declare) {
|
if (!irPropertySymbol.isBound) {
|
||||||
with(propertyDescriptor) {
|
with(propertyDescriptor) {
|
||||||
propertyParent.factory.createProperty(
|
propertyParent.factory.createProperty(
|
||||||
propertyParent.startOffset, propertyParent.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, irPropertySymbol,
|
propertyParent.startOffset, propertyParent.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, irPropertySymbol,
|
||||||
@@ -270,7 +270,7 @@ interface IrBuilderExtension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generatePropertyAccessor(
|
private fun generatePropertyAccessor(
|
||||||
property: IrProperty,
|
property: IrProperty,
|
||||||
descriptor: PropertyAccessorDescriptor,
|
descriptor: PropertyAccessorDescriptor,
|
||||||
fieldSymbol: IrFieldSymbol,
|
fieldSymbol: IrFieldSymbol,
|
||||||
@@ -279,7 +279,7 @@ interface IrBuilderExtension {
|
|||||||
val symbol = compilerContext.symbolTable.referenceSimpleFunction(descriptor)
|
val symbol = compilerContext.symbolTable.referenceSimpleFunction(descriptor)
|
||||||
assert(symbol.isBound || declare)
|
assert(symbol.isBound || declare)
|
||||||
|
|
||||||
if (declare) {
|
if (!symbol.isBound) {
|
||||||
with(descriptor) {
|
with(descriptor) {
|
||||||
property.factory.createFunction(
|
property.factory.createFunction(
|
||||||
fieldSymbol.owner.startOffset, fieldSymbol.owner.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, symbol,
|
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.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.util.constructors
|
import org.jetbrains.kotlin.ir.util.constructors
|
||||||
import org.jetbrains.kotlin.ir.util.defaultType
|
import org.jetbrains.kotlin.ir.util.defaultType
|
||||||
|
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
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
|
// 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).
|
// 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.
|
// 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<...>>.
|
// TODO: support annotation properties of types KClass<...> and Array<KClass<...>>.
|
||||||
class SerialInfoImplJvmIrGenerator(
|
class SerialInfoImplJvmIrGenerator(
|
||||||
private val irClass: IrClass,
|
|
||||||
private val context: SerializationPluginContext,
|
private val context: SerializationPluginContext,
|
||||||
) : IrBuilderExtension {
|
) : IrBuilderExtension {
|
||||||
override val compilerContext: SerializationPluginContext
|
override val compilerContext: SerializationPluginContext
|
||||||
@@ -33,7 +33,18 @@ class SerialInfoImplJvmIrGenerator(
|
|||||||
|
|
||||||
private val jvmNameClass = context.referenceClass(DescriptorUtils.JVM_NAME)!!.owner
|
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>()
|
val properties = irClass.declarations.filterIsInstance<IrProperty>()
|
||||||
if (properties.isEmpty()) return
|
if (properties.isEmpty()) return
|
||||||
|
|
||||||
@@ -54,7 +65,7 @@ class SerialInfoImplJvmIrGenerator(
|
|||||||
ctor.body = ctorBody
|
ctor.body = ctorBody
|
||||||
|
|
||||||
for (property in properties) {
|
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!!
|
val getter = property.getter!!
|
||||||
getter.origin = SERIALIZABLE_SYNTHETIC_ORIGIN
|
getter.origin = SERIALIZABLE_SYNTHETIC_ORIGIN
|
||||||
@@ -84,11 +95,4 @@ class SerialInfoImplJvmIrGenerator(
|
|||||||
).apply {
|
).apply {
|
||||||
putValueArgument(0, IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.stringType, name))
|
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(
|
class SerializerForEnumsGenerator(
|
||||||
irClass: IrClass,
|
irClass: IrClass,
|
||||||
compilerContext: SerializationPluginContext,
|
compilerContext: SerializationPluginContext,
|
||||||
bindingContext: BindingContext
|
bindingContext: BindingContext,
|
||||||
) :
|
serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
|
||||||
SerializerIrGenerator(irClass, compilerContext, bindingContext, null) {
|
) : SerializerIrGenerator(irClass, compilerContext, bindingContext, null, serialInfoJvmGenerator) {
|
||||||
|
|
||||||
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc ->
|
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc ->
|
||||||
fun irThis(): IrExpression =
|
fun irThis(): IrExpression =
|
||||||
IrGetValueImpl(startOffset, endOffset, saveFunc.dispatchReceiverParameter!!.symbol)
|
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.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBranchImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
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.expressions.mapValueParametersIndexed
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.constructors
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||||
import org.jetbrains.kotlin.ir.util.withReferenceScope
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
@@ -50,10 +46,9 @@ open class SerializerIrGenerator(
|
|||||||
val irClass: IrClass,
|
val irClass: IrClass,
|
||||||
final override val compilerContext: SerializationPluginContext,
|
final override val compilerContext: SerializationPluginContext,
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
metadataPlugin: SerializationDescriptorSerializerPlugin?
|
metadataPlugin: SerializationDescriptorSerializerPlugin?,
|
||||||
) :
|
private val serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
|
||||||
SerializerCodegen(irClass.descriptor, bindingContext, metadataPlugin), IrBuilderExtension {
|
) : SerializerCodegen(irClass.descriptor, bindingContext, metadataPlugin), IrBuilderExtension {
|
||||||
|
|
||||||
protected val serializableIrClass = compilerContext.symbolTable.referenceClass(serializableDescriptor).owner
|
protected val serializableIrClass = compilerContext.symbolTable.referenceClass(serializableDescriptor).owner
|
||||||
protected val irAnySerialDescProperty = anySerialDescProperty?.let { compilerContext.symbolTable.referenceProperty(it) }
|
protected val irAnySerialDescProperty = anySerialDescProperty?.let { compilerContext.symbolTable.referenceProperty(it) }
|
||||||
|
|
||||||
@@ -160,9 +155,24 @@ open class SerializerIrGenerator(
|
|||||||
receiver: IrVariable,
|
receiver: IrVariable,
|
||||||
method: IrFunctionSymbol
|
method: IrFunctionSymbol
|
||||||
) {
|
) {
|
||||||
annotations.forEach { annotationCall ->
|
for (annotationCall in annotations) {
|
||||||
if ((annotationCall.symbol.descriptor as? ClassConstructorDescriptor)?.constructedClass?.isSerialInfoAnnotation == true)
|
val annotationClass = annotationCall.symbol.owner.parentAsClass
|
||||||
+irInvoke(irGet(receiver), method, annotationCall.deepCopyWithVariables())
|
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,
|
irClass: IrClass,
|
||||||
context: SerializationPluginContext,
|
context: SerializationPluginContext,
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
metadataPlugin: SerializationDescriptorSerializerPlugin?
|
metadataPlugin: SerializationDescriptorSerializerPlugin?,
|
||||||
|
serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
|
||||||
) {
|
) {
|
||||||
val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return
|
val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return
|
||||||
if (serializableDesc.isSerializableEnum()) {
|
if (serializableDesc.isSerializableEnum()) {
|
||||||
SerializerForEnumsGenerator(irClass, context, bindingContext).generate()
|
SerializerForEnumsGenerator(irClass, context, bindingContext, serialInfoJvmGenerator).generate()
|
||||||
} else {
|
} else {
|
||||||
SerializerIrGenerator(irClass, context, bindingContext, metadataPlugin).generate()
|
SerializerIrGenerator(irClass, context, bindingContext, metadataPlugin, serialInfoJvmGenerator).generate()
|
||||||
}
|
}
|
||||||
irClass.patchDeclarationParents(irClass.parent)
|
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.SerializableCompanionIrGenerator
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializableIrGenerator
|
import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializableIrGenerator
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializerIrGenerator
|
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.
|
* Copy of [runOnFilePostfix], but this implementation first lowers declaration, then its children.
|
||||||
@@ -44,15 +45,16 @@ typealias SerializationPluginContext = IrPluginContext
|
|||||||
private class SerializerClassLowering(
|
private class SerializerClassLowering(
|
||||||
val context: SerializationPluginContext,
|
val context: SerializationPluginContext,
|
||||||
val metadataPlugin: SerializationDescriptorSerializerPlugin?
|
val metadataPlugin: SerializationDescriptorSerializerPlugin?
|
||||||
) :
|
) : IrElementTransformerVoid(), ClassLoweringPass {
|
||||||
IrElementTransformerVoid(), ClassLoweringPass {
|
private val serialInfoJvmGenerator = SerialInfoImplJvmIrGenerator(context)
|
||||||
|
|
||||||
override fun lower(irClass: IrClass) {
|
override fun lower(irClass: IrClass) {
|
||||||
SerializableIrGenerator.generate(irClass, context, context.bindingContext)
|
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)
|
SerializableCompanionIrGenerator.generate(irClass, context, context.bindingContext)
|
||||||
|
|
||||||
if (context.platform.isJvm()) {
|
if (context.platform.isJvm() && KSerializerDescriptorResolver.isSerialInfoImpl(irClass.descriptor)) {
|
||||||
SerialInfoImplJvmIrGenerator.generate(irClass, context)
|
serialInfoJvmGenerator.generate(irClass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user