Support static final write$Self method inside serializable classes on IR

to properly serialize class hierarchies with/or private fields.
JVM only for now, because Native/JS do not have private fields.
Update tests and test data and rebase fix.
Unify formEncodeDecodePropertyCall functions.
Fix incorrect reference to object in writeSelf,
so properties dependent on other properties would be correctly compared
with defaults.
This commit is contained in:
Leonid Startsev
2021-03-02 19:09:09 +03:00
parent 9be5421e7c
commit 3b789448a3
22 changed files with 387 additions and 167 deletions
@@ -1,15 +1,16 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2021 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.common
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.secondaryConstructors
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
abstract class SerializableCodegen(
@@ -37,7 +38,15 @@ abstract class SerializableCodegen(
private fun generateSyntheticMethods() {
val serializerDescriptor = serializableDescriptor.classSerializer ?: return
if (serializableDescriptor.shouldHaveSpecificSyntheticMethods { SerializerCodegen.getSyntheticSaveMember(serializerDescriptor) }) {
val func = KSerializerDescriptorResolver.createWriteSelfFunctionDescriptor(serializableDescriptor)
val func =
serializableDescriptor.unsubstitutedMemberScope.getContributedFunctions(
Name.identifier(SerialEntityNames.WRITE_SELF_NAME.toString()),
NoLookupLocation.FROM_BACKEND
).singleOrNull { function ->
function.kind == CallableMemberDescriptor.Kind.SYNTHESIZED &&
function.modality == Modality.FINAL &&
function.returnType?.isUnit() ?: false
} ?: return
generateWriteSelfMethod(func)
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2021 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.
*/
@@ -70,7 +70,7 @@ abstract class SerializerCodegen(
serializerDescriptor::checkSerializableClassPropertyResult
) { true }
lateinit var localSerializersFieldsDescriptors: List<Pair<PropertyDescriptor, IrProperty>>
var localSerializersFieldsDescriptors: List<Pair<PropertyDescriptor, IrProperty>> = emptyList()
protected set
// Can be false if user specified inheritance from KSerializer explicitly
@@ -7,6 +7,7 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irIfThen
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
@@ -59,9 +60,9 @@ interface IrBuilderExtension {
return throwMissedFieldExceptionFunc != null && throwMissedFieldExceptionArrayFunc != null
}
fun IrClass.contributeFunction(descriptor: FunctionDescriptor, bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit) {
val f: IrSimpleFunction = searchForDeclaration(descriptor) ?: compilerContext.symbolTable.referenceSimpleFunction(descriptor).owner
// TODO: default parameters
fun IrClass.contributeFunction(descriptor: FunctionDescriptor, ignoreWhenMissing: Boolean = false, bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit) {
val f: IrSimpleFunction = searchForDeclaration(descriptor)
?: (if (ignoreWhenMissing) return else compilerContext.symbolTable.referenceSimpleFunction(descriptor).owner)
f.body = DeclarationIrBuilder(compilerContext, f.symbol, this.startOffset, this.endOffset).irBlockBody(
this.startOffset,
this.endOffset
@@ -489,7 +490,7 @@ interface IrBuilderExtension {
)
}.also { f ->
generateOverriddenFunctionSymbols(f, compilerContext.symbolTable)
f.createParameterDeclarations(receiver = null)
f.createParameterDeclarations(descriptor)
f.returnType = descriptor.returnType!!.toIrType()
f.correspondingPropertySymbol = fieldSymbol.owner.correspondingPropertySymbol
}
@@ -572,7 +573,7 @@ interface IrBuilderExtension {
}
fun IrFunction.createParameterDeclarations(
receiver: IrValueParameter?,
descriptor: FunctionDescriptor,
overwriteValueParameters: Boolean = false,
copyTypeParameters: Boolean = true
) {
@@ -589,7 +590,7 @@ interface IrBuilderExtension {
if (copyTypeParameters) {
assert(typeParameters.isEmpty())
copyTypeParamsFromDescriptor()
copyTypeParamsFromDescriptor(descriptor)
}
dispatchReceiverParameter = descriptor.dispatchReceiverParameter?.let { irValueParameter(it) }
@@ -601,7 +602,7 @@ interface IrBuilderExtension {
valueParameters = descriptor.valueParameters.map { irValueParameter(it) }
}
fun IrFunction.copyTypeParamsFromDescriptor() {
fun IrFunction.copyTypeParamsFromDescriptor(descriptor: FunctionDescriptor) {
val newTypeParameters = descriptor.typeParameters.map {
factory.createTypeParameter(
startOffset, endOffset,
@@ -991,4 +992,98 @@ interface IrBuilderExtension {
return superClasses.singleOrNull { it.kind == ClassKind.CLASS }
}
fun IrClass.findWriteSelfMethod(): IrSimpleFunction? =
declarations.filter { it is IrSimpleFunction && it.name == SerialEntityNames.WRITE_SELF_NAME && !it.isFakeOverride }
.takeUnless(Collection<*>::isEmpty)?.single() as IrSimpleFunction?
fun IrBlockBodyBuilder.serializeAllProperties(
generator: AbstractSerialGenerator,
serializableIrClass: IrClass,
serializableProperties: List<SerializableProperty>,
objectToSerialize: IrValueDeclaration,
localOutput: IrValueDeclaration,
localSerialDesc: IrValueDeclaration,
kOutputClass: ClassDescriptor,
ignoreIndexTo: Int,
initializerAdapter: (IrExpressionBody) -> IrExpression,
genericGetter: ((Int, KotlinType) -> IrExpression)?
) {
fun SerializableProperty.irGet(): IrExpression {
val ownerType = objectToSerialize.symbol.owner.type
return getProperty(
irGet(
type = ownerType,
variable = objectToSerialize.symbol
), getIrPropertyFrom(serializableIrClass)
)
}
for ((index, property) in serializableProperties.withIndex()) {
if (index < ignoreIndexTo) continue
// output.writeXxxElementValue(classDesc, index, value)
val elementCall = formEncodeDecodePropertyCall(
generator,
irGet(localOutput),
property, { innerSerial, sti ->
val f =
kOutputClass.referenceFunctionSymbol("${CallingConventions.encode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}")
f to listOf(
irGet(localSerialDesc),
irInt(index),
innerSerial,
property.irGet()
)
}, {
val f =
kOutputClass.referenceFunctionSymbol("${CallingConventions.encode}${it.elementMethodPrefix}${CallingConventions.elementPostfix}")
val args: MutableList<IrExpression> = mutableListOf(irGet(localSerialDesc), irInt(index))
if (it.elementMethodPrefix != "Unit") args.add(property.irGet())
f to args
},
genericGetter
)
// check for call to .shouldEncodeElementDefault
if (!property.optional) {
// emit call right away
+elementCall
} else {
// emit check:
// if (if (output.shouldEncodeElementDefault(this.descriptor, i)) true else {obj.prop != DEFAULT_VALUE} ) {
// output.encodeIntElement(this.descriptor, i, obj.prop)// block {obj.prop != DEFAULT_VALUE} may contain several statements
val shouldEncodeFunc = kOutputClass.referenceFunctionSymbol(CallingConventions.shouldEncodeDefault)
val partA = irInvoke(irGet(localOutput), shouldEncodeFunc, irGet(localSerialDesc), irInt(index))
val partB = irNotEquals(property.irGet(), initializerAdapter(property.irField.initializer!!))
// Ir infrastructure does not have dedicated symbol for ||, so
// `a || b == if (a) true else b`, see org.jetbrains.kotlin.ir.builders.PrimitivesKt.oror
val condition = irIfThenElse(compilerContext.irBuiltIns.booleanType, partA, irTrue(), partB)
+irIfThen(condition, elementCall)
}
}
}
fun IrBlockBodyBuilder.formEncodeDecodePropertyCall(
enclosingGenerator: AbstractSerialGenerator,
encoder: IrExpression,
property: SerializableProperty,
whenHaveSerializer: (serializer: IrExpression, sti: SerialTypeInfo) -> FunctionWithArgs,
whenDoNot: (sti: SerialTypeInfo) -> FunctionWithArgs,
genericGetter: ((Int, KotlinType) -> IrExpression)? = null,
returnTypeHint: IrType? = null
): IrExpression {
val sti = enclosingGenerator.getSerialTypeInfo(property)
val innerSerial = serializerInstance(
enclosingGenerator,
sti.serializer,
property.module,
property.type,
property.genericIndex,
genericGetter
)
val (functionToCall, args: List<IrExpression>) = if (innerSerial != null) whenHaveSerializer(innerSerial, sti) else whenDoNot(sti)
val typeArgs = if (functionToCall.descriptor.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf()
return irInvoke(encoder, functionToCall, typeArguments = typeArgs, valueArguments = args, returnTypeHint = returnTypeHint)
}
}
@@ -25,9 +25,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.getOrPutNullable
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.isStaticSerializable
import org.jetbrains.kotlinx.serialization.compiler.backend.common.serialName
import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
@@ -284,7 +282,57 @@ class SerializableIrGenerator(
}
override fun generateWriteSelfMethod(methodDescriptor: FunctionDescriptor) {
// no-op
irClass.contributeFunction(methodDescriptor, ignoreWhenMissing = true) { writeSelfFunction ->
val objectToSerialize = writeSelfFunction.valueParameters[0]
val localOutput = writeSelfFunction.valueParameters[1]
val localSerialDesc = writeSelfFunction.valueParameters[2]
val serializableProperties = properties.serializableProperties
val kOutputClass = serializableDescriptor.getClassFromSerializationPackage(SerialEntityNames.STRUCTURE_ENCODER_CLASS)
val propertyByParamReplacer: (ValueParameterDescriptor) -> IrExpression? =
createPropertyByParamReplacer(irClass, serializableProperties, objectToSerialize, bindingContext)
// Since writeSelf is a static method, we have to replace all references to this in property initializers
val thisSymbol = irClass.thisReceiver!!.symbol
val initializerAdapter: (IrExpressionBody) -> IrExpression = createInitializerAdapter(irClass, propertyByParamReplacer, thisSymbol to { irGet(objectToSerialize) })
// Compute offset of properties in superclass
var ignoreIndexTo = -1
val superClass = irClass.getSuperClassOrAny()
if (superClass.descriptor.isInternalSerializable) {
ignoreIndexTo = bindingContext.serializablePropertiesFor(superClass.descriptor).size
// call super.writeSelf
val superWriteSelfF = superClass.findWriteSelfMethod()
if (superWriteSelfF != null) {
val args = mutableListOf<IrExpression>(irGet(objectToSerialize), irGet(localOutput), irGet(localSerialDesc))
val typeArgsForParent = serializableDescriptor.typeConstructor.supertypes.single { it.toClassDescriptor?.isInternalSerializable == true }.arguments
val parentWriteSelfSerializers = typeArgsForParent.map { arg ->
val genericIdx = serializableDescriptor.defaultType.arguments.indexOf(arg).let { if (it == -1) null else it }
val serial = findTypeSerializerOrContext(serializableDescriptor.module, arg.type)
serializerInstance(
this@SerializableIrGenerator,
serial,
serializableDescriptor.module,
arg.type,
genericIdx
) { it, _ ->
irGet(writeSelfFunction.valueParameters[3 + it])
}!!
}
+irInvoke(null, superWriteSelfF.symbol, typeArgsForParent.map { it.type.toIrType() }, args + parentWriteSelfSerializers)
}
}
serializeAllProperties(
this@SerializableIrGenerator, irClass, serializableProperties,
objectToSerialize, localOutput, localSerialDesc,
kOutputClass, ignoreIndexTo, initializerAdapter
) { it, _ ->
irGet(writeSelfFunction.valueParameters[3 + it])
}
}
}
companion object {
@@ -298,8 +346,7 @@ class SerializableIrGenerator(
if (serializableClass.isInternalSerializable) {
SerializableIrGenerator(irClass, context, bindingContext).generate()
irClass.patchDeclarationParents(irClass.parent)
}
else if (serializableClass.serializableAnnotationIsUseless) {
} else if (serializableClass.serializableAnnotationIsUseless) {
throw CompilationException(
"@Serializable annotation on $serializableClass would be ignored because it is impossible to serialize it automatically. " +
"Provide serializer manually via e.g. companion object", null, serializableClass.findPsi()
@@ -25,9 +25,9 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerialTypeInfo
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
@@ -196,13 +196,13 @@ open class SerializerIrGenerator(
val thisAsReceiverParameter = irClass.thisReceiver!!
ctor.valueParameters.forEachIndexed { index, param ->
val localSerial = localSerializersFieldsDescriptors[index].second.backingField!!
+irSetField(generateReceiverExpressionForFieldAccess(
thisAsReceiverParameter.symbol,
localSerializersFieldsDescriptors[index].first
), localSerial, irGet(param))
+irSetField(
generateReceiverExpressionForFieldAccess(
thisAsReceiverParameter.symbol,
localSerializersFieldsDescriptors[index].first
), localSerial, irGet(param)
)
}
}
override fun generateChildSerializersGetter(function: FunctionDescriptor) = irClass.contributeFunction(function) { irFun ->
@@ -256,69 +256,44 @@ open class SerializerIrGenerator(
val objectToSerialize = saveFunc.valueParameters[1]
val localOutput = irTemporary(call, "output")
fun SerializableProperty.irGet(): IrExpression {
val ownerType = objectToSerialize.symbol.owner.type
return getProperty(
irGet(
type = ownerType,
variable = objectToSerialize.symbol
), getIrPropertyFrom(serializableIrClass)
)
}
val writeSelfFunction = serializableIrClass.findWriteSelfMethod()
// 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 = serializableIrClass.getSuperClassOrAny().descriptor
val ignoreIndexTo = if (superClass.isInternalSerializable) {
bindingContext.serializablePropertiesFor(superClass).size
} else {
-1
}
val propertyByParamReplacer: (ValueParameterDescriptor) -> IrExpression? =
createPropertyByParamReplacer(serializableIrClass, serializableProperties, objectToSerialize, bindingContext)
val thisSymbol = serializableIrClass.thisReceiver!!.symbol
val initializerAdapter: (IrExpressionBody) -> IrExpression =
createInitializerAdapter(serializableIrClass, propertyByParamReplacer, thisSymbol to { irGet(objectToSerialize) })
// internal serialization via virtual calls?
for ((index, property) in serializableProperties.withIndex()) {
// output.writeXxxElementValue(classDesc, index, value)
val elementCall = formEncodeDecodePropertyCall(irGet(localOutput), saveFunc.dispatchReceiverParameter!!, property, {innerSerial, sti ->
val f =
kOutputClass.referenceFunctionSymbol("${CallingConventions.encode}${sti.elementMethodPrefix}Serializable${CallingConventions.elementPostfix}")
f to listOf(
irGet(localSerialDesc),
irInt(index),
innerSerial,
property.irGet()
if (writeSelfFunction != null) {
// extract Tx from KSerializer<Tx> list
val typeArgs =
localSerializersFieldsDescriptors.map { (_, ir) -> ir.backingField!!.type.cast<IrSimpleType>().arguments.single().typeOrNull }
val args = mutableListOf<IrExpression>(irGet(objectToSerialize), irGet(localOutput), irGet(localSerialDesc))
args.addAll(localSerializersFieldsDescriptors.map { (_, ir) ->
irGetField(
irGet(saveFunc.dispatchReceiverParameter!!),
ir.backingField!!
)
}, {
val f =
kOutputClass.referenceFunctionSymbol("${CallingConventions.encode}${it.elementMethodPrefix}${CallingConventions.elementPostfix}")
val args: MutableList<IrExpression> = mutableListOf(irGet(localSerialDesc), irInt(index))
if (it.elementMethodPrefix != "Unit") args.add(property.irGet())
f to args
})
// check for call to .shouldEncodeElementDefault
if (!property.optional || index < ignoreIndexTo) {
// emit call right away
+elementCall
+irInvoke(null, writeSelfFunction.symbol, typeArgs, args)
} else {
// No write$Self, old behaviour:
// 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.
val superClass = serializableIrClass.getSuperClassOrAny().descriptor
val ignoreIndexTo = if (superClass.isInternalSerializable) {
bindingContext.serializablePropertiesFor(superClass).size
} else {
// emit check:
// if ( if (output.shouldEncodeElementDefault(this.descriptor, i)) true else {obj.prop != DEFAULT_VALUE} ) {
// output.encodeIntElement(this.descriptor, i, obj.prop)
// block {obj.prop != DEFAULT_VALUE} may contain several statements
val shouldEncodeFunc = kOutputClass.referenceFunctionSymbol(CallingConventions.shouldEncodeDefault)
val partA = irInvoke(irGet(localOutput), shouldEncodeFunc, irGet(localSerialDesc), irInt(index))
val partB = irNotEquals(property.irGet(), initializerAdapter(property.irField.initializer!!))
// Ir infrastructure does not have dedicated symbol for ||, so
// `a || b == if (a) true else b`, see org.jetbrains.kotlin.ir.builders.PrimitivesKt.oror
val condition = irIfThenElse(compilerContext.irBuiltIns.booleanType, partA, irTrue(), partB)
+irIfThen(condition, elementCall)
-1
}
val propertyByParamReplacer: (ValueParameterDescriptor) -> IrExpression? =
createPropertyByParamReplacer(serializableIrClass, serializableProperties, objectToSerialize, bindingContext)
val thisSymbol = serializableIrClass.thisReceiver!!.symbol
val initializerAdapter: (IrExpressionBody) -> IrExpression =
createInitializerAdapter(serializableIrClass, propertyByParamReplacer, thisSymbol to { irGet(objectToSerialize) })
serializeAllProperties(
this@SerializerIrGenerator, serializableIrClass, serializableProperties, objectToSerialize,
localOutput, localSerialDesc, kOutputClass, ignoreIndexTo, initializerAdapter
) { it, _ ->
val (_, ir) = localSerializersFieldsDescriptors[it]
irGetField(irGet(saveFunc.dispatchReceiverParameter!!), ir.backingField!!)
}
}
@@ -327,27 +302,25 @@ open class SerializerIrGenerator(
+irInvoke(irGet(localOutput), wEndFunc, irGet(localSerialDesc))
}
protected inline fun IrBlockBodyBuilder.formEncodeDecodePropertyCall(
protected fun IrBlockBodyBuilder.formEncodeDecodePropertyCall(
encoder: IrExpression,
dispatchReceiver: IrValueParameter,
property: SerializableProperty,
whenHaveSerializer: (serializer: IrExpression, sti: SerialTypeInfo) -> FunctionWithArgs,
whenDoNot: (sti: SerialTypeInfo) -> FunctionWithArgs,
returnTypeHint: IrType? = null
): IrExpression {
val sti = getSerialTypeInfo(property)
val innerSerial = serializerInstance(
this@SerializerIrGenerator,
dispatchReceiver,
sti.serializer,
property.module,
property.type,
genericIndex = property.genericIndex
)
val (functionToCall, args: List<IrExpression>) = if (innerSerial != null) whenHaveSerializer(innerSerial, sti) else whenDoNot(sti)
val typeArgs = if (functionToCall.descriptor.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf()
return irInvoke(encoder, functionToCall, typeArguments = typeArgs, valueArguments = args, returnTypeHint = returnTypeHint)
}
): IrExpression = formEncodeDecodePropertyCall(
this@SerializerIrGenerator,
encoder,
property,
whenHaveSerializer,
whenDoNot,
{ it, _ ->
val (_, ir) = localSerializersFieldsDescriptors[it]
irGetField(irGet(dispatchReceiver), ir.backingField!!)
},
returnTypeHint
)
// returns null: Any? for boxed types and 0: <number type> for primitives
private fun IrBuilderWithScope.defaultValueAndType(descriptor: PropertyDescriptor): Pair<IrExpression, IrType> {
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2021 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.
*/
@@ -39,9 +39,25 @@ open class SerializationResolveExtension @JvmOverloads constructor(val metadataP
override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List<Name> = when {
thisDescriptor.isSerializableObject || thisDescriptor.isCompanionObject && getSerializableClassDescriptorByCompanion(thisDescriptor) != null ->
listOf(SerialEntityNames.SERIALIZER_PROVIDER_NAME)
thisDescriptor.isInternalSerializable && thisDescriptor.platform?.isJvm() == true && !hasCustomizedSerializeMethod(thisDescriptor) -> {
// add write$Self, but only if .serialize was not customized in companion.
// It works not only on JVM, but I see no reason to enable it on other platforms —
// private fields there have no access control, and additional function
// only increases compiled code size.
listOf(SerialEntityNames.WRITE_SELF_NAME)
}
else -> emptyList()
}
private fun hasCustomizedSerializeMethod(serializableClass: ClassDescriptor): Boolean {
// We cannot check whether companion has @Serializer(MyClass::class) annotation due to recursive resolve problems
// (apparently, resolve MyClass type asks for all function names, which leads us to this function again)
// so we rely on less strict check that companion just has non-empty @Serializer annotation.
// Anyway, I doubt that serializable class companion would ever be serializer for _another_ class.
val companion = serializableClass.companionObjectDescriptor ?: return false
return companion.annotations.hasAnnotation(SerializationAnnotations.serializerAnnotationFqName)
}
override fun generateSyntheticClasses(
thisDescriptor: ClassDescriptor,
name: Name,
@@ -91,6 +107,7 @@ open class SerializationResolveExtension @JvmOverloads constructor(val metadataP
) {
KSerializerDescriptorResolver.generateSerializerMethods(thisDescriptor, fromSupertypes, name, result)
KSerializerDescriptorResolver.generateCompanionObjectMethods(thisDescriptor, name, result)
KSerializerDescriptorResolver.generateSerializableClassMethods(thisDescriptor, name, result)
}
override fun generateSyntheticProperties(
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2021 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.
*/
@@ -217,6 +217,11 @@ object KSerializerDescriptorResolver {
}
}
fun generateSerializableClassMethods(thisDescriptor: ClassDescriptor, name: Name, result: MutableCollection<SimpleFunctionDescriptor>) {
if (thisDescriptor.isInternalSerializable && name == SerialEntityNames.WRITE_SELF_NAME)
result.add(createWriteSelfFunctionDescriptor(thisDescriptor))
}
private fun createSerializableClassPropertyDescriptor(
companionDescriptor: ClassDescriptor,
classDescriptor: ClassDescriptor
@@ -490,7 +495,7 @@ object KSerializerDescriptorResolver {
if (KotlinBuiltIns.isPrimitiveType(this)) this
else this.makeNullable()
fun createWriteSelfFunctionDescriptor(thisClass: ClassDescriptor): FunctionDescriptor {
fun createWriteSelfFunctionDescriptor(thisClass: ClassDescriptor): SimpleFunctionDescriptor {
val jvmStaticClass = thisClass.module.findClassAcrossModuleDependencies(
ClassId(
FqName("kotlin.jvm"),
@@ -570,7 +575,7 @@ object KSerializerDescriptorResolver {
f.initialize(
null,
thisClass.thisAsReceiverParameter,
null,
typeArgs,
args,
returnType,
@@ -182,18 +182,10 @@ public final class ListOfUsers$$serializer : java/lang/Object, kotlinx/serializa
ALOAD (3)
INVOKEINTERFACE (kotlinx/serialization/encoding/Encoder, beginStructure, (Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/encoding/CompositeEncoder;)
ASTORE (4)
ALOAD (2)
ALOAD (4)
ALOAD (3)
ICONST_0
NEW
DUP
GETSTATIC (INSTANCE, LUser$$serializer;)
CHECKCAST
INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, <init>, (Lkotlinx/serialization/KSerializer;)V)
CHECKCAST
ALOAD (2)
INVOKEVIRTUAL (ListOfUsers, getList, ()Ljava/util/List;)
INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeSerializableElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V)
INVOKESTATIC (ListOfUsers, write$Self, (LListOfUsers;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V)
ALOAD (4)
ALOAD (3)
INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, endStructure, (Lkotlinx/serialization/descriptors/SerialDescriptor;)V)
@@ -293,6 +285,35 @@ public final class ListOfUsers : java/lang/Object {
}
public final java.util.List getList()
public final static void write$Self(ListOfUsers self, kotlinx.serialization.encoding.CompositeEncoder output, kotlinx.serialization.descriptors.SerialDescriptor serialDesc) {
LABEL (L0)
ALOAD (0)
LDC (self)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
ALOAD (1)
LDC (output)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
ALOAD (2)
LDC (serialDesc)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
LABEL (L1)
LINENUMBER (12)
ALOAD (1)
ALOAD (2)
ICONST_0
NEW
DUP
GETSTATIC (INSTANCE, LUser$$serializer;)
CHECKCAST
INVOKESPECIAL (kotlinx/serialization/internal/ArrayListSerializer, <init>, (Lkotlinx/serialization/KSerializer;)V)
CHECKCAST
ALOAD (0)
GETFIELD (list, Ljava/util/List;)
INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeSerializableElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V)
RETURN
LABEL (L2)
}
}
public final class OptionalUser$$serializer : java/lang/Object, kotlinx/serialization/internal/GeneratedSerializer {
@@ -467,47 +488,15 @@ public final class OptionalUser$$serializer : java/lang/Object, kotlinx/serializ
ALOAD (3)
INVOKEINTERFACE (kotlinx/serialization/encoding/Encoder, beginStructure, (Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/encoding/CompositeEncoder;)
ASTORE (4)
ALOAD (2)
ALOAD (4)
ALOAD (3)
ICONST_0
INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, shouldEncodeElementDefault, (Lkotlinx/serialization/descriptors/SerialDescriptor;I)Z)
IFEQ (L2)
ICONST_1
GOTO (L3)
LABEL (L2)
ALOAD (2)
INVOKEVIRTUAL (OptionalUser, getUser, ()LUser;)
LABEL (L4)
LINENUMBER (10)
NEW
DUP
LDC ()
LDC ()
INVOKESPECIAL (User, <init>, (Ljava/lang/String;Ljava/lang/String;)V)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, areEqual, (Ljava/lang/Object;Ljava/lang/Object;)Z)
IFNE (L5)
ICONST_1
GOTO (L3)
LABEL (L5)
ICONST_0
LABEL (L3)
IFEQ (L6)
LABEL (L7)
LINENUMBER (9)
ALOAD (4)
ALOAD (3)
ICONST_0
GETSTATIC (INSTANCE, LUser$$serializer;)
CHECKCAST
ALOAD (2)
INVOKEVIRTUAL (OptionalUser, getUser, ()LUser;)
INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeSerializableElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V)
LABEL (L6)
INVOKESTATIC (OptionalUser, write$Self, (LOptionalUser;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V)
ALOAD (4)
ALOAD (3)
INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, endStructure, (Lkotlinx/serialization/descriptors/SerialDescriptor;)V)
RETURN
LABEL (L8)
LABEL (L2)
}
public void serialize(kotlinx.serialization.encoding.Encoder encoder, java.lang.Object value) {
@@ -650,6 +639,59 @@ public final class OptionalUser : java/lang/Object {
}
public final User getUser()
public final static void write$Self(OptionalUser self, kotlinx.serialization.encoding.CompositeEncoder output, kotlinx.serialization.descriptors.SerialDescriptor serialDesc) {
LABEL (L0)
ALOAD (0)
LDC (self)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
ALOAD (1)
LDC (output)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
ALOAD (2)
LDC (serialDesc)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
LABEL (L1)
LINENUMBER (9)
ALOAD (1)
ALOAD (2)
ICONST_0
INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, shouldEncodeElementDefault, (Lkotlinx/serialization/descriptors/SerialDescriptor;I)Z)
IFEQ (L2)
ICONST_1
GOTO (L3)
LABEL (L2)
ALOAD (0)
GETFIELD (user, LUser;)
LABEL (L4)
LINENUMBER (10)
NEW
DUP
LDC ()
LDC ()
INVOKESPECIAL (User, <init>, (Ljava/lang/String;Ljava/lang/String;)V)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, areEqual, (Ljava/lang/Object;Ljava/lang/Object;)Z)
IFNE (L5)
ICONST_1
GOTO (L3)
LABEL (L5)
ICONST_0
LABEL (L3)
IFEQ (L6)
LABEL (L7)
LINENUMBER (9)
ALOAD (1)
ALOAD (2)
ICONST_0
GETSTATIC (INSTANCE, LUser$$serializer;)
CHECKCAST
ALOAD (0)
GETFIELD (user, LUser;)
INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeSerializableElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V)
LABEL (L6)
RETURN
LABEL (L8)
}
}
public final class User$$serializer : java/lang/Object, kotlinx/serialization/internal/GeneratedSerializer {
@@ -849,18 +891,10 @@ public final class User$$serializer : java/lang/Object, kotlinx/serialization/in
ALOAD (3)
INVOKEINTERFACE (kotlinx/serialization/encoding/Encoder, beginStructure, (Lkotlinx/serialization/descriptors/SerialDescriptor;)Lkotlinx/serialization/encoding/CompositeEncoder;)
ASTORE (4)
ALOAD (2)
ALOAD (4)
ALOAD (3)
ICONST_0
ALOAD (2)
INVOKEVIRTUAL (User, getFirstName, ()Ljava/lang/String;)
INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeStringElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILjava/lang/String;)V)
ALOAD (4)
ALOAD (3)
ICONST_1
ALOAD (2)
INVOKEVIRTUAL (User, getLastName, ()Ljava/lang/String;)
INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeStringElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILjava/lang/String;)V)
INVOKESTATIC (User, write$Self, (LUser;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V)
ALOAD (4)
ALOAD (3)
INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, endStructure, (Lkotlinx/serialization/descriptors/SerialDescriptor;)V)
@@ -973,4 +1007,33 @@ public final class User : java/lang/Object {
public final java.lang.String getFirstName()
public final java.lang.String getLastName()
public final static void write$Self(User self, kotlinx.serialization.encoding.CompositeEncoder output, kotlinx.serialization.descriptors.SerialDescriptor serialDesc) {
LABEL (L0)
ALOAD (0)
LDC (self)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
ALOAD (1)
LDC (output)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
ALOAD (2)
LDC (serialDesc)
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
LABEL (L1)
LINENUMBER (6)
ALOAD (1)
ALOAD (2)
ICONST_0
ALOAD (0)
GETFIELD (firstName, Ljava/lang/String;)
INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeStringElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILjava/lang/String;)V)
ALOAD (1)
ALOAD (2)
ICONST_1
ALOAD (0)
GETFIELD (lastName, Ljava/lang/String;)
INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeStringElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILjava/lang/String;)V)
RETURN
LABEL (L2)
}
}
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
// WITH_RUNTIME
// FILE: test.kt
import kotlinx.serialization.*
@@ -7,6 +7,8 @@ package
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
@kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: Derived, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit
@kotlin.jvm.JvmStatic public final override /*1*/ /*fake_override*/ fun `write$Self`(/*0*/ self: Parent, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit
@kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer<Derived> {
private constructor `$serializer`()
@@ -36,6 +38,7 @@ package
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
@kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: Parent, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit
@kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer<Parent> {
private constructor `$serializer`()
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
// WITH_RUNTIME
// FILE: test.kt
import kotlinx.serialization.*
@@ -8,6 +8,7 @@ package
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
@kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: Derived, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit
@kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer<Derived> {
private constructor `$serializer`()
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
// WITH_RUNTIME
// FILE: test.kt
import kotlinx.serialization.*
@@ -7,6 +7,7 @@ package
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
@kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: Basic, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit
@kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer<Basic> {
private constructor `$serializer`()
@@ -36,6 +37,7 @@ package
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
@kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: Inside, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit
@kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer<Inside> {
private constructor `$serializer`()
@@ -72,6 +74,7 @@ public final class NonSerializable {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
@kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: WithImplicitType, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit
@kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer<WithImplicitType> {
private constructor `$serializer`()
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
// WITH_RUNTIME
// FILE: test.kt
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.*
@@ -7,6 +7,7 @@ package
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
@kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: Foo, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit
@kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer<Foo> {
private constructor `$serializer`()
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
// WITH_RUNTIME
// FILE: test.kt
import kotlinx.serialization.*
@@ -7,6 +7,7 @@ package
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
@kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: Test, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit
@kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer<Test> {
private constructor `$serializer`()
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
// WITH_RUNTIME
// FILE: test.kt
import kotlinx.serialization.*
import kotlinx.serialization.encoding.*
@@ -23,6 +23,7 @@ public object EnumSerializer : kotlinx.serialization.KSerializer<ExplicitlyMarke
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
@kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: EnumUsage, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit
@kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer<EnumUsage> {
private constructor `$serializer`()
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER,-UNUSED_VARIABLE
// WITH_RUNTIME
// FILE: test.kt
import kotlinx.serialization.*
@@ -11,6 +11,7 @@ package
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
@kotlin.jvm.JvmStatic public final /*synthesized*/ fun `write$Self`(/*0*/ self: WithTransients, /*1*/ output: kotlinx.serialization.encoding.CompositeEncoder, /*2*/ serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit
@kotlin.Deprecated(level = DeprecationLevel.HIDDEN, message = "This synthesized declaration should not be used directly", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer<WithTransients> {
private constructor `$serializer`()