Object serialization for JVM, JS and Native

This commit is contained in:
Leonid Startsev
2019-03-20 19:50:27 +03:00
parent 449c406e24
commit 8a90b82e9b
11 changed files with 137 additions and 76 deletions
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPureClassOrObject import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.* import org.jetbrains.kotlin.types.typeUtil.*
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
@@ -48,10 +49,15 @@ fun AbstractSerialGenerator.findAddOnSerializer(propertyType: KotlinType, module
additionalSerializersInScopeOfCurrentFile[propertyType]?.let { return it } additionalSerializersInScopeOfCurrentFile[propertyType]?.let { return it }
if (propertyType in contextualKClassListInCurrentFile) if (propertyType in contextualKClassListInCurrentFile)
return module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer) return module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer)
if (propertyType.toClassDescriptor?.annotations?.hasAnnotation(SerializationAnnotations.polymorphicFqName) == true)
return module.getClassFromSerializationPackage(SpecialBuiltins.polymorphicSerializer)
if (propertyType.isMarkedNullable) return findAddOnSerializer(propertyType.makeNotNullable(), module) if (propertyType.isMarkedNullable) return findAddOnSerializer(propertyType.makeNotNullable(), module)
return null return null
} }
fun KotlinType.isSerializableObject() =
toClassDescriptor?.run { kind == ClassKind.OBJECT && hasSerializableAnnotationWithoutArgs } == true
@Suppress("FunctionName", "LocalVariableName") @Suppress("FunctionName", "LocalVariableName")
fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo { fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
fun SerializableInfo(serializer: ClassDescriptor?) = fun SerializableInfo(serializer: ClassDescriptor?) =
@@ -76,7 +82,7 @@ fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): S
) )
SerializableInfo(serializer) SerializableInfo(serializer)
} }
T.toClassDescriptor?.kind == ClassKind.ENUM_CLASS -> { T.isEnum() -> {
val serializer = property.module.findClassAcrossModuleDependencies(enumSerializerId) val serializer = property.module.findClassAcrossModuleDependencies(enumSerializerId)
SerializableInfo(serializer) SerializableInfo(serializer)
} }
@@ -88,6 +94,11 @@ fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): S
} }
} }
fun KotlinType.serialName(): String {
val serializableDescriptor = this.toClassDescriptor!!
return serializableDescriptor.annotations.serialNameValue ?: serializableDescriptor.fqNameUnsafe.asString()
}
/** /**
* Returns class descriptor for ContextSerializer or PolymorphicSerializer * Returns class descriptor for ContextSerializer or PolymorphicSerializer
* if [annotations] contains @Contextual or @Polymorphic annotation * if [annotations] contains @Contextual or @Polymorphic annotation
@@ -136,6 +147,7 @@ fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescri
if (userOverride != null) return userOverride.toClassDescriptor if (userOverride != null) return userOverride.toClassDescriptor
if (kType.isTypeParameter()) return null if (kType.isTypeParameter()) return null
if (KotlinBuiltIns.isArray(kType)) return module.getClassFromInternalSerializationPackage(SpecialBuiltins.referenceArraySerializer) if (KotlinBuiltIns.isArray(kType)) return module.getClassFromInternalSerializationPackage(SpecialBuiltins.referenceArraySerializer)
if (kType.isSerializableObject()) return module.getClassFromInternalSerializationPackage(SpecialBuiltins.objectSerializer)
val stdSer = findStandardKotlinTypeSerializer(module, kType) // see if there is a standard serializer val stdSer = findStandardKotlinTypeSerializer(module, kType) // see if there is a standard serializer
?: findEnumTypeSerializer(module, kType) ?: findEnumTypeSerializer(module, kType)
if (stdSer != null) return stdSer if (stdSer != null) return stdSer
@@ -38,11 +38,10 @@ import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlinx.serialization.compiler.backend.common.AbstractSerialGenerator
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId import org.jetbrains.kotlinx.serialization.compiler.backend.common.serialName
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.*
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.polymorphicSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.*
val BackendContext.externalSymbols: ReferenceSymbolTable get() = ir.symbols.externalSymbolTable val BackendContext.externalSymbols: ReferenceSymbolTable get() = ir.symbols.externalSymbolTable
@@ -513,14 +512,32 @@ interface IrBuilderExtension {
module: ModuleDescriptor, module: ModuleDescriptor,
kType: KotlinType, kType: KotlinType,
genericIndex: Int? = null genericIndex: Int? = null
): IrExpression? = serializerInstance(
enclosingGenerator,
serializableDescriptor,
serializerClassOriginal,
module,
kType,
genericIndex
) {
val prop = enclosingGenerator.localSerializersFieldsDescriptors[it]
irGetField(irGet(dispatchReceiverParameter), compilerContext.localSymbolTable.referenceField(prop).owner)
}
fun IrBuilderWithScope.serializerInstance(
enclosingGenerator: AbstractSerialGenerator,
serializableDescriptor: ClassDescriptor,
serializerClassOriginal: ClassDescriptor?,
module: ModuleDescriptor,
kType: KotlinType,
genericIndex: Int? = null,
genericGetter: (Int) -> IrExpression
): IrExpression? { ): IrExpression? {
val nullableSerClass = val nullableSerClass =
compilerContext.externalSymbols.referenceClass(module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer)) compilerContext.externalSymbols.referenceClass(module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer))
if (serializerClassOriginal == null) { if (serializerClassOriginal == null) {
if (genericIndex == null) return null if (genericIndex == null) return null
return genericGetter(genericIndex)
val prop = enclosingGenerator.localSerializersFieldsDescriptors[genericIndex]
return irGetField(irGet(dispatchReceiverParameter), compilerContext.localSymbolTable.referenceField(prop).owner)
} }
if (serializerClassOriginal.kind == ClassKind.OBJECT) { if (serializerClassOriginal.kind == ClassKind.OBJECT) {
return irGetObject(serializerClassOriginal) return irGetObject(serializerClassOriginal)
@@ -533,6 +550,10 @@ interface IrBuilderExtension {
args = listOf(classReference(kType)) args = listOf(classReference(kType))
typeArgs = listOf(kType.toIrType()) typeArgs = listOf(kType.toIrType())
} }
objectSerializerId -> {
args = listOf(irString(kType.serialName()), irGetObject(kType.toClassDescriptor!!))
typeArgs = listOf(kType.toIrType())
}
enumSerializerId -> { enumSerializerId -> {
serializerClass = serializableDescriptor.getClassFromInternalSerializationPackage("CommonEnumSerializer") serializerClass = serializableDescriptor.getClassFromInternalSerializationPackage("CommonEnumSerializer")
args = kType.toClassDescriptor!!.let { enumDesc -> args = kType.toClassDescriptor!!.let { enumDesc ->
@@ -556,12 +577,12 @@ interface IrBuilderExtension {
) )
val expr = serializerInstance( val expr = serializerInstance(
enclosingGenerator, enclosingGenerator,
dispatchReceiverParameter,
serializableDescriptor, serializableDescriptor,
argSer, argSer,
module, module,
it.type, it.type,
it.type.genericIndex it.type.genericIndex,
genericGetter
) )
?: return null ?: return null
wrapWithNullableSerializerIfNeeded(module, it.type, expr, nullableSerClass) wrapWithNullableSerializerIfNeeded(module, it.type, expr, nullableSerClass)
@@ -21,7 +21,10 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer
import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
import org.jetbrains.kotlinx.serialization.compiler.resolve.shouldHaveGeneratedMethodsInCompanion
class SerializableCompanionIrGenerator( class SerializableCompanionIrGenerator(
val irClass: IrClass, val irClass: IrClass,
@@ -82,30 +85,21 @@ class SerializableCompanionIrGenerator(
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) = override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) =
irClass.contributeFunction(methodDescriptor, fromStubs = true) { getter -> irClass.contributeFunction(methodDescriptor, fromStubs = true) { getter ->
val serializer = serializableDescriptor.classSerializer!! val serializer = requireNotNull(
val expr = when { findTypeSerializer(
serializer.kind == ClassKind.OBJECT -> irGetObject(serializer) serializableDescriptor.module,
serializer.isSerializerWhichRequiersKClass() -> { serializableDescriptor.toSimpleType()
val serializableType = serializableDescriptor.defaultType )
irInvoke( )
null, val args: List<IrExpression> = getter.valueParameters.map { irGet(it) }
compilerContext.externalSymbols.referenceConstructor(serializer.unsubstitutedPrimaryConstructor!!), val expr = serializerInstance(
typeArguments = listOf(serializableType.toIrType()), this@SerializableCompanionIrGenerator,
valueArguments = listOf(classReference(serializableType)), serializableDescriptor, serializer,
returnTypeHint = getter.returnType serializableDescriptor.module,
) serializableDescriptor.defaultType
} ) { args[it] }
else -> {
val desc = requireNotNull(
findSerializerConstructorForTypeArgumentsSerializers(serializer)
) { "Generated serializer does not have constructor with required number of arguments" }
val ctor = compilerContext.externalSymbols.referenceConstructor(desc)
val typeArgs = getter.typeParameters.map { it.defaultType }
val args: List<IrExpression> = getter.valueParameters.map { irGet(it) }
irInvoke(null, ctor, typeArgs, args, returnTypeHint = getter.returnType)
}
}
patchSerializableClassWithMarkerAnnotation(serializer) patchSerializableClassWithMarkerAnnotation(serializer)
+irReturn(expr) +irReturn(requireNotNull(expr))
} }
} }
@@ -30,9 +30,8 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlinx.serialization.compiler.backend.common.bodyPropertiesDescriptorsMap import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.objectSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.common.primaryConstructorPropertiesDescriptorsMap
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.*
@@ -126,31 +125,40 @@ internal fun SerializerJsTranslator.serializerTower(property: SerializableProper
property.type, property.type,
property.descriptor.findPsi() property.descriptor.findPsi()
) else null ) else null
return serializerInstance(serializer, property.module, property.type, property.genericIndex) return serializerInstance(context, serializer, property.module, property.type, property.genericIndex)
?.let { expr -> if (property.type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr } ?.let { expr -> if (property.type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr }
} }
internal fun SerializerJsTranslator.serializerInstance( internal fun AbstractSerialGenerator.serializerInstance(
context: TranslationContext,
serializerClass: ClassDescriptor?, serializerClass: ClassDescriptor?,
module: ModuleDescriptor, module: ModuleDescriptor,
kType: KotlinType, kType: KotlinType,
genericIndex: Int? = null genericIndex: Int? = null,
genericGetter: (Int) -> JsExpression = { JsNameRef(context.scope().declareName("${SerialEntityNames.typeArgPrefix}$it"), JsThisRef()) }
): JsExpression? { ): JsExpression? {
val nullableSerClass = val nullableSerClass =
context.translateQualifiedReference(module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer)) context.translateQualifiedReference(module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer))
if (serializerClass == null) { if (serializerClass == null) {
if (genericIndex == null) return null if (genericIndex == null) return null
return JsNameRef(context.scope().declareName("${SerialEntityNames.typeArgPrefix}$genericIndex"), JsThisRef()) return genericGetter(genericIndex)
} }
if (serializerClass.kind == ClassKind.OBJECT) { if (serializerClass.kind == ClassKind.OBJECT) {
return context.serializerObjectGetter(serializerClass) return context.serializerObjectGetter(serializerClass)
} else { } else {
var args = if (serializerClass.isSerializerWhichRequiersKClass()) var args = when {
listOf(ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!)) serializerClass.isSerializerWhichRequiersKClass() -> listOf(
else kType.arguments.map { ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!)
val argSer = findTypeSerializerOrContext(module, it.type, sourceElement = serializerClass.findPsi()) )
val expr = serializerInstance(argSer, module, it.type, it.type.genericIndex) ?: return null serializerClass.classId == objectSerializerId -> listOf(
if (it.type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr JsStringLiteral(kType.serialName()),
context.serializerObjectGetter(kType.toClassDescriptor!!)
)
else -> kType.arguments.map {
val argSer = findTypeSerializerOrContext(module, it.type, sourceElement = serializerClass.findPsi())
val expr = serializerInstance(context, argSer, module, it.type, it.type.genericIndex, genericGetter) ?: return null
if (it.type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr
}
} }
if (serializerClass.classId == referenceArraySerializerId) if (serializerClass.classId == referenceArraySerializerId)
args = listOf(ExpressionVisitor.getObjectKClass(context, kType.arguments[0].type.toClassDescriptor!!)) + args args = listOf(ExpressionVisitor.getObjectKClass(context, kType.arguments[0].type.toClassDescriptor!!)) + args
@@ -17,40 +17,45 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.js package org.jetbrains.kotlinx.serialization.compiler.backend.js
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.JsNameRef
import org.jetbrains.kotlin.js.backend.ast.JsReturn
import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor
import org.jetbrains.kotlin.js.translate.expression.ExpressionVisitor
import org.jetbrains.kotlin.psi.KtPureClassOrObject import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
import org.jetbrains.kotlinx.serialization.compiler.resolve.shouldHaveGeneratedMethodsInCompanion
import org.jetbrains.kotlinx.serialization.compiler.resolve.toSimpleType
class SerializableCompanionJsTranslator( class SerializableCompanionJsTranslator(
declaration: ClassDescriptor, declaration: ClassDescriptor,
val translator: DeclarationBodyVisitor, val translator: DeclarationBodyVisitor,
val context: TranslationContext val context: TranslationContext
): SerializableCompanionCodegen(declaration, context.bindingContext()) { ) : SerializableCompanionCodegen(declaration, context.bindingContext()) {
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) { override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
val f = context.buildFunction(methodDescriptor) {jsFun, context -> val f = context.buildFunction(methodDescriptor) { jsFun, context ->
val serializer = serializableDescriptor.classSerializer!! val serializer = requireNotNull(
val stmt: JsExpression = when { findTypeSerializer(
serializer.kind == ClassKind.OBJECT -> context.serializerObjectGetter(serializer) serializableDescriptor.module,
serializer.isSerializerWhichRequiersKClass() -> JsNew( serializableDescriptor.toSimpleType()
context.translateQualifiedReference(serializer), )
listOf(ExpressionVisitor.getObjectKClass(context, serializableDescriptor)) )
val args = jsFun.parameters.map { JsNameRef(it.name) }
val stmt =
requireNotNull(
serializerInstance(
context,
serializer,
serializableDescriptor.module,
serializableDescriptor.defaultType,
genericGetter = {
args[it]
})
) )
else -> {
val args = jsFun.parameters.map { JsNameRef(it.name) }
val ref = context.getInnerNameForDescriptor(
requireNotNull(
findSerializerConstructorForTypeArgumentsSerializers(serializer)
) { "Generated serializer does not have constructor with required number of arguments" })
JsInvocation(ref.makeRef(), args)
}
}
+JsReturn(stmt) +JsReturn(stmt)
} }
translator.addFunction(methodDescriptor, f, null) translator.addFunction(methodDescriptor, f, null)
@@ -170,7 +170,7 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
if (property.transient) continue if (property.transient) continue
// output.writeXxxElementValue(classDesc, index, value) // output.writeXxxElementValue(classDesc, index, value)
val sti = getSerialTypeInfo(property) val sti = getSerialTypeInfo(property)
val innerSerial = serializerInstance(sti.serializer, property.module, property.type, property.genericIndex) val innerSerial = serializerInstance(context, sti.serializer, property.module, property.type, property.genericIndex)
val invocation = if (innerSerial == null) { val invocation = if (innerSerial == null) {
val writeFunc = val writeFunc =
kOutputClass.getFuncDesc("${CallingConventions.encode}${sti.elementMethodPrefix}${CallingConventions.elementPostfix}").single() kOutputClass.getFuncDesc("${CallingConventions.encode}${sti.elementMethodPrefix}${CallingConventions.elementPostfix}").single()
@@ -275,7 +275,7 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
case(JsIntLiteral(i)) { case(JsIntLiteral(i)) {
// input.readXxxElementValue // input.readXxxElementValue
val sti = getSerialTypeInfo(property) val sti = getSerialTypeInfo(property)
val innerSerial = serializerInstance(sti.serializer, property.module, property.type, property.genericIndex) val innerSerial = serializerInstance(context, sti.serializer, property.module, property.type, property.genericIndex)
val call: JsExpression = if (innerSerial == null) { val call: JsExpression = if (innerSerial == null) {
val unknownSer = (sti.elementMethodPrefix.isEmpty()) val unknownSer = (sti.elementMethodPrefix.isEmpty())
val readFunc = val readFunc =
@@ -156,6 +156,7 @@ internal fun ImplementationBodyCodegen.generateMethod(
internal val enumSerializerId = ClassId(internalPackageFqName, Name.identifier(SpecialBuiltins.enumSerializer)) internal val enumSerializerId = ClassId(internalPackageFqName, Name.identifier(SpecialBuiltins.enumSerializer))
internal val polymorphicSerializerId = ClassId(packageFqName, Name.identifier(SpecialBuiltins.polymorphicSerializer)) internal val polymorphicSerializerId = ClassId(packageFqName, Name.identifier(SpecialBuiltins.polymorphicSerializer))
internal val referenceArraySerializerId = ClassId(internalPackageFqName, Name.identifier(SpecialBuiltins.referenceArraySerializer)) internal val referenceArraySerializerId = ClassId(internalPackageFqName, Name.identifier(SpecialBuiltins.referenceArraySerializer))
internal val objectSerializerId = ClassId(internalPackageFqName, Name.identifier(SpecialBuiltins.objectSerializer))
internal val contextSerializerId = ClassId(packageFqName, Name.identifier(SpecialBuiltins.contextSerializer)) internal val contextSerializerId = ClassId(packageFqName, Name.identifier(SpecialBuiltins.contextSerializer))
@@ -294,6 +295,13 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
// Reference array serializer still needs serializer for its argument type // Reference array serializer still needs serializer for its argument type
instantiate(argSerializers[0]) instantiate(argSerializers[0])
} }
objectSerializerId -> {
val serialName = kType.serialName()
aconst(serialName)
signature.append("Ljava/lang/String;")
StackValue.singleton(kType.toClassDescriptor!!, codegen.typeMapper).put(Type.getType("Ljava/lang/Object;"), iv)
signature.append("Ljava/lang/Object;")
}
// all serializers get arguments with serializers of their generic types // all serializers get arguments with serializers of their generic types
else -> argSerializers.forEach(::instantiate) else -> argSerializers.forEach(::instantiate)
} }
@@ -20,9 +20,10 @@ import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
import org.jetbrains.kotlinx.serialization.compiler.resolve.classSerializer import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
import org.jetbrains.kotlinx.serialization.compiler.resolve.shouldHaveGeneratedMethodsInCompanion import org.jetbrains.kotlinx.serialization.compiler.resolve.shouldHaveGeneratedMethodsInCompanion
import org.jetbrains.kotlinx.serialization.compiler.resolve.toSimpleType
class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationBodyCodegen) : class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationBodyCodegen) :
SerializableCompanionCodegen(classCodegen.descriptor, classCodegen.bindingContext) { SerializableCompanionCodegen(classCodegen.descriptor, classCodegen.bindingContext) {
@@ -36,7 +37,12 @@ class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationB
} }
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) { override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
val serial = serializableDescriptor.classSerializer ?: return val serial = requireNotNull(
findTypeSerializer(
serializableDescriptor.module,
serializableDescriptor.toSimpleType()
)
)
classCodegen.generateMethod(methodDescriptor) { _, _ -> classCodegen.generateMethod(methodDescriptor) { _, _ ->
stackValueSerializerInstance( stackValueSerializerInstance(
classCodegen, classCodegen,
@@ -18,6 +18,7 @@ package org.jetbrains.kotlinx.serialization.compiler.extensions
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -43,7 +44,7 @@ open class SerializationResolveExtension : SyntheticResolveExtension {
} }
override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List<Name> = when { override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List<Name> = when {
thisDescriptor.isCompanionObject && getSerializableClassDescriptorByCompanion(thisDescriptor) != null -> thisDescriptor.isSerializableObject || thisDescriptor.isCompanionObject && getSerializableClassDescriptorByCompanion(thisDescriptor) != null ->
listOf(SerialEntityNames.SERIALIZER_PROVIDER_NAME) listOf(SerialEntityNames.SERIALIZER_PROVIDER_NAME)
else -> emptyList() else -> emptyList()
} }
@@ -65,7 +66,8 @@ open class SerializationResolveExtension : SyntheticResolveExtension {
} }
override fun getSyntheticCompanionObjectNameIfNeeded(thisDescriptor: ClassDescriptor): Name? = override fun getSyntheticCompanionObjectNameIfNeeded(thisDescriptor: ClassDescriptor): Name? =
if (thisDescriptor.shouldHaveGeneratedMethodsInCompanion) SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT if (thisDescriptor.kind == ClassKind.CLASS && thisDescriptor.annotations.hasAnnotation(SerializationAnnotations.serializableAnnotationFqName))
SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT
else null else null
override fun addSyntheticSupertypes(thisDescriptor: ClassDescriptor, supertypes: MutableList<KotlinType>) { override fun addSyntheticSupertypes(thisDescriptor: ClassDescriptor, supertypes: MutableList<KotlinType>) {
@@ -105,7 +105,10 @@ val KotlinType?.toClassDescriptor: ClassDescriptor?
} }
internal val ClassDescriptor.shouldHaveGeneratedMethodsInCompanion: Boolean internal val ClassDescriptor.shouldHaveGeneratedMethodsInCompanion: Boolean
get() = this.kind == ClassKind.CLASS && annotations.hasAnnotation(SerializationAnnotations.serializableAnnotationFqName) get() = this.isSerializableObject || this.kind == ClassKind.CLASS && annotations.hasAnnotation(SerializationAnnotations.serializableAnnotationFqName)
internal val ClassDescriptor.isSerializableObject: Boolean
get() = kind == ClassKind.OBJECT && hasSerializableAnnotationWithoutArgs
internal val ClassDescriptor.isInternalSerializable: Boolean //todo normal checking internal val ClassDescriptor.isInternalSerializable: Boolean //todo normal checking
get() { get() {
@@ -159,7 +162,7 @@ internal val ClassDescriptor?.classSerializer: ClassDescriptor?
} }
internal val ClassDescriptor.hasCompanionObjectAsSerializer: Boolean internal val ClassDescriptor.hasCompanionObjectAsSerializer: Boolean
get() = companionObjectDescriptor?.serializerForClass == this.defaultType get() = isSerializableObject || companionObjectDescriptor?.serializerForClass == this.defaultType
internal fun ClassDescriptor.isSerializerWhichRequiersKClass() = classId in setOf(enumSerializerId, contextSerializerId, polymorphicSerializerId) internal fun ClassDescriptor.isSerializerWhichRequiersKClass() = classId in setOf(enumSerializerId, contextSerializerId, polymorphicSerializerId)
@@ -177,6 +180,7 @@ internal val KotlinType.genericIndex: Int?
get() = (this.constructor.declarationDescriptor as? TypeParameterDescriptor)?.index get() = (this.constructor.declarationDescriptor as? TypeParameterDescriptor)?.index
internal fun getSerializableClassDescriptorByCompanion(thisDescriptor: ClassDescriptor): ClassDescriptor? { internal fun getSerializableClassDescriptorByCompanion(thisDescriptor: ClassDescriptor): ClassDescriptor? {
if (thisDescriptor.isSerializableObject) return thisDescriptor
if (!thisDescriptor.isCompanionObject) return null if (!thisDescriptor.isCompanionObject) return null
val classDescriptor = (thisDescriptor.containingDeclaration as? ClassDescriptor) ?: return null val classDescriptor = (thisDescriptor.containingDeclaration as? ClassDescriptor) ?: return null
if (!classDescriptor.shouldHaveGeneratedMethodsInCompanion) return null if (!classDescriptor.shouldHaveGeneratedMethodsInCompanion) return null
@@ -76,6 +76,7 @@ object SerialEntityNames {
object SpecialBuiltins { object SpecialBuiltins {
const val referenceArraySerializer = "ReferenceArraySerializer" const val referenceArraySerializer = "ReferenceArraySerializer"
const val objectSerializer = "ObjectSerializer"
const val enumSerializer = "EnumSerializer" const val enumSerializer = "EnumSerializer"
const val polymorphicSerializer = "PolymorphicSerializer" const val polymorphicSerializer = "PolymorphicSerializer"
const val contextSerializer = "ContextSerializer" const val contextSerializer = "ContextSerializer"