From 572e8873ca4c54d8d5b29e95a6aa9018f55a2241 Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Fri, 25 May 2018 18:32:26 +0300 Subject: [PATCH] Respect `@Serializable(with)` on properties on JS too. Don't generate constructor for passing generic serializers if user already defined proper one. --- .../backend/common/SerializerCodegen.kt | 25 ++++++++++++++++--- .../compiler/backend/common/TypeUtil.kt | 5 ++-- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt index 3522211710f..9aefbd96984 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt @@ -19,15 +19,13 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.common import org.jetbrains.kotlin.backend.common.CodegenUtil.getMemberToGenerate import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.incremental.components.NoLookupLocation -import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtPureClassOrObject import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe -import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver +import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor -import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContext: BindingContext) { protected val serializerDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext) @@ -43,11 +41,30 @@ abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContex val load = generateLoadIfNeeded() if (save || load || prop) generateSerialDesc() - if (serializableDescriptor.declaredTypeParameters.isNotEmpty()) { + if (serializableDescriptor.declaredTypeParameters.isNotEmpty() && typedSerializerConstructorNotDeclared()) { generateGenericFieldsAndConstructor(createTypedSerializerConstructorDescriptor(serializerDescriptor, serializableDescriptor)) } } + // checks if user didn't declared constructor (KSerializer, KSerializer...) on a KSerializer> + private fun typedSerializerConstructorNotDeclared(): Boolean { + val kSerializerSupertype = serializerDescriptor.typeConstructor.supertypes + .find { isKSerializer(it) } ?: throw AssertionError("Serializer does not implement KSerializer??") + val serializableImplementationTypeArguments = kSerializerSupertype.arguments.first().type.arguments + + val typeParamsCount = serializableImplementationTypeArguments.size + if (typeParamsCount == 0) return false //don't need it + val ctors = serializerDescriptor.constructors + val found = + ctors.any { + it.valueParameters.size == typeParamsCount && it.valueParameters.foldIndexed(false) { index, flag, parameterDescriptor -> + val type = parameterDescriptor.type + flag || (isKSerializer(type) && type.arguments.first() == serializableImplementationTypeArguments[index]) + } + } + return !found + } + protected val serialDescPropertyDescriptor = getPropertyToGenerate(serializerDescriptor, KSerializerDescriptorResolver.SERIAL_DESC_FIELD, serializerDescriptor::checkSerializableClassPropertyResult) protected abstract fun generateSerialDesc() 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 af397c8ad7b..6336a2345ab 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 @@ -47,6 +47,8 @@ open class SerialTypeInfo( fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo { val T = property.type + val serializableWith = property.serializableWith?.toClassDescriptor + if (serializableWith != null) return SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializableWith) return when { T.isTypeParameter() -> SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", null) T.isPrimitiveNumberType() or T.isBoolean() -> SerialTypeInfo( @@ -63,8 +65,7 @@ fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo { SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer) } T.toClassDescriptor?.kind == ClassKind.ENUM_CLASS -> { - val serializer = - property.serializableWith?.toClassDescriptor ?: property.module.findClassAcrossModuleDependencies(enumSerializerId) + val serializer = property.module.findClassAcrossModuleDependencies(enumSerializerId) SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer) } else -> {