Auto-applying @Polymorphic for interfaces and serializable abstract
classes
This commit is contained in:
+5
-5
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.classSerializer
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.toClassDescriptor
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.isAbstractSerializableClass
|
||||
|
||||
abstract class SerializableCodegen(
|
||||
protected val serializableDescriptor: ClassDescriptor,
|
||||
@@ -37,16 +37,16 @@ abstract class SerializableCodegen(
|
||||
}
|
||||
|
||||
private fun generateSyntheticInternalConstructor() {
|
||||
val serializerDescriptor = serializableDescriptor.classSerializer?.toClassDescriptor ?: return
|
||||
if (SerializerCodegen.getSyntheticLoadMember(serializerDescriptor) != null) {
|
||||
val serializerDescriptor = serializableDescriptor.classSerializer ?: return
|
||||
if (isAbstractSerializableClass(serializableDescriptor) || SerializerCodegen.getSyntheticLoadMember(serializerDescriptor) != null) {
|
||||
val constrDesc = KSerializerDescriptorResolver.createLoadConstructorDescriptor(serializableDescriptor, bindingContext)
|
||||
generateInternalConstructor(constrDesc)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateSyntheticMethods() {
|
||||
val serializerDescriptor = serializableDescriptor.classSerializer?.toClassDescriptor ?: return
|
||||
if (SerializerCodegen.getSyntheticSaveMember(serializerDescriptor) != null) {
|
||||
val serializerDescriptor = serializableDescriptor.classSerializer ?: return
|
||||
if (isAbstractSerializableClass(serializableDescriptor) || SerializerCodegen.getSyntheticSaveMember(serializerDescriptor) != null) {
|
||||
val func = KSerializerDescriptorResolver.createWriteSelfFunctionDescriptor(serializableDescriptor)
|
||||
generateWriteSelfMethod(func)
|
||||
}
|
||||
|
||||
+5
-5
@@ -30,11 +30,9 @@ 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.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
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.resolve.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages.internalPackageFqName
|
||||
@@ -130,9 +128,11 @@ 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)
|
||||
return kType.typeSerializer.toClassDescriptor // check for serializer defined on the type
|
||||
?: findStandardKotlinTypeSerializer(module, kType) // otherwise see if there is a standard serializer
|
||||
?: findEnumTypeSerializer(module, kType)
|
||||
val stdSer = findStandardKotlinTypeSerializer(module, kType) // see if there is a standard serializer
|
||||
?: findEnumTypeSerializer(module, kType)
|
||||
if (stdSer != null) return stdSer
|
||||
if (kType.isInterface()) return module.getClassFromSerializationPackage(SpecialBuiltins.polymorphicSerializer)
|
||||
return kType.toClassDescriptor?.classSerializer // check for serializer defined on the type
|
||||
}
|
||||
|
||||
fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? {
|
||||
|
||||
+5
-2
@@ -12,7 +12,10 @@ import org.jetbrains.kotlin.ir.util.TypeTranslator
|
||||
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.resolve.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.classSerializer
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.shouldHaveGeneratedMethodsInCompanion
|
||||
|
||||
class SerializableCompanionIrGenerator(
|
||||
val irClass: IrClass,
|
||||
@@ -39,7 +42,7 @@ class SerializableCompanionIrGenerator(
|
||||
|
||||
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) =
|
||||
irClass.contributeFunction(methodDescriptor, fromStubs = true) { getter ->
|
||||
val serializer = serializableDescriptor.classSerializer?.toClassDescriptor!!
|
||||
val serializer = serializableDescriptor.classSerializer!!
|
||||
val expr = if (serializer.kind == ClassKind.OBJECT) {
|
||||
irGetObject(serializer)
|
||||
} else {
|
||||
|
||||
+5
-2
@@ -27,7 +27,10 @@ import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor
|
||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.classSerializer
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.shouldHaveGeneratedMethodsInCompanion
|
||||
|
||||
class SerializableCompanionJsTranslator(
|
||||
declaration: ClassDescriptor,
|
||||
@@ -37,7 +40,7 @@ class SerializableCompanionJsTranslator(
|
||||
|
||||
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
|
||||
val f = context.buildFunction(methodDescriptor) {jsFun, context ->
|
||||
val serializer = serializableDescriptor.classSerializer?.toClassDescriptor!!
|
||||
val serializer = serializableDescriptor.classSerializer!!
|
||||
val stmt: JsExpression = if (serializer.kind == ClassKind.OBJECT) {
|
||||
context.serializerObjectGetter(serializer)
|
||||
} else {
|
||||
|
||||
+4
-2
@@ -20,7 +20,9 @@ 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.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.classSerializer
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.shouldHaveGeneratedMethodsInCompanion
|
||||
|
||||
class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationBodyCodegen) :
|
||||
SerializableCompanionCodegen(classCodegen.descriptor, classCodegen.bindingContext) {
|
||||
@@ -34,7 +36,7 @@ class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationB
|
||||
}
|
||||
|
||||
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
|
||||
val serial = serializableDescriptor.classSerializer?.toClassDescriptor ?: return
|
||||
val serial = serializableDescriptor.classSerializer ?: return
|
||||
classCodegen.generateMethod(methodDescriptor) { _, _ ->
|
||||
stackValueSerializerInstance(
|
||||
classCodegen,
|
||||
|
||||
+28
-12
@@ -117,19 +117,33 @@ internal val ClassDescriptor.hasSerializableAnnotationWithoutArgs: Boolean
|
||||
return psi.valueArguments.isEmpty()
|
||||
}
|
||||
|
||||
// For abstract classes marked with @Serializable,
|
||||
// methods are generated anyway although they shouldn't have
|
||||
// generated $serializer and use Polymorphic one.
|
||||
internal fun isAbstractSerializableClass(serializableDescriptor: ClassDescriptor): Boolean =
|
||||
serializableDescriptor.isInternalSerializable && serializableDescriptor.modality == Modality.ABSTRACT
|
||||
|
||||
internal fun ClassDescriptor.polymorphicSerializerIfApplicableAutomatically(): ClassDescriptor? = if (
|
||||
isAbstractSerializableClass(this)
|
||||
|| kind == ClassKind.INTERFACE
|
||||
) module.getClassFromSerializationPackage(SpecialBuiltins.polymorphicSerializer)
|
||||
else null
|
||||
|
||||
// serializer that was declared for this type
|
||||
internal val ClassDescriptor?.classSerializer: KotlinType?
|
||||
internal val ClassDescriptor?.classSerializer: ClassDescriptor?
|
||||
get() = this?.let {
|
||||
// serializer annotation on class?
|
||||
serializableWith?.let { return it }
|
||||
serializableWith?.let { return it.toClassDescriptor }
|
||||
// companion object serializer?
|
||||
if (hasCompanionObjectAsSerializer) return companionObjectDescriptor?.defaultType
|
||||
if (hasCompanionObjectAsSerializer) return companionObjectDescriptor
|
||||
// can infer @Poly?
|
||||
polymorphicSerializerIfApplicableAutomatically()?.let { return it }
|
||||
// default serializable?
|
||||
if (isInternalSerializable) {
|
||||
// $serializer nested class
|
||||
return this.unsubstitutedMemberScope
|
||||
.getDescriptorsFiltered(nameFilter = {it == SerialEntityNames.SERIALIZER_CLASS_NAME})
|
||||
.filterIsInstance<ClassDescriptor>().singleOrNull()?.defaultType
|
||||
.getDescriptorsFiltered(nameFilter = { it == SerialEntityNames.SERIALIZER_CLASS_NAME })
|
||||
.filterIsInstance<ClassDescriptor>().singleOrNull()
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -139,8 +153,8 @@ internal val ClassDescriptor.hasCompanionObjectAsSerializer: Boolean
|
||||
|
||||
internal fun checkSerializerNullability(classType: KotlinType, serializerType: KotlinType): KotlinType {
|
||||
val castedToKSerial = requireNotNull(
|
||||
serializerType.supertypes().find { isKSerializer(it) },
|
||||
{ "${KSERIALIZER_CLASS} is not a supertype of $serializerType" }
|
||||
serializerType.supertypes().find { isKSerializer(it) },
|
||||
{ "${KSERIALIZER_CLASS} is not a supertype of $serializerType" }
|
||||
)
|
||||
if (!classType.isMarkedNullable && castedToKSerial.arguments.first().type.isMarkedNullable)
|
||||
throw IllegalStateException("Can't serialize non-nullable field of type ${classType} with nullable serializer ${serializerType}")
|
||||
@@ -149,11 +163,13 @@ internal fun checkSerializerNullability(classType: KotlinType, serializerType: K
|
||||
|
||||
// returns only user-overriden Serializer
|
||||
val KotlinType.overridenSerializer: KotlinType?
|
||||
get() = (this.toClassDescriptor?.serializableWith)?.let { checkSerializerNullability(this, it) }
|
||||
|
||||
// serializer that was declared for this specific type or annotation from a class declaration
|
||||
val KotlinType.typeSerializer: KotlinType?
|
||||
get() = this.toClassDescriptor?.classSerializer
|
||||
get() {
|
||||
val desc = this.toClassDescriptor ?: return null
|
||||
(desc.serializableWith)?.let { return checkSerializerNullability(this, it) }
|
||||
if (desc.annotations.hasAnnotation(SerializationAnnotations.polymorphicFqName))
|
||||
return desc.module.getClassFromSerializationPackage(SpecialBuiltins.polymorphicSerializer).defaultType
|
||||
return null
|
||||
}
|
||||
|
||||
val KotlinType.genericIndex: Int?
|
||||
get() = (this.constructor.declarationDescriptor as? TypeParameterDescriptor)?.index
|
||||
|
||||
Reference in New Issue
Block a user