Object serialization for JVM, JS and Native
This commit is contained in:
+13
-1
@@ -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
|
||||||
|
|||||||
+30
-9
@@ -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)
|
||||||
|
|||||||
+18
-24
@@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+21
-13
@@ -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
|
||||||
|
|||||||
+26
-21
@@ -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)
|
||||||
|
|||||||
+2
-2
@@ -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 =
|
||||||
|
|||||||
+8
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-2
@@ -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,
|
||||||
|
|||||||
+4
-2
@@ -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>) {
|
||||||
|
|||||||
+6
-2
@@ -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
|
||||||
|
|||||||
+1
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user