IR-plugin

[IR-plugin] Synthetic property declaration in $serializer

[IR-plugin] Saving most of simple cases

[IP-plugin] Some refactoring and start of work on load func

[IP-plugin] Loading simple case without validation

[IP-plugin] Rebase to IR types and Native-enabled

[IP-plugin] Generating .serializer() accessor in companion

[IP-plugin] Basic synthetic deserializing constructor, fixed some todos

[IR-plugin] Remove reference to SerialDescriptor.init() since K/N now has freeze-aware lazy
This commit is contained in:
Leonid Startsev
2018-07-06 15:40:55 +03:00
parent edcac21723
commit 8cd5966c4a
15 changed files with 940 additions and 29 deletions
@@ -19,14 +19,14 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.common
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties
import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor
import org.jetbrains.kotlin.resolve.BindingContext
abstract class SerializableCodegen(declaration: KtPureClassOrObject, private val bindingContext: BindingContext) {
protected val serializableDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext)
abstract class SerializableCodegen(
protected val serializableDescriptor: ClassDescriptor,
private val bindingContext: BindingContext
) {
protected val properties = SerializableProperties(serializableDescriptor, bindingContext)
fun generate() {
@@ -18,19 +18,18 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.common
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
import org.jetbrains.kotlin.psi2ir.findSingleFunction
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.SERIALIZER_PROVIDER_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
abstract class SerializableCompanionCodegen(declaration: KtPureClassOrObject, bindingContext: BindingContext) {
protected val companionDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext)
abstract class SerializableCompanionCodegen(
protected val companionDescriptor: ClassDescriptor /*declaration: KtPureClassOrObject*/
) {
protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorByCompanion(companionDescriptor)!!
fun generate() {
val fser = KSerializerDescriptorResolver.createSerializerGetterDescriptor(companionDescriptor, serializableDescriptor)
generateSerializerGetter(fser)
val serializerGetterDescriptor = companionDescriptor.unsubstitutedMemberScope.findSingleFunction(SERIALIZER_PROVIDER_NAME)
generateSerializerGetter(serializerGetterDescriptor)
}
protected abstract fun generateSerializerGetter(methodDescriptor: FunctionDescriptor)
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor
@@ -36,11 +37,12 @@ abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContex
fun generate() {
check(properties.isExternallySerializable) { "Class ${serializableDescriptor.name} is not externally serializable" }
generateSerialDesc()
val prop = generateSerializableClassPropertyIfNeeded()
val save = generateSaveIfNeeded()
val load = generateLoadIfNeeded()
if (save || load || prop)
generateSerialDesc()
// if (save || load || prop)
// generateSerialDesc()
if (serializableDescriptor.declaredTypeParameters.isNotEmpty() && typedSerializerConstructorNotDeclared()) {
generateGenericFieldsAndConstructor(createTypedSerializerConstructorDescriptor(serializerDescriptor, serializableDescriptor))
}
@@ -111,4 +113,7 @@ abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContex
property.returnType != null &&
isReturnTypeOk(property)
}
protected fun ClassDescriptor.getFuncDesc(funcName: String): Sequence<FunctionDescriptor> =
unsubstitutedMemberScope.getDescriptorsFiltered { it == Name.identifier(funcName) }.asSequence().filterIsInstance<FunctionDescriptor>()
}
@@ -51,7 +51,8 @@ fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
T.isTypeParameter() -> SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", null)
T.isPrimitiveNumberType() or T.isBoolean() -> SerialTypeInfo(
property,
T.nameIfStandardType.toString().capitalize()
T.getJetTypeFqName(false).removePrefix("kotlin.") // i don't feel so good about it...
// alternative: KotlinBuiltIns.getPrimitiveType(T)!!.typeName.identifier
)
KotlinBuiltIns.isString(T) -> SerialTypeInfo(property, "String")
KotlinBuiltIns.isUnit(T) -> SerialTypeInfo(property, "Unit", unit = true)
@@ -0,0 +1,311 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.BackendContext
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.TypeTranslator
import org.jetbrains.kotlin.ir.util.declareSimpleFunctionWithOverrides
import org.jetbrains.kotlin.ir.util.withScope
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperty
interface IrBuilderExtension {
val compilerContext: BackendContext
val translator: TypeTranslator
fun IrClass.contributeFunction(descriptor: FunctionDescriptor, bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit) {
val f = compilerContext.symbolTable.declareSimpleFunctionWithOverrides(
this.startOffset,
this.endOffset,
SERIALIZABLE_PLUGIN_ORIGIN,
descriptor
)
f.parent = this
f.returnType = descriptor.returnType!!.toIrType()
f.createParameterDeclarations()
f.body = compilerContext.createIrBuilder(f.symbol).irBlockBody { bodyGen(f) }
this.addMember(f)
}
fun IrClass.contributeConstructor(
descriptor: ClassConstructorDescriptor,
bodyGen: IrBlockBodyBuilder.(IrConstructor) -> Unit
) {
val c = compilerContext.symbolTable.declareConstructor(
this.startOffset,
this.endOffset,
SERIALIZABLE_PLUGIN_ORIGIN,
descriptor
)
c.parent = this
c.returnType = descriptor.returnType.toIrType()
c.createParameterDeclarations()
c.body = compilerContext.createIrBuilder(c.symbol).irBlockBody { bodyGen(c) }
this.addMember(c)
}
fun IrBuilderWithScope.irInvoke(
dispatchReceiver: IrExpression? = null,
callee: IrFunctionSymbol,
vararg args: IrExpression,
typeHint: IrType? = null
): IrCall {
val call = typeHint?.let { irCall(callee, type = it) } ?: irCall(callee)
call.dispatchReceiver = dispatchReceiver
args.forEachIndexed(call::putValueArgument)
return call
}
fun IrBuilderWithScope.irBinOp(name: Name, lhs: IrExpression, rhs: IrExpression): IrExpression {
val symbol = compilerContext.ir.symbols.getBinaryOperator(
name,
lhs.type.toKotlinType(),
rhs.type.toKotlinType()
)
return irInvoke(lhs, symbol, rhs)
}
fun IrBuilderWithScope.irGetObject(classDescriptor: ClassDescriptor) =
IrGetObjectValueImpl(
startOffset,
endOffset,
classDescriptor.defaultType.toIrType(),
compilerContext.symbolTable.referenceClass(classDescriptor)
)
fun <T : IrDeclaration> T.buildWithScope(builder: (T) -> Unit): T =
also { irDeclaration ->
compilerContext.symbolTable.withScope(irDeclaration.descriptor) {
builder(irDeclaration)
}
}
fun IrBuilderWithScope.irEmptyVararg(forValueParameter: ValueParameterDescriptor) =
IrVarargImpl(
startOffset,
endOffset,
forValueParameter.type.toIrType(),
forValueParameter.varargElementType!!.toIrType()
)
class BranchBuilder(
val irWhen: IrWhen,
context: IrGeneratorContext,
scope: Scope,
startOffset: Int,
endOffset: Int
) : IrBuilderWithScope(context, scope, startOffset, endOffset) {
operator fun IrBranch.unaryPlus() {
irWhen.branches.add(this)
}
}
fun IrBuilderWithScope.irWhen(typeHint: IrType? = null, block: BranchBuilder.() -> Unit): IrWhen {
val whenExpr = IrWhenImpl(startOffset, endOffset, typeHint ?: compilerContext.irBuiltIns.unitType)
val builder = BranchBuilder(whenExpr, context, scope, startOffset, endOffset)
builder.block()
return whenExpr
}
fun BranchBuilder.elseBranch(result: IrExpression): IrElseBranch =
IrElseBranchImpl(
IrConstImpl.boolean(result.startOffset, result.endOffset, compilerContext.irBuiltIns.booleanType, true),
result
)
fun translateType(ktType: KotlinType): IrType =
translator.translateType(ktType)
fun KotlinType.toIrType() = translateType(this)
val SerializableProperty.irField: IrField
get () = compilerContext.symbolTable.referenceField(this.descriptor).owner
/*
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)
Also, FunctionGenerator itself has DeclarationGenerator as ctor param, which is a part of psi2ir
(it can be instantiated here, but I don't know how good is that idea)
*/
fun IrBuilderWithScope.generateAnySuperConstructorCall(toBuilder: IrBlockBodyBuilder) {
val anyConstructor = compilerContext.builtIns.any.constructors.single()
with(toBuilder) {
+IrDelegatingConstructorCallImpl(
startOffset, endOffset,
compilerContext.irBuiltIns.unitType,
compilerContext.symbolTable.referenceConstructor(anyConstructor),
anyConstructor
)
}
}
fun generateSimplePropertyWithBackingField(
ownerSymbol: IrValueSymbol,
propertyDescriptor: PropertyDescriptor,
propertyParent: IrClass
): IrProperty {
val irProperty = IrPropertyImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
SERIALIZABLE_PLUGIN_ORIGIN, false,
propertyDescriptor
)
irProperty.parent = propertyParent
irProperty.backingField = generatePropertyBackingField(propertyDescriptor).apply { parent = propertyParent }
val fieldSymbol = irProperty.backingField!!.symbol
irProperty.getter = propertyDescriptor.getter?.let { generatePropertyAccessor(it, fieldSymbol, ownerSymbol) }
?.apply { parent = propertyParent }
irProperty.setter = propertyDescriptor.setter?.let { generatePropertyAccessor(it, fieldSymbol, ownerSymbol) }
?.apply { parent = propertyParent }
return irProperty
}
fun generatePropertyBackingField(propertyDescriptor: PropertyDescriptor): IrField {
return compilerContext.symbolTable.declareField(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
SERIALIZABLE_PLUGIN_ORIGIN,
propertyDescriptor,
propertyDescriptor.type.toIrType()
)
}
fun generatePropertyAccessor(
descriptor: PropertyAccessorDescriptor,
fieldSymbol: IrFieldSymbol,
ownerSymbol: IrValueSymbol
): IrSimpleFunction {
return compilerContext.symbolTable.declareSimpleFunctionWithOverrides(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
SERIALIZABLE_PLUGIN_ORIGIN, descriptor
).buildWithScope { irAccessor ->
irAccessor.createParameterDeclarations((ownerSymbol as IrValueParameterSymbol).owner) // todo: neat this
irAccessor.returnType = irAccessor.descriptor.returnType!!.toIrType()
irAccessor.body = when (descriptor) {
is PropertyGetterDescriptor -> generateDefaultGetterBody(descriptor, irAccessor, ownerSymbol)
is PropertySetterDescriptor -> generateDefaultSetterBody(descriptor, irAccessor, ownerSymbol)
else -> throw AssertionError("Should be getter or setter: $descriptor")
}
}
}
private fun generateDefaultGetterBody(
getter: PropertyGetterDescriptor,
irAccessor: IrSimpleFunction,
ownerSymbol: IrValueSymbol
): IrBlockBody {
val property = getter.correspondingProperty
val irBody = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET)
val receiver = generateReceiverExpressionForFieldAccess(ownerSymbol, property)
irBody.statements.add(
IrReturnImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, compilerContext.irBuiltIns.nothingType,
irAccessor.symbol,
IrGetFieldImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
compilerContext.symbolTable.referenceField(property),
property.type.toIrType(),
receiver
)
)
)
return irBody
}
private fun generateDefaultSetterBody(
setter: PropertySetterDescriptor,
irAccessor: IrSimpleFunction,
ownerSymbol: IrValueSymbol
): IrBlockBody {
val property = setter.correspondingProperty
val startOffset = UNDEFINED_OFFSET
val endOffset = UNDEFINED_OFFSET
val irBody = IrBlockBodyImpl(startOffset, endOffset)
val receiver = generateReceiverExpressionForFieldAccess(ownerSymbol, property)
val irValueParameter = irAccessor.valueParameters.single()
irBody.statements.add(
IrSetFieldImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
compilerContext.symbolTable.referenceField(property),
receiver,
IrGetValueImpl(startOffset, endOffset, irValueParameter.type, irValueParameter.symbol),
compilerContext.irBuiltIns.unitType
)
)
return irBody
}
fun generateReceiverExpressionForFieldAccess(
ownerSymbol: IrValueSymbol,
property: PropertyDescriptor
): IrExpression {
val containingDeclaration = property.containingDeclaration
return when (containingDeclaration) {
is ClassDescriptor ->
IrGetValueImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
// symbolTable.referenceValue(containingDeclaration.thisAsReceiverParameter)
ownerSymbol
)
else -> throw AssertionError("Property must be in class")
}
}
// todo: delet zis
fun IrFunction.createParameterDeclarations(receiver: IrValueParameter? = null) {
fun ParameterDescriptor.irValueParameter() = IrValueParameterImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
SERIALIZABLE_PLUGIN_ORIGIN,
this,
type.toIrType(),
(this as? ValueParameterDescriptor)?.varargElementType?.toIrType()
).also {
it.parent = this@createParameterDeclarations
}
dispatchReceiverParameter = receiver ?: (descriptor.dispatchReceiverParameter?.irValueParameter())
extensionReceiverParameter = descriptor.extensionReceiverParameter?.irValueParameter()
assert(valueParameters.isEmpty())
descriptor.valueParameters.mapTo(valueParameters) { it.irValueParameter() }
assert(typeParameters.isEmpty())
descriptor.typeParameters.mapTo(typeParameters) {
IrTypeParameterImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
SERIALIZABLE_PLUGIN_ORIGIN,
it
).also { typeParameter ->
typeParameter.parent = this
}
}
}
}
@@ -0,0 +1,46 @@
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.irReturn
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.util.TypeTranslator
import org.jetbrains.kotlin.resolve.BindingContext
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
class SerializableCompanionIrGenerator(
val irClass: IrClass,
override val compilerContext: BackendContext,
bindingContext: BindingContext
) : SerializableCompanionCodegen(irClass.descriptor), IrBuilderExtension {
override val translator: TypeTranslator = TypeTranslator(compilerContext.symbolTable)
companion object {
fun generate(irClass: IrClass,
context: BackendContext,
bindingContext: BindingContext) {
val companionDescriptor = irClass.descriptor
val serializableClass = getSerializableClassDescriptorByCompanion(companionDescriptor) ?: return
if (serializableClass.isInternalSerializable)
SerializableCompanionIrGenerator(irClass, context, bindingContext).generate()
}
}
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) = irClass.contributeFunction(methodDescriptor) { getter ->
val serializer = serializableDescriptor.classSerializer?.toClassDescriptor!!
val expr = if (serializer.kind == ClassKind.OBJECT) {
irGetObject(serializer)
} else {
val ctor = compilerContext.symbolTable.referenceConstructor(serializer.unsubstitutedPrimaryConstructor!!)
val args: List<IrExpression> = emptyList() // todo
irInvoke(null, ctor, *args.toTypedArray())
}
+irReturn(expr)
}
}
@@ -0,0 +1,111 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.lower.irThrow
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.util.TypeTranslator
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen
import org.jetbrains.kotlinx.serialization.compiler.resolve.getClassFromSerializationPackage
import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable
class SerializableIrGenerator(
val irClass: IrClass,
override val compilerContext: BackendContext,
bindingContext: BindingContext
) : SerializableCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
override val translator: TypeTranslator = TypeTranslator(compilerContext.symbolTable)
override fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor) =
irClass.contributeConstructor(constructorDescriptor) { ctor ->
val original = irClass.constructors.singleOrNull { it.isPrimary } ?: throw IllegalStateException("Serializable class must have single primary constructor")
// default arguments of original constructor
val defaultsMap: Map<ParameterDescriptor, IrExpression?> = original.valueParameters.associate { it.descriptor to it.defaultValue?.expression }
fun transformFieldInitializer(f: IrField): IrExpression? {
val i = f.initializer?.expression ?: return null
return if (i is IrGetValueImpl && i.origin == IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER) {
// this is a primary constructor property, use corresponding default of value parameter
defaultsMap.getValue(i.descriptor as ParameterDescriptor)
} else {
i
}
}
// Missing field exception parts
val exceptionCtor =
serializableDescriptor.getClassFromSerializationPackage("MissingFieldException")
.unsubstitutedPrimaryConstructor!!
val exceptionCtorRef = compilerContext.symbolTable.referenceConstructor(exceptionCtor)
val exceptionType = exceptionCtor.returnType.toIrType()
val thiz = irClass.thisReceiver!!
if (KotlinBuiltIns.isAny(irClass.descriptor.getSuperClassOrAny()))
generateAnySuperConstructorCall(toBuilder = this@contributeConstructor)
else
TODO("Serializable classes with inheritance")
val seenVar = ctor.valueParameters[0]
for ((index, prop) in properties.serializableProperties.withIndex()) {
val paramRef = ctor.valueParameters[index + 1]
// assign this.a = a in else branch
val assignParamExpr = irSetField(irGet(thiz), prop.irField, 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)
} else {
irThrow(irInvoke(null, exceptionCtorRef, irString(prop.name), typeHint = exceptionType))
}
val propNotSeenTest =
irEquals(
irInt(0),
irBinOp(OperatorNameConventions.AND, irGet(seenVar), irInt(1 shl (index % 32)))
)
+irIfThenElse(compilerContext.irBuiltIns.unitType, propNotSeenTest, ifNotSeenExpr, assignParamExpr)
}
// todo: transient initializers and init blocks
// remaining initalizers of variables
// val serialDescs = properties.serializableProperties.map { it.descriptor }.toSet()
// irClass.declarations.asSequence()
// .filterIsInstance<IrProperty>()
// .filter { it.descriptor !in serialDescs }
// .filter { it.backingField != null }
// .mapNotNull { prop -> prop.backingField!!.initializer?.let { prop to it.expression } }
// .forEach { (prop, expr) -> +irSetField(irGet(thiz), prop.backingField!!, expr) }
}
override fun generateWriteSelfMethod(methodDescriptor: FunctionDescriptor) {
// no-op
}
companion object {
fun generate(
irClass: IrClass,
context: BackendContext,
bindingContext: BindingContext
) {
if (irClass.descriptor.isInternalSerializable)
SerializableIrGenerator(irClass, context, bindingContext).generate()
}
}
}
@@ -0,0 +1,378 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.BackendContext
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irThrow
import org.jetbrains.kotlin.descriptors.*
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.mapValueParameters
import org.jetbrains.kotlin.ir.expressions.mapValueParametersIndexed
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.TypeTranslator
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.withScope
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
// Is creating synthetic origin is a good idea or not?
object SERIALIZABLE_PLUGIN_ORIGIN : IrDeclarationOriginImpl("SERIALIZER")
class SerializerIrGenerator(val irClass: IrClass, override val compilerContext: BackendContext, bindingContext: BindingContext) :
SerializerCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
override val translator: TypeTranslator = TypeTranslator(compilerContext.symbolTable)
override fun generateSerialDesc() {
val desc: PropertyDescriptor = serialDescPropertyDescriptor ?: return
val serialDescImplClass = serializerDescriptor
.getClassFromInternalSerializationPackage("SerialClassDescImpl")
val serialDescImplConstructor = serialDescImplClass
.unsubstitutedPrimaryConstructor!!
val addFuncS = serialDescImplClass.referenceMethod("addElement")
val thisAsReceiverParameter = irClass.thisReceiver!!
lateinit var prop: IrProperty
// how to (auto)create backing field and getter/setter?
compilerContext.symbolTable.withScope(irClass.descriptor) {
introduceValueParameter(thisAsReceiverParameter)
prop = generateSimplePropertyWithBackingField(thisAsReceiverParameter.symbol, desc, irClass)
irClass.addMember(prop)
}
compilerContext.symbolTable.declareAnonymousInitializer(
irClass.startOffset, irClass.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, irClass.descriptor
).buildWithScope { initIrBody ->
val ctor = irClass.declarations.filterIsInstance<IrConstructor>().singleOrNull()
val serialClassDescImplCtor = compilerContext.symbolTable.referenceConstructor(serialDescImplConstructor)
compilerContext.symbolTable.withScope(initIrBody.descriptor) {
initIrBody.body = compilerContext.createIrBuilder(initIrBody.symbol).irBlockBody {
val localDesc = irTemporary(
irCall(
serialClassDescImplCtor,
type = serialDescImplConstructor.returnType.toIrType()
).mapValueParameters { irString(serialName) },
nameHint = "serialDesc"
)
fun addFieldCall(fieldName: String) =
irCall(addFuncS, type = compilerContext.irBuiltIns.unitType).apply {
dispatchReceiver = irGet(localDesc)
}.mapValueParameters { irString(fieldName) }
for (classProp in orderedProperties) {
if (classProp.transient) continue
+addFieldCall(classProp.name)
// serialDesc.pushAnnotation(...) todo
}
+irSetField(
generateReceiverExpressionForFieldAccess(
thisAsReceiverParameter.symbol,
serialDescPropertyDescriptor
),
prop.backingField!!,
irGet(localDesc)
)
}
// workaround for KT-25353
// irClass.addMember(initIrBody)
(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 generateSerializableClassProperty(property: PropertyDescriptor) {
// TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
private fun IrBuilderWithScope.serializerInstance(
serializerClass: ClassDescriptor?,
module: ModuleDescriptor,
kType: KotlinType,
genericIndex: Int? = null
): IrExpression? {
val nullableSerClass =
compilerContext.symbolTable.referenceClass(module.getClassFromInternalSerializationPackage("NullableSerializer"))
if (serializerClass == null) {
if (genericIndex == null) return null
return TODO("Saved serializer for generic argument")
}
if (serializerClass.kind == ClassKind.OBJECT) {
return irGetObject(serializerClass)
} else {
var args = if (serializerClass.classId == enumSerializerId || serializerClass.classId == contextSerializerId)
TODO("enum and context serializer")
else kType.arguments.map {
val argSer = findTypeSerializerOrContext(module, it.type)
val expr = serializerInstance(argSer, module, it.type, it.type.genericIndex) ?: return null
// todo: smth better than constructors[0] ??
if (it.type.isMarkedNullable) irInvoke(null, nullableSerClass.constructors.toList()[0], expr) else expr
}
if (serializerClass.classId == referenceArraySerializerId)
args = TODO("reference array serializer")
val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
val ctor = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializerClass, serializableDescriptor)
.let { compilerContext.symbolTable.referenceConstructor(it) }
} else {
compilerContext.symbolTable.referenceConstructor(serializerClass.unsubstitutedPrimaryConstructor!!)
}
return irInvoke(
null,
ctor,
*args.toTypedArray()
)
}
}
fun ClassDescriptor.referenceMethod(methodName: String) =
getFuncDesc(methodName).single().let { compilerContext.symbolTable.referenceFunction(it) }
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc ->
fun irThis(): IrExpression =
IrGetValueImpl(startOffset, endOffset, saveFunc.dispatchReceiverParameter!!.symbol)
val kOutputClass = serializerDescriptor.getClassFromSerializationPackage("StructureEncoder")
val descriptorGetterSymbol = compilerContext.symbolTable.referenceFunction(serialDescPropertyDescriptor?.getter!!)
val localSerialDesc = irTemporary(irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol), "desc")
// fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): StructureEncoder
val beginFunc = kOutputClass.referenceMethod("beginStructure") // todo: retrieve from actual encoder instead
val call = irCall(beginFunc).mapValueParametersIndexed { i, parameterDescriptor ->
if (i == 0) irGet(localSerialDesc) else IrVarargImpl(
startOffset,
endOffset,
parameterDescriptor.type.toIrType(),
parameterDescriptor.varargElementType!!.toIrType()
)
}
// can it be done in more concise way? e.g. additional builder function?
call.dispatchReceiver = irGet(saveFunc.valueParameters[0])
val serialObjectSymbol = saveFunc.valueParameters[1]
val localOutput = irTemporary(call, "output")
// internal serialization via virtual calls?
val labeledProperties = orderedProperties.filter { !it.transient }
for (index in labeledProperties.indices) {
val property = labeledProperties[index]
if (property.transient) continue
// output.writeXxxElementValue(classDesc, index, value)
val sti = getSerialTypeInfo(property)
val innerSerial = serializerInstance(sti.serializer, property.module, property.type, property.genericIndex)
if (innerSerial == null) {
val writeFunc =
kOutputClass.referenceMethod("encode${sti.elementMethodPrefix}ElementValue")
+irInvoke(
irGet(localOutput),
writeFunc,
irGet(localSerialDesc),
irInt(index),
// todo: direct field access?
// irInvoke(irGet(serialObjectSymbol), compilerContext.symbolTable.referenceFunction(property.descriptor.getter!!))
irGetField(irGet(serialObjectSymbol), compilerContext.symbolTable.referenceField(property.descriptor).owner)
)
} else {
val writeFunc = kOutputClass.referenceMethod("encode${sti.elementMethodPrefix}SerializableElementValue")
+irInvoke(
irGet(localOutput),
writeFunc,
irGet(localSerialDesc),
irInt(index),
innerSerial,
// todo: direct field access?
// irInvoke(irGet(serialObjectSymbol), compilerContext.symbolTable.referenceFunction(property.descriptor.getter!!))
irGetField(irGet(serialObjectSymbol), compilerContext.symbolTable.referenceField(property.descriptor).owner)
)
}
}
// output.writeEnd(serialClassDesc)
val wEndFunc = kOutputClass.referenceMethod("endStructure")
+irInvoke(irGet(localOutput), wEndFunc, irGet(localSerialDesc))
}
// returns null: Any? for boxed types and 0: <number type> for primitives
fun IrBuilderWithScope.defaultValueAndType(prop: SerializableProperty): Pair<IrExpression, KotlinType> {
val kType = prop.descriptor.returnType!!
val T = kType.toIrType()
val defaultPrimitive: IrExpression? = when {
T.isInt() -> IrConstImpl.int(startOffset, endOffset, T, 0)
T.isBoolean() -> IrConstImpl.boolean(startOffset, endOffset, T, false)
T.isLong() -> IrConstImpl.long(startOffset, endOffset, T, 0)
T.isDouble() -> IrConstImpl.double(startOffset, endOffset, T, 0.0)
T.isFloat() -> IrConstImpl.float(startOffset, endOffset, T, 0.0f)
T.isChar() -> IrConstImpl.char(startOffset, endOffset, T, 0.toChar())
T.isByte() -> IrConstImpl.byte(startOffset, endOffset, T, 0)
T.isShort() -> IrConstImpl.short(startOffset, endOffset, T, 0)
else -> null
}
return if (defaultPrimitive == null)
irNull() to (compilerContext.builtIns.nullableAnyType)
else
defaultPrimitive to kType
}
override fun generateLoad(function: FunctionDescriptor) = irClass.contributeFunction(function) { loadFunc ->
fun irThis(): IrExpression =
IrGetValueImpl(startOffset, endOffset, loadFunc.dispatchReceiverParameter!!.symbol)
fun IrVariable.get() = irGet(this)
val inputClass = serializerDescriptor.getClassFromSerializationPackage("StructureDecoder")
val descriptorGetterSymbol = compilerContext.symbolTable.referenceFunction(serialDescPropertyDescriptor?.getter!!)
val localSerialDesc = irTemporary(irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol), "desc")
// workaround due to unavailability of labels (KT-25386)
val flagVar = irTemporaryVar(irBoolean(true), "flag", parent = loadFunc)
val indexVar = irTemporaryVar(irInt(0), "index", parent = loadFunc)
// val readAll = irTemporaryVar(irBoolean(false), "readAll", parent = loadFunc)
//
// calculating bit mask vars
val blocksCnt = orderedProperties.size / 32 + 1
// var bitMask0 = 0, bitMask1 = 0...
val bitMasks = (0 until blocksCnt).map { irTemporaryVar(irInt(0), "bitMask$it", parent = loadFunc) }
// var local0 = null, local1 = null ...
val localProps = orderedProperties.mapIndexed { i, prop ->
val (expr, type) = defaultValueAndType(prop)
irTemporaryVar(
expr,
"local$i",
typeHint = type,
parent = loadFunc
)
}
//input = input.beginStructure(...)
val beginFunc = inputClass.referenceMethod("beginStructure")
val call = irInvoke(
irGet(loadFunc.valueParameters[0]),
beginFunc,
irGet(localSerialDesc),
irEmptyVararg(beginFunc.descriptor.valueParameters[1])
)
val localInput = irTemporary(call, "input")
+irWhile().also { loop ->
loop.condition = flagVar.get()
loop.body = irBlock {
val readElementF = inputClass.referenceMethod("decodeElement")
+irSetVar(indexVar.symbol, irInvoke(localInput.get(), readElementF, localSerialDesc.get()))
+irWhen {
// if index == -2 (READ_ALL) todo...
+IrBranchImpl(irEquals(indexVar.get(), irInt(-2)), irThrowNpe())
// if index == -1 (READ_DONE) break loop
+IrBranchImpl(irEquals(indexVar.get(), irInt(-1)), irSetVar(flagVar.symbol, irBoolean(false)))
val branchBodies: List<Pair<Int, IrExpression>> = orderedProperties.mapIndexed { index, property ->
val body = irBlock {
val sti = getSerialTypeInfo(property)
val innerSerial = serializerInstance(sti.serializer, property.module, property.type, property.genericIndex)
// todo: update
val decodeFuncToCall =
(if (innerSerial != null) "decode${sti.elementMethodPrefix}SerializableElementValue"
else "decode${sti.elementMethodPrefix}ElementValue")
.let {
inputClass.referenceMethod(it)
}
val args = mutableListOf<IrExpression>(localSerialDesc.get(), irInt(index))
if (innerSerial != null)
args.add(innerSerial)
// local$i = localInput.decode...(...)
+irSetVar(localProps[index].symbol, irInvoke(localInput.get(), decodeFuncToCall, *args.toTypedArray()))
// bitMask[i] |= 1 << x
val bitPos = 1 shl (index % 32)
val or = irBinOp(OperatorNameConventions.OR, bitMasks[index / 32].get(), irInt(bitPos))
+irSetVar(bitMasks[index / 32].symbol, or)
}
index to body
}
branchBodies.forEach { (i, e) -> +IrBranchImpl(irEquals(indexVar.get(), irInt(i)), e) }
// throw exception on unknown field
val exceptionCtor =
serializableDescriptor.getClassFromSerializationPackage("UnknownFieldException")
.unsubstitutedPrimaryConstructor!!
val excClassRef = compilerContext.symbolTable.referenceConstructor(exceptionCtor)
+elseBranch(
irThrow(
irInvoke(
null,
excClassRef,
indexVar.get(),
typeHint = exceptionCtor.returnType.toIrType()
)
)
)
}
}
}
//input.endStructure(...)
val endFunc = inputClass.referenceMethod("endStructure")
+irInvoke(
localInput.get(),
endFunc,
irGet(localSerialDesc)
)
// todo: set properties in external deserialization
var args: List<IrExpression> = localProps.map { it.get() }
val ctor: IrConstructorSymbol = if (serializableDescriptor.isInternalSerializable) {
val ctorDesc = compilerContext.symbolTable.referenceClass(serializableDescriptor)
.owner.constructors.single { it.origin == SERIALIZABLE_PLUGIN_ORIGIN }
args = listOf(irGet(bitMasks[0])) + args + irNull()
ctorDesc.symbol
} else {
compilerContext.symbolTable.referenceConstructor(serializableDescriptor.unsubstitutedPrimaryConstructor!!)
}
+irReturn(irInvoke(null, ctor, *args.toTypedArray()))
}
companion object {
fun generate(
irClass: IrClass,
context: BackendContext,
bindingContext: BindingContext
) {
if (getSerializableClassDescriptorBySerializer(irClass.descriptor) != null)
SerializerIrGenerator(irClass, context, bindingContext).generate()
}
}
}
@@ -29,9 +29,11 @@ import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
class SerializableCompanionJsTranslator(declaration: KtPureClassOrObject,
val translator: DeclarationBodyVisitor,
val context: TranslationContext): SerializableCompanionCodegen(declaration, context.bindingContext()) {
class SerializableCompanionJsTranslator(
declaration: ClassDescriptor,
val translator: DeclarationBodyVisitor,
val context: TranslationContext): SerializableCompanionCodegen(declaration) {
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
val f = context.buildFunction(methodDescriptor) {jsFun, context ->
val serializer = serializableDescriptor.classSerializer?.toClassDescriptor!!
@@ -52,7 +54,7 @@ class SerializableCompanionJsTranslator(declaration: KtPureClassOrObject,
fun translate(declaration: KtPureClassOrObject, descriptor: ClassDescriptor, translator: DeclarationBodyVisitor, context: TranslationContext) {
val serializableClass = getSerializableClassDescriptorByCompanion(descriptor) ?: return
if (serializableClass.isInternalSerializable)
SerializableCompanionJsTranslator(declaration, translator, context).generate()
SerializableCompanionJsTranslator(descriptor, translator, context).generate()
}
}
}
@@ -37,9 +37,10 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializab
class SerializableJsTranslator(
val declaration: KtPureClassOrObject,
val descriptor: ClassDescriptor,
val translator: DeclarationBodyVisitor,
val context: TranslationContext
) : SerializableCodegen(declaration, context.bindingContext()) {
) : SerializableCodegen(descriptor, context.bindingContext()) {
private val initMap: Map<PropertyDescriptor, KtExpression?> = declaration.run {
(bodyPropertiesDescriptorsMap(context.bindingContext()).mapValues { it.value.delegateExpressionOrInitializer } +
@@ -109,7 +110,7 @@ class SerializableJsTranslator(
context: TranslationContext
) {
if (descriptor.isInternalSerializable)
SerializableJsTranslator(declaration, translator, context).generate()
SerializableJsTranslator(declaration, descriptor, translator, context).generate()
}
}
}
@@ -119,13 +119,10 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
context.addDeclarationStatement(f.makeStmt())
}
private fun ClassDescriptor.getFuncDesc(funcName: String) =
unsubstitutedMemberScope.getDescriptorsFiltered { it == Name.identifier(funcName) }
override fun generateSave(function: FunctionDescriptor) = generateFunction(function) { jsFun, ctx ->
val kOutputClass = serializerDescriptor.getClassFromSerializationPackage("StructureEncoder")
val wBeginFunc = ctx.getNameForDescriptor(
kOutputClass.getFuncDesc("beginStructure").single { (it as FunctionDescriptor).valueParameters.size == 2 })
kOutputClass.getFuncDesc("beginStructure").single { it.valueParameters.size == 2 })
val serialClassDescRef = JsNameRef(context.getNameForDescriptor(serialDescPropertyDescriptor!!), JsThisRef())
// output.writeBegin(desc, [])
@@ -41,7 +41,7 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
class SerializableCodegenImpl(
private val classCodegen: ImplementationBodyCodegen,
serializableClass: ClassDescriptor
) : SerializableCodegen(classCodegen.myClass, classCodegen.bindingContext) {
) : SerializableCodegen(classCodegen.descriptor, classCodegen.bindingContext) {
private val thisAsmType = classCodegen.typeMapper.mapClass(serializableDescriptor)
@@ -23,7 +23,7 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableC
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
class SerializableCompanionCodegenImpl(private val codegen: ImplementationBodyCodegen) :
SerializableCompanionCodegen(codegen.myClass, codegen.bindingContext) {
SerializableCompanionCodegen(codegen.descriptor) {
companion object {
fun generateSerializableExtensions(codegen: ImplementationBodyCodegen) {
@@ -0,0 +1,60 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.extensions
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.resolve.BindingContext
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
/**
* Copy of [runOnFilePostfix], but this implementation first lowers declaration, then its children.
*/
fun ClassLoweringPass.runOnFileInOrder(irFile: IrFile) {
irFile.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitClass(declaration: IrClass) {
lower(declaration)
declaration.acceptChildrenVoid(this)
}
})
}
private class SerializerClassLowering(
val context: BackendContext,
val bindingContext: BindingContext
) :
IrElementTransformerVoid(), ClassLoweringPass {
override fun lower(irClass: IrClass) {
SerializableIrGenerator.generate(irClass, context, bindingContext)
SerializerIrGenerator.generate(irClass, context, bindingContext)
SerializableCompanionIrGenerator.generate(irClass, context, bindingContext)
}
}
class SerializationLoweringExtension : IrGenerationExtension {
override fun generate(
file: IrFile,
backendContext: BackendContext,
bindingContext: BindingContext
) {
SerializerClassLowering(backendContext, bindingContext).runOnFileInOrder(file)
}
}
@@ -280,7 +280,7 @@ object KSerializerDescriptorResolver {
fun createTypedSerializerConstructorDescriptor(
classDescriptor: ClassDescriptor,
serializableDescriptor: ClassDescriptor
): ConstructorDescriptor {
): ClassConstructorDescriptor {
val constrDesc = ClassConstructorDescriptorImpl.createSynthesized(
classDescriptor,
Annotations.EMPTY,