Respect @Serializable(with) on properties on JS too.
Don't generate constructor for passing generic serializers if user already defined proper one.
This commit is contained in:
+21
-4
@@ -19,15 +19,13 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.common
|
|||||||
import org.jetbrains.kotlin.backend.common.CodegenUtil.getMemberToGenerate
|
import org.jetbrains.kotlin.backend.common.CodegenUtil.getMemberToGenerate
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||||
import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor
|
import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
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.KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties
|
|
||||||
|
|
||||||
abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContext: BindingContext) {
|
abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContext: BindingContext) {
|
||||||
protected val serializerDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext)
|
protected val serializerDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext)
|
||||||
@@ -43,11 +41,30 @@ abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContex
|
|||||||
val load = generateLoadIfNeeded()
|
val load = generateLoadIfNeeded()
|
||||||
if (save || load || prop)
|
if (save || load || prop)
|
||||||
generateSerialDesc()
|
generateSerialDesc()
|
||||||
if (serializableDescriptor.declaredTypeParameters.isNotEmpty()) {
|
if (serializableDescriptor.declaredTypeParameters.isNotEmpty() && typedSerializerConstructorNotDeclared()) {
|
||||||
generateGenericFieldsAndConstructor(createTypedSerializerConstructorDescriptor(serializerDescriptor, serializableDescriptor))
|
generateGenericFieldsAndConstructor(createTypedSerializerConstructorDescriptor(serializerDescriptor, serializableDescriptor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checks if user didn't declared constructor (KSerializer<T0>, KSerializer<T1>...) on a KSerializer<T<T0, T1...>>
|
||||||
|
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,
|
protected val serialDescPropertyDescriptor = getPropertyToGenerate(serializerDescriptor, KSerializerDescriptorResolver.SERIAL_DESC_FIELD,
|
||||||
serializerDescriptor::checkSerializableClassPropertyResult)
|
serializerDescriptor::checkSerializableClassPropertyResult)
|
||||||
protected abstract fun generateSerialDesc()
|
protected abstract fun generateSerialDesc()
|
||||||
|
|||||||
+3
-2
@@ -47,6 +47,8 @@ open class SerialTypeInfo(
|
|||||||
|
|
||||||
fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
|
fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
|
||||||
val T = property.type
|
val T = property.type
|
||||||
|
val serializableWith = property.serializableWith?.toClassDescriptor
|
||||||
|
if (serializableWith != null) return SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializableWith)
|
||||||
return when {
|
return when {
|
||||||
T.isTypeParameter() -> SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", null)
|
T.isTypeParameter() -> SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", null)
|
||||||
T.isPrimitiveNumberType() or T.isBoolean() -> SerialTypeInfo(
|
T.isPrimitiveNumberType() or T.isBoolean() -> SerialTypeInfo(
|
||||||
@@ -63,8 +65,7 @@ fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
|
|||||||
SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer)
|
SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer)
|
||||||
}
|
}
|
||||||
T.toClassDescriptor?.kind == ClassKind.ENUM_CLASS -> {
|
T.toClassDescriptor?.kind == ClassKind.ENUM_CLASS -> {
|
||||||
val serializer =
|
val serializer = property.module.findClassAcrossModuleDependencies(enumSerializerId)
|
||||||
property.serializableWith?.toClassDescriptor ?: property.module.findClassAcrossModuleDependencies(enumSerializerId)
|
|
||||||
SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer)
|
SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
|||||||
Reference in New Issue
Block a user