Generics serialization in IR
This commit is contained in:
+13
-6
@@ -30,7 +30,6 @@ abstract class SerializerCodegen(
|
||||
protected val serializerDescriptor: ClassDescriptor,
|
||||
bindingContext: BindingContext
|
||||
) : AbstractSerialGenerator(bindingContext, serializerDescriptor) {
|
||||
// protected val serializerDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext)
|
||||
val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!!
|
||||
protected val serialName: String = serializableDescriptor.annotations.serialNameValue ?: serializableDescriptor.fqNameUnsafe.asString()
|
||||
protected val properties = SerializableProperties(serializableDescriptor, bindingContext)
|
||||
@@ -61,9 +60,7 @@ abstract class SerializerCodegen(
|
||||
return true
|
||||
}
|
||||
|
||||
protected open fun generateChildSerializersGetter(function: FunctionDescriptor) {
|
||||
// TODO()
|
||||
}
|
||||
protected abstract fun generateChildSerializersGetter(function: FunctionDescriptor)
|
||||
|
||||
protected val generatedSerialDescPropertyDescriptor = getPropertyToGenerate(
|
||||
serializerDescriptor, SerialEntityNames.SERIAL_DESC_FIELD,
|
||||
@@ -73,9 +70,20 @@ abstract class SerializerCodegen(
|
||||
serializerDescriptor::checkSerializableClassPropertyResult
|
||||
) { true }
|
||||
|
||||
val localSerializersFieldsDescriptors: List<PropertyDescriptor> = findLocalSerializersFieldDescriptors()
|
||||
|
||||
private fun findLocalSerializersFieldDescriptors(): List<PropertyDescriptor> {
|
||||
val count = serializableDescriptor.declaredTypeParameters.size
|
||||
if (count == 0) return emptyList()
|
||||
val propNames = (0 until count).map { "${SerialEntityNames.typeArgPrefix}$it" }
|
||||
return propNames.mapNotNull { name ->
|
||||
getPropertyToGenerate(serializerDescriptor, name) { isKSerializer(it.returnType) }
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun generateSerialDesc()
|
||||
|
||||
protected abstract fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ConstructorDescriptor)
|
||||
protected abstract fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ClassConstructorDescriptor)
|
||||
|
||||
protected abstract fun generateSerializableClassProperty(property: PropertyDescriptor)
|
||||
|
||||
@@ -129,7 +137,6 @@ abstract class SerializerCodegen(
|
||||
)
|
||||
.singleOrNull { property ->
|
||||
isKindOk(property.kind) &&
|
||||
property.modality != Modality.FINAL &&
|
||||
property.returnType != null &&
|
||||
isReturnTypeOk(property)
|
||||
}
|
||||
|
||||
+13
-3
@@ -58,11 +58,19 @@ interface IrBuilderExtension {
|
||||
) else compilerContext.externalSymbols.referenceSimpleFunction(descriptor).owner
|
||||
f.parent = this
|
||||
f.returnType = descriptor.returnType!!.toIrType()
|
||||
f.createParameterDeclarations()
|
||||
if (!fromStubs) f.createParameterDeclarations(this.thisReceiver)
|
||||
f.body = compilerContext.createIrBuilder(f.symbol).irBlockBody { bodyGen(f) }
|
||||
this.addMember(f)
|
||||
}
|
||||
|
||||
fun IrClass.contributeCtor(descriptor: ClassConstructorDescriptor, bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit) {
|
||||
val c = compilerContext.externalSymbols.referenceConstructor(descriptor).owner
|
||||
c.parent = this
|
||||
c.returnType = descriptor.returnType.toIrType()
|
||||
c.body = compilerContext.createIrBuilder(c.symbol).irBlockBody { bodyGen(c) }
|
||||
this.addMember(c)
|
||||
}
|
||||
|
||||
fun IrClass.contributeConstructor(
|
||||
descriptor: ClassConstructorDescriptor,
|
||||
bodyGen: IrBlockBodyBuilder.(IrConstructor) -> Unit
|
||||
@@ -369,7 +377,7 @@ interface IrBuilderExtension {
|
||||
}
|
||||
|
||||
fun IrBuilderWithScope.serializerInstance(
|
||||
enclosingGenerator: AbstractSerialGenerator,
|
||||
enclosingGenerator: SerializerIrGenerator,
|
||||
serializableDescriptor: ClassDescriptor,
|
||||
serializerClass: ClassDescriptor?,
|
||||
module: ModuleDescriptor,
|
||||
@@ -380,7 +388,9 @@ interface IrBuilderExtension {
|
||||
compilerContext.externalSymbols.referenceClass(module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer))
|
||||
if (serializerClass == null) {
|
||||
if (genericIndex == null) return null
|
||||
TODO("Saved serializer for generic argument")
|
||||
val thiz = enclosingGenerator.irClass.thisReceiver!!
|
||||
val prop = enclosingGenerator.localSerializersFieldsDescriptors[genericIndex]
|
||||
return irGetField(irGet(thiz), compilerContext.localSymbolTable.referenceField(prop).owner)
|
||||
}
|
||||
if (serializerClass.kind == ClassKind.OBJECT) {
|
||||
return irGetObject(serializerClass)
|
||||
|
||||
+9
-7
@@ -3,6 +3,7 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
||||
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
@@ -11,10 +12,8 @@ import org.jetbrains.kotlin.ir.util.TypeTranslator
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.classSerializer
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.toClassDescriptor
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.findSerializerConstructorForTypeArgumentsSerializers
|
||||
|
||||
class SerializableCompanionIrGenerator(
|
||||
val irClass: IrClass,
|
||||
@@ -40,13 +39,16 @@ class SerializableCompanionIrGenerator(
|
||||
}
|
||||
|
||||
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) =
|
||||
irClass.contributeFunction(methodDescriptor, fromStubs = true) { _ ->
|
||||
irClass.contributeFunction(methodDescriptor, fromStubs = true) { getter ->
|
||||
val serializer = serializableDescriptor.classSerializer?.toClassDescriptor!!
|
||||
val expr = if (serializer.kind == ClassKind.OBJECT) {
|
||||
irGetObject(serializer)
|
||||
} else {
|
||||
val ctor = compilerContext.externalSymbols.referenceConstructor(serializer.unsubstitutedPrimaryConstructor!!)
|
||||
val args: List<IrExpression> = emptyList() // todo
|
||||
val desc = requireNotNull(
|
||||
KSerializerDescriptorResolver.findSerializerConstructorForTypeArgumentsSerializers(serializer)
|
||||
) { "Generated serializer does not have constructor with required number of arguments" }
|
||||
val ctor = compilerContext.externalSymbols.referenceConstructor(desc)
|
||||
val args: List<IrExpression> = getter.valueParameters.map { irGet(it) }
|
||||
irInvoke(null, ctor, *args.toTypedArray())
|
||||
}
|
||||
+irReturn(expr)
|
||||
|
||||
+32
-12
@@ -8,18 +8,15 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
||||
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irThrow
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||
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.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.expressions.mapValueParameters
|
||||
import org.jetbrains.kotlin.ir.expressions.mapValueParametersIndexed
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
@@ -69,12 +66,17 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
||||
introduceValueParameter(thisAsReceiverParameter)
|
||||
prop = generateSimplePropertyWithBackingField(thisAsReceiverParameter.symbol, desc, irClass)
|
||||
irClass.addMember(prop)
|
||||
|
||||
localSerializersFieldsDescriptors.forEach {
|
||||
irClass.addMember(generateSimplePropertyWithBackingField(thisAsReceiverParameter.symbol, it, irClass))
|
||||
}
|
||||
}
|
||||
|
||||
compilerContext.localSymbolTable.declareAnonymousInitializer(
|
||||
irClass.startOffset, irClass.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, irClass.descriptor
|
||||
).buildWithScope { initIrBody ->
|
||||
val ctor = irClass.declarations.filterIsInstance<IrConstructor>().singleOrNull()
|
||||
val ctor = irClass.declarations.filterIsInstance<IrConstructor>().find { it.isPrimary }
|
||||
?: throw AssertionError("Serializer must have primary constructor")
|
||||
val serialClassDescImplCtor = compilerContext.externalSymbols.referenceConstructor(serialDescImplConstructor)
|
||||
compilerContext.localSymbolTable.withScope(initIrBody.descriptor) {
|
||||
initIrBody.body = compilerContext.createIrBuilder(initIrBody.symbol).irBlockBody {
|
||||
@@ -106,16 +108,34 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
||||
irGet(localDesc)
|
||||
)
|
||||
}
|
||||
// workaround for KT-25353
|
||||
// irClass.addMember(initIrBody)
|
||||
(ctor?.body as? IrBlockBody)?.statements?.addAll(initIrBody.body.statements)
|
||||
(ctor.body as? IrBlockBody)?.statements?.addAll(initIrBody.body.statements)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ConstructorDescriptor) {
|
||||
// TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
override fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ClassConstructorDescriptor) =
|
||||
irClass.contributeCtor(typedConstructorDescriptor) { ctor ->
|
||||
// generate call to primary ctor to init serialClassDesc and super()
|
||||
val primaryCtor = irClass.descriptor.unsubstitutedPrimaryConstructor
|
||||
?: throw AssertionError("Serializer class must have primary constructor")
|
||||
+IrDelegatingConstructorCallImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
compilerContext.irBuiltIns.unitType,
|
||||
compilerContext.localSymbolTable.referenceConstructor(primaryCtor),
|
||||
primaryCtor
|
||||
)
|
||||
|
||||
// store type arguments serializers in fields
|
||||
val thisAsReceiverParameter = irClass.thisReceiver!!
|
||||
ctor.valueParameters.forEachIndexed { index, param ->
|
||||
val localSerial = compilerContext.localSymbolTable.referenceField(localSerializersFieldsDescriptors[index])
|
||||
+irSetField(generateReceiverExpressionForFieldAccess(
|
||||
thisAsReceiverParameter.symbol,
|
||||
localSerializersFieldsDescriptors[index]
|
||||
), localSerial.owner, irGet(param))
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateChildSerializersGetter(function: FunctionDescriptor) = irClass.contributeFunction(function) { irFun ->
|
||||
val allSerializers = orderedProperties.map { requireNotNull(
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.FieldDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
|
||||
/**
|
||||
* Simple property descriptor with backing field without getters/setters for ir generation purposes
|
||||
*/
|
||||
class SimpleSyntheticPropertyDescriptor(
|
||||
owner: ClassDescriptor,
|
||||
name: String,
|
||||
type: KotlinType,
|
||||
isVar: Boolean = false,
|
||||
visibility: Visibility = Visibilities.PRIVATE
|
||||
) : PropertyDescriptorImpl(
|
||||
owner,
|
||||
null,
|
||||
Annotations.EMPTY,
|
||||
Modality.FINAL,
|
||||
visibility,
|
||||
isVar,
|
||||
Name.identifier(name),
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
owner.source,
|
||||
false, false, false, false, false, false
|
||||
) {
|
||||
|
||||
private val _backingField = FieldDescriptorImpl(Annotations.EMPTY, this)
|
||||
|
||||
init {
|
||||
super.setType(type, emptyList(), owner.thisAsReceiverParameter, null)
|
||||
super.initialize(null, null, _backingField, null)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -107,7 +107,7 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
||||
translator.addProperty(propDesc, getterExpr, null)
|
||||
}
|
||||
|
||||
override fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ConstructorDescriptor) {
|
||||
override fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ClassConstructorDescriptor) {
|
||||
val f = context.buildFunction(typedConstructorDescriptor) { jsFun, context ->
|
||||
val thiz = jsFun.scope.declareName(Namer.ANOTHER_THIS_PARAMETER_NAME).makeRef()
|
||||
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ class SerializerCodegenImpl(
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ConstructorDescriptor) {
|
||||
override fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ClassConstructorDescriptor) {
|
||||
serializableDescriptor.declaredTypeParameters.forEachIndexed { i, _ ->
|
||||
codegen.v.newField(
|
||||
OtherOrigin(codegen.myClass.psiOrParent), ACC_PRIVATE or ACC_SYNTHETIC,
|
||||
|
||||
+21
-4
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.typeUtil.createProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SimpleSyntheticPropertyDescriptor
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.IMPL_NAME
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIALIZER_CLASS_NAME
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.typeArgPrefix
|
||||
@@ -133,9 +134,10 @@ object KSerializerDescriptorResolver {
|
||||
val classDescriptor = getSerializableClassDescriptorBySerializer(thisDescriptor) ?: return
|
||||
if (name == SerialEntityNames.SERIAL_DESC_FIELD_NAME && result.none(thisDescriptor::checkSerializableClassPropertyResult) &&
|
||||
fromSupertypes.none { thisDescriptor.checkSerializableClassPropertyResult(it) && it.modality == Modality.FINAL }
|
||||
)
|
||||
) {
|
||||
result.add(createSerializableClassPropertyDescriptor(thisDescriptor, classDescriptor))
|
||||
|
||||
}
|
||||
result.addAll(createLocalSerializersFieldsDescriptors(classDescriptor, thisDescriptor))
|
||||
}
|
||||
|
||||
fun generateCompanionObjectMethods(
|
||||
@@ -176,7 +178,7 @@ object KSerializerDescriptorResolver {
|
||||
}
|
||||
}
|
||||
|
||||
fun createSerializableClassPropertyDescriptor(
|
||||
private fun createSerializableClassPropertyDescriptor(
|
||||
companionDescriptor: ClassDescriptor,
|
||||
classDescriptor: ClassDescriptor
|
||||
): PropertyDescriptor =
|
||||
@@ -338,7 +340,7 @@ object KSerializerDescriptorResolver {
|
||||
return constrDesc
|
||||
}
|
||||
|
||||
fun createSerializerGetterDescriptor(thisClass: ClassDescriptor, serializableClass: ClassDescriptor): SimpleFunctionDescriptor {
|
||||
private fun createSerializerGetterDescriptor(thisClass: ClassDescriptor, serializableClass: ClassDescriptor): SimpleFunctionDescriptor {
|
||||
val f = SimpleFunctionDescriptorImpl.create(
|
||||
thisClass,
|
||||
Annotations.EMPTY,
|
||||
@@ -493,4 +495,19 @@ object KSerializerDescriptorResolver {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// create properties typeSerial0, typeSerial1, etc... for storing generic arguments' serializers
|
||||
private fun createLocalSerializersFieldsDescriptors(serializableDescriptor: ClassDescriptor, serializerDescriptor: ClassDescriptor): List<PropertyDescriptor> {
|
||||
if (serializableDescriptor.declaredTypeParameters.isEmpty()) return emptyList()
|
||||
val serializerClass = serializableDescriptor.getClassFromSerializationPackage(SerialEntityNames.KSERIALIZER_CLASS)
|
||||
return serializerDescriptor.declaredTypeParameters.mapIndexed { index, param ->
|
||||
val pType =
|
||||
KotlinTypeFactory.simpleNotNullType(
|
||||
Annotations.EMPTY,
|
||||
serializerClass,
|
||||
listOf(TypeProjectionImpl(param.defaultType))
|
||||
)
|
||||
SimpleSyntheticPropertyDescriptor(serializerDescriptor, "$typeArgPrefix$index", pType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user