From 8a90b82e9bde2d63e61ee40e6d913650ff885b02 Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Wed, 20 Mar 2019 19:50:27 +0300 Subject: [PATCH] Object serialization for JVM, JS and Native --- .../compiler/backend/common/TypeUtil.kt | 14 +++++- .../compiler/backend/ir/GeneratorHelpers.kt | 39 +++++++++++---- .../ir/SerializableCompanionIrGenerator.kt | 42 +++++++---------- .../compiler/backend/js/JsCodegenUtil.kt | 34 +++++++++----- .../js/SerializableCompanionJsTranslator.kt | 47 ++++++++++--------- .../backend/js/SerializerJsTranslator.kt | 4 +- .../compiler/backend/jvm/JVMCodegenUtil.kt | 8 ++++ .../jvm/SerializableCompanionCodegenImpl.kt | 10 +++- .../SerializationResolveExtension.kt | 6 ++- .../compiler/resolve/KSerializationUtil.kt | 8 +++- .../compiler/resolve/NamingConventions.kt | 1 + 11 files changed, 137 insertions(+), 76 deletions(-) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt index 5f33c66763f..9db693ea9de 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.psi.KtPureClassOrObject import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.* import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId @@ -48,10 +49,15 @@ fun AbstractSerialGenerator.findAddOnSerializer(propertyType: KotlinType, module additionalSerializersInScopeOfCurrentFile[propertyType]?.let { return it } if (propertyType in contextualKClassListInCurrentFile) 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) return null } +fun KotlinType.isSerializableObject() = + toClassDescriptor?.run { kind == ClassKind.OBJECT && hasSerializableAnnotationWithoutArgs } == true + @Suppress("FunctionName", "LocalVariableName") fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo { fun SerializableInfo(serializer: ClassDescriptor?) = @@ -76,7 +82,7 @@ fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): S ) SerializableInfo(serializer) } - T.toClassDescriptor?.kind == ClassKind.ENUM_CLASS -> { + T.isEnum() -> { val serializer = property.module.findClassAcrossModuleDependencies(enumSerializerId) 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 * 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 (kType.isTypeParameter()) return null 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 ?: findEnumTypeSerializer(module, kType) if (stdSer != null) return stdSer diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt index 02170aa9acb..972a97d209d 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt @@ -38,11 +38,10 @@ import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.typeUtil.isTypeParameter 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.jvm.contextSerializerId -import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId -import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.polymorphicSerializerId -import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId +import org.jetbrains.kotlinx.serialization.compiler.backend.common.serialName +import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.* import org.jetbrains.kotlinx.serialization.compiler.resolve.* val BackendContext.externalSymbols: ReferenceSymbolTable get() = ir.symbols.externalSymbolTable @@ -513,14 +512,32 @@ interface IrBuilderExtension { module: ModuleDescriptor, kType: KotlinType, 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? { val nullableSerClass = compilerContext.externalSymbols.referenceClass(module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer)) if (serializerClassOriginal == null) { if (genericIndex == null) return null - - val prop = enclosingGenerator.localSerializersFieldsDescriptors[genericIndex] - return irGetField(irGet(dispatchReceiverParameter), compilerContext.localSymbolTable.referenceField(prop).owner) + return genericGetter(genericIndex) } if (serializerClassOriginal.kind == ClassKind.OBJECT) { return irGetObject(serializerClassOriginal) @@ -533,6 +550,10 @@ interface IrBuilderExtension { args = listOf(classReference(kType)) typeArgs = listOf(kType.toIrType()) } + objectSerializerId -> { + args = listOf(irString(kType.serialName()), irGetObject(kType.toClassDescriptor!!)) + typeArgs = listOf(kType.toIrType()) + } enumSerializerId -> { serializerClass = serializableDescriptor.getClassFromInternalSerializationPackage("CommonEnumSerializer") args = kType.toClassDescriptor!!.let { enumDesc -> @@ -556,12 +577,12 @@ interface IrBuilderExtension { ) val expr = serializerInstance( enclosingGenerator, - dispatchReceiverParameter, serializableDescriptor, argSer, module, it.type, - it.type.genericIndex + it.type.genericIndex, + genericGetter ) ?: return null wrapWithNullableSerializerIfNeeded(module, it.type, expr, nullableSerClass) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableCompanionIrGenerator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableCompanionIrGenerator.kt index b609d358367..2ca536b1934 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableCompanionIrGenerator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableCompanionIrGenerator.kt @@ -21,7 +21,10 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen +import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer 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( val irClass: IrClass, @@ -82,30 +85,21 @@ class SerializableCompanionIrGenerator( override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) = irClass.contributeFunction(methodDescriptor, fromStubs = true) { getter -> - val serializer = serializableDescriptor.classSerializer!! - val expr = when { - serializer.kind == ClassKind.OBJECT -> irGetObject(serializer) - serializer.isSerializerWhichRequiersKClass() -> { - val serializableType = serializableDescriptor.defaultType - irInvoke( - null, - compilerContext.externalSymbols.referenceConstructor(serializer.unsubstitutedPrimaryConstructor!!), - typeArguments = listOf(serializableType.toIrType()), - valueArguments = listOf(classReference(serializableType)), - returnTypeHint = getter.returnType - ) - } - 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 = getter.valueParameters.map { irGet(it) } - irInvoke(null, ctor, typeArgs, args, returnTypeHint = getter.returnType) - } - } + val serializer = requireNotNull( + findTypeSerializer( + serializableDescriptor.module, + serializableDescriptor.toSimpleType() + ) + ) + val args: List = getter.valueParameters.map { irGet(it) } + val expr = serializerInstance( + this@SerializableCompanionIrGenerator, + serializableDescriptor, serializer, + serializableDescriptor.module, + serializableDescriptor.defaultType + ) { args[it] } patchSerializableClassWithMarkerAnnotation(serializer) - +irReturn(expr) + +irReturn(requireNotNull(expr)) } + } \ No newline at end of file diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/JsCodegenUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/JsCodegenUtil.kt index 86ef0d1d742..3e5c3710ad2 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/JsCodegenUtil.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/JsCodegenUtil.kt @@ -30,9 +30,8 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.isTypeParameter -import org.jetbrains.kotlinx.serialization.compiler.backend.common.bodyPropertiesDescriptorsMap -import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext -import org.jetbrains.kotlinx.serialization.compiler.backend.common.primaryConstructorPropertiesDescriptorsMap +import org.jetbrains.kotlinx.serialization.compiler.backend.common.* +import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.objectSerializerId import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId import org.jetbrains.kotlinx.serialization.compiler.resolve.* @@ -126,31 +125,40 @@ internal fun SerializerJsTranslator.serializerTower(property: SerializableProper property.type, property.descriptor.findPsi() ) 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 } } -internal fun SerializerJsTranslator.serializerInstance( +internal fun AbstractSerialGenerator.serializerInstance( + context: TranslationContext, serializerClass: ClassDescriptor?, module: ModuleDescriptor, kType: KotlinType, - genericIndex: Int? = null + genericIndex: Int? = null, + genericGetter: (Int) -> JsExpression = { JsNameRef(context.scope().declareName("${SerialEntityNames.typeArgPrefix}$it"), JsThisRef()) } ): JsExpression? { val nullableSerClass = context.translateQualifiedReference(module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer)) if (serializerClass == null) { if (genericIndex == null) return null - return JsNameRef(context.scope().declareName("${SerialEntityNames.typeArgPrefix}$genericIndex"), JsThisRef()) + return genericGetter(genericIndex) } if (serializerClass.kind == ClassKind.OBJECT) { return context.serializerObjectGetter(serializerClass) } else { - var args = if (serializerClass.isSerializerWhichRequiersKClass()) - listOf(ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!)) - else kType.arguments.map { - val argSer = findTypeSerializerOrContext(module, it.type, sourceElement = serializerClass.findPsi()) - val expr = serializerInstance(argSer, module, it.type, it.type.genericIndex) ?: return null - if (it.type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr + var args = when { + serializerClass.isSerializerWhichRequiersKClass() -> listOf( + ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!) + ) + serializerClass.classId == objectSerializerId -> listOf( + 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) args = listOf(ExpressionVisitor.getObjectKClass(context, kType.arguments[0].type.toClassDescriptor!!)) + args diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableCompanionJsTranslator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableCompanionJsTranslator.kt index 7459e809c5d..907188a34fa 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableCompanionJsTranslator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableCompanionJsTranslator.kt @@ -17,40 +17,45 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.js import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ClassKind 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.declaration.DeclarationBodyVisitor -import org.jetbrains.kotlin.js.translate.expression.ExpressionVisitor 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.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( declaration: ClassDescriptor, val translator: DeclarationBodyVisitor, val context: TranslationContext -): SerializableCompanionCodegen(declaration, context.bindingContext()) { +) : SerializableCompanionCodegen(declaration, context.bindingContext()) { override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) { - val f = context.buildFunction(methodDescriptor) {jsFun, context -> - val serializer = serializableDescriptor.classSerializer!! - val stmt: JsExpression = when { - serializer.kind == ClassKind.OBJECT -> context.serializerObjectGetter(serializer) - serializer.isSerializerWhichRequiersKClass() -> JsNew( - context.translateQualifiedReference(serializer), - listOf(ExpressionVisitor.getObjectKClass(context, serializableDescriptor)) + val f = context.buildFunction(methodDescriptor) { jsFun, context -> + val serializer = requireNotNull( + findTypeSerializer( + serializableDescriptor.module, + serializableDescriptor.toSimpleType() + ) + ) + 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) } translator.addFunction(methodDescriptor, f, null) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt index 03bbfcda72d..93805b56232 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt @@ -170,7 +170,7 @@ class SerializerJsTranslator(descriptor: ClassDescriptor, if (property.transient) continue // output.writeXxxElementValue(classDesc, index, value) 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 writeFunc = kOutputClass.getFuncDesc("${CallingConventions.encode}${sti.elementMethodPrefix}${CallingConventions.elementPostfix}").single() @@ -275,7 +275,7 @@ class SerializerJsTranslator(descriptor: ClassDescriptor, case(JsIntLiteral(i)) { // input.readXxxElementValue 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 unknownSer = (sti.elementMethodPrefix.isEmpty()) val readFunc = diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt index 0f6c7a55a37..3014c14fcb5 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt @@ -156,6 +156,7 @@ internal fun ImplementationBodyCodegen.generateMethod( internal val enumSerializerId = ClassId(internalPackageFqName, Name.identifier(SpecialBuiltins.enumSerializer)) internal val polymorphicSerializerId = ClassId(packageFqName, Name.identifier(SpecialBuiltins.polymorphicSerializer)) 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)) @@ -294,6 +295,13 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class // Reference array serializer still needs serializer for its argument type 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 else -> argSerializers.forEach(::instantiate) } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCompanionCodegenImpl.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCompanionCodegenImpl.kt index ae7a1018854..2dc8f3bab6e 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCompanionCodegenImpl.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCompanionCodegenImpl.kt @@ -20,9 +20,10 @@ import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen -import org.jetbrains.kotlinx.serialization.compiler.resolve.classSerializer +import org.jetbrains.kotlinx.serialization.compiler.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 SerializableCompanionCodegenImpl(private val classCodegen: ImplementationBodyCodegen) : SerializableCompanionCodegen(classCodegen.descriptor, classCodegen.bindingContext) { @@ -36,7 +37,12 @@ class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationB } override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) { - val serial = serializableDescriptor.classSerializer ?: return + val serial = requireNotNull( + findTypeSerializer( + serializableDescriptor.module, + serializableDescriptor.toSimpleType() + ) + ) classCodegen.generateMethod(methodDescriptor) { _, _ -> stackValueSerializerInstance( classCodegen, diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt index 2c218b038b1..02f162b7d09 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlinx.serialization.compiler.extensions import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.name.Name @@ -43,7 +44,7 @@ open class SerializationResolveExtension : SyntheticResolveExtension { } override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List = when { - thisDescriptor.isCompanionObject && getSerializableClassDescriptorByCompanion(thisDescriptor) != null -> + thisDescriptor.isSerializableObject || thisDescriptor.isCompanionObject && getSerializableClassDescriptorByCompanion(thisDescriptor) != null -> listOf(SerialEntityNames.SERIALIZER_PROVIDER_NAME) else -> emptyList() } @@ -65,7 +66,8 @@ open class SerializationResolveExtension : SyntheticResolveExtension { } 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 override fun addSyntheticSupertypes(thisDescriptor: ClassDescriptor, supertypes: MutableList) { diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt index 2302fb81d15..c66f9a005d8 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt @@ -105,7 +105,10 @@ val KotlinType?.toClassDescriptor: ClassDescriptor? } 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 get() { @@ -159,7 +162,7 @@ internal val ClassDescriptor?.classSerializer: ClassDescriptor? } 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) @@ -177,6 +180,7 @@ internal val KotlinType.genericIndex: Int? get() = (this.constructor.declarationDescriptor as? TypeParameterDescriptor)?.index internal fun getSerializableClassDescriptorByCompanion(thisDescriptor: ClassDescriptor): ClassDescriptor? { + if (thisDescriptor.isSerializableObject) return thisDescriptor if (!thisDescriptor.isCompanionObject) return null val classDescriptor = (thisDescriptor.containingDeclaration as? ClassDescriptor) ?: return null if (!classDescriptor.shouldHaveGeneratedMethodsInCompanion) return null diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt index 39393676f1d..92f23b30643 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt @@ -76,6 +76,7 @@ object SerialEntityNames { object SpecialBuiltins { const val referenceArraySerializer = "ReferenceArraySerializer" + const val objectSerializer = "ObjectSerializer" const val enumSerializer = "EnumSerializer" const val polymorphicSerializer = "PolymorphicSerializer" const val contextSerializer = "ContextSerializer"