.childSerializers for JS
This commit is contained in:
committed by
Leonid Startsev
parent
baf8cb6e9b
commit
3010814327
+1
-1
@@ -31,7 +31,7 @@ abstract class SerializerCodegen(
|
|||||||
bindingContext: BindingContext
|
bindingContext: BindingContext
|
||||||
) : AbstractSerialGenerator(bindingContext, serializerDescriptor) {
|
) : AbstractSerialGenerator(bindingContext, serializerDescriptor) {
|
||||||
// protected val serializerDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext)
|
// protected val serializerDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext)
|
||||||
protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!!
|
val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!!
|
||||||
protected val serialName: String = serializableDescriptor.annotations.serialNameValue ?: serializableDescriptor.fqNameUnsafe.asString()
|
protected val serialName: String = serializableDescriptor.annotations.serialNameValue ?: serializableDescriptor.fqNameUnsafe.asString()
|
||||||
protected val properties = SerializableProperties(serializableDescriptor, bindingContext)
|
protected val properties = SerializableProperties(serializableDescriptor, bindingContext)
|
||||||
protected val orderedProperties = properties.serializableProperties
|
protected val orderedProperties = properties.serializableProperties
|
||||||
|
|||||||
+68
@@ -17,12 +17,23 @@
|
|||||||
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.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||||
import org.jetbrains.kotlin.js.translate.expression.translateAndAliasParameters
|
import org.jetbrains.kotlin.js.translate.expression.translateAndAliasParameters
|
||||||
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
|
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||||
|
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.referenceArraySerializerId
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||||
|
|
||||||
internal class JsBlockBuilder {
|
internal class JsBlockBuilder {
|
||||||
val block: JsBlock = JsBlock()
|
val block: JsBlock = JsBlock()
|
||||||
@@ -102,3 +113,60 @@ internal fun TranslationContext.serializerObjectGetter(serializer: ClassDescript
|
|||||||
internal fun TranslationContext.translateQualifiedReference(clazz: ClassDescriptor): JsExpression {
|
internal fun TranslationContext.translateQualifiedReference(clazz: ClassDescriptor): JsExpression {
|
||||||
return ReferenceTranslator.translateAsTypeReference(clazz, this)
|
return ReferenceTranslator.translateAsTypeReference(clazz, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Does not use sti and therefore does not perform encoder calls optimization
|
||||||
|
internal fun SerializerJsTranslator.serializerTower(property: SerializableProperty): JsExpression? {
|
||||||
|
val nullableSerClass =
|
||||||
|
context.translateQualifiedReference(property.module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer))
|
||||||
|
val serializer =
|
||||||
|
property.serializableWith?.toClassDescriptor
|
||||||
|
?: if (!property.type.isTypeParameter()) findTypeSerializerOrContext(
|
||||||
|
property.module,
|
||||||
|
property.type,
|
||||||
|
property.descriptor.annotations,
|
||||||
|
property.descriptor.findPsi()
|
||||||
|
) else null
|
||||||
|
return serializerInstance(serializer, property.module, property.type, property.genericIndex)
|
||||||
|
?.let { expr -> if (property.type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun SerializerJsTranslator.serializerInstance(
|
||||||
|
serializerClass: ClassDescriptor?,
|
||||||
|
module: ModuleDescriptor,
|
||||||
|
kType: KotlinType,
|
||||||
|
genericIndex: Int? = null
|
||||||
|
): 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())
|
||||||
|
}
|
||||||
|
if (serializerClass.kind == ClassKind.OBJECT) {
|
||||||
|
return context.serializerObjectGetter(serializerClass)
|
||||||
|
} else {
|
||||||
|
var args = if (serializerClass.classId == enumSerializerId || serializerClass.classId == contextSerializerId)
|
||||||
|
listOf(createGetKClassExpression(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
|
||||||
|
}
|
||||||
|
if (serializerClass.classId == referenceArraySerializerId)
|
||||||
|
args = listOf(createGetKClassExpression(kType.arguments[0].type.toClassDescriptor!!)) + args
|
||||||
|
val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
|
||||||
|
val ref = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
|
||||||
|
val desc = KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializerClass, serializableDescriptor)
|
||||||
|
JsInvocation(context.getInnerReference(desc), args)
|
||||||
|
} else {
|
||||||
|
JsNew(context.translateQualifiedReference(serializerClass), args)
|
||||||
|
}
|
||||||
|
return ref
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun SerializerJsTranslator.createGetKClassExpression(classDescriptor: ClassDescriptor): JsExpression =
|
||||||
|
JsInvocation(
|
||||||
|
context.namer().kotlin("getKClass"),
|
||||||
|
context.translateQualifiedReference(classDescriptor)
|
||||||
|
)
|
||||||
+13
-43
@@ -20,24 +20,18 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
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.declaration.DefaultPropertyTranslator
|
import org.jetbrains.kotlin.js.translate.declaration.DefaultPropertyTranslator
|
||||||
import org.jetbrains.kotlin.js.translate.general.Translation
|
import org.jetbrains.kotlin.js.translate.general.Translation
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||||
|
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
|
||||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
|
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo
|
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo
|
||||||
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.referenceArraySerializerId
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.typeArgPrefix
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.typeArgPrefix
|
||||||
@@ -60,7 +54,8 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
.unsubstitutedPrimaryConstructor!!
|
.unsubstitutedPrimaryConstructor!!
|
||||||
|
|
||||||
// this.serialDesc = new SerialDescImpl(...)
|
// this.serialDesc = new SerialDescImpl(...)
|
||||||
val value = JsNew(context.getInnerReference(serialDescImplConstructor), listOf(JsStringLiteral(serialName)))
|
val correctThis = context.getDispatchReceiver(JsDescriptorUtils.getReceiverParameterForDeclaration(desc.containingDeclaration))
|
||||||
|
val value = JsNew(context.getInnerReference(serialDescImplConstructor), listOf(JsStringLiteral(serialName), correctThis))
|
||||||
val assgmnt = TranslationUtils.assignmentToBackingField(context, desc, value)
|
val assgmnt = TranslationUtils.assignmentToBackingField(context, desc, value)
|
||||||
translator.addInitializerStatement(assgmnt.makeStmt())
|
translator.addInitializerStatement(assgmnt.makeStmt())
|
||||||
|
|
||||||
@@ -72,7 +67,11 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
|
|
||||||
for (prop in orderedProperties) {
|
for (prop in orderedProperties) {
|
||||||
if (prop.transient) continue
|
if (prop.transient) continue
|
||||||
val call = JsInvocation(JsNameRef(context.getNameForDescriptor(addFunc), serialClassDescRef), JsStringLiteral(prop.name))
|
val call = JsInvocation(
|
||||||
|
JsNameRef(context.getNameForDescriptor(addFunc), serialClassDescRef),
|
||||||
|
JsStringLiteral(prop.name),
|
||||||
|
JsBooleanLiteral(prop.optional)
|
||||||
|
)
|
||||||
translator.addInitializerStatement(call.makeStmt())
|
translator.addInitializerStatement(call.makeStmt())
|
||||||
// serialDesc.pushAnnotation(...)
|
// serialDesc.pushAnnotation(...)
|
||||||
pushAnnotationsInto(prop.descriptor, pushFunc, serialClassDescRef)
|
pushAnnotationsInto(prop.descriptor, pushFunc, serialClassDescRef)
|
||||||
@@ -93,6 +92,11 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun generateChildSerializersGetter(function: FunctionDescriptor) = generateFunction(function) { _, _ ->
|
||||||
|
val allSerializers = orderedProperties.map { requireNotNull(serializerTower(it)) { "Property ${it.name} must have a serializer" } }
|
||||||
|
+JsReturn(JsArrayLiteral(allSerializers))
|
||||||
|
}
|
||||||
|
|
||||||
override fun generateSerializableClassProperty(property: PropertyDescriptor) {
|
override fun generateSerializableClassProperty(property: PropertyDescriptor) {
|
||||||
val propDesc = generatedSerialDescPropertyDescriptor ?: return
|
val propDesc = generatedSerialDescPropertyDescriptor ?: return
|
||||||
val propTranslator = DefaultPropertyTranslator(propDesc, context,
|
val propTranslator = DefaultPropertyTranslator(propDesc, context,
|
||||||
@@ -174,40 +178,6 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
+JsInvocation(JsNameRef(wEndFunc, localOutputRef), serialClassDescRef).makeStmt()
|
+JsInvocation(JsNameRef(wEndFunc, localOutputRef), serialClassDescRef).makeStmt()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun serializerInstance(serializerClass: ClassDescriptor?, module: ModuleDescriptor, kType: KotlinType, genericIndex: Int? = null): JsExpression? {
|
|
||||||
val nullableSerClass = context.translateQualifiedReference(module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer))
|
|
||||||
if (serializerClass == null) {
|
|
||||||
if (genericIndex == null) return null
|
|
||||||
return JsNameRef(context.scope().declareName("$typeArgPrefix$genericIndex"), JsThisRef())
|
|
||||||
}
|
|
||||||
if (serializerClass.kind == ClassKind.OBJECT) {
|
|
||||||
return context.serializerObjectGetter(serializerClass)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var args = if (serializerClass.classId == enumSerializerId || serializerClass.classId == contextSerializerId)
|
|
||||||
listOf(createGetKClassExpression(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
|
|
||||||
}
|
|
||||||
if (serializerClass.classId == referenceArraySerializerId)
|
|
||||||
args = listOf(createGetKClassExpression(kType.arguments[0].type.toClassDescriptor!!)) + args
|
|
||||||
val serializable = getSerializableClassDescriptorBySerializer(serializerClass)
|
|
||||||
val ref = if (serializable?.declaredTypeParameters?.isNotEmpty() == true) {
|
|
||||||
val desc = KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor(serializerClass, serializableDescriptor)
|
|
||||||
JsInvocation(context.getInnerReference(desc), args)
|
|
||||||
} else {
|
|
||||||
JsNew(context.translateQualifiedReference(serializerClass), args)
|
|
||||||
}
|
|
||||||
return ref
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createGetKClassExpression(classDescriptor: ClassDescriptor): JsExpression =
|
|
||||||
JsInvocation(context.namer().kotlin("getKClass"),
|
|
||||||
context.translateQualifiedReference(classDescriptor))
|
|
||||||
|
|
||||||
|
|
||||||
override fun generateLoad(function: FunctionDescriptor) = generateFunction(function) { jsFun, context ->
|
override fun generateLoad(function: FunctionDescriptor) = generateFunction(function) { jsFun, context ->
|
||||||
val inputClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.STRUCTURE_DECODER_CLASS)
|
val inputClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.STRUCTURE_DECODER_CLASS)
|
||||||
|
|||||||
+7
-5
@@ -191,11 +191,13 @@ class SerializerCodegenImpl(
|
|||||||
dup() // array
|
dup() // array
|
||||||
iconst(i) // index
|
iconst(i) // index
|
||||||
val prop = orderedProperties[i]
|
val prop = orderedProperties[i]
|
||||||
stackValueSerializerInstanceFromSerializerWithoutSti(
|
assert(
|
||||||
codegen,
|
stackValueSerializerInstanceFromSerializerWithoutSti(
|
||||||
prop,
|
codegen,
|
||||||
this@SerializerCodegenImpl
|
prop,
|
||||||
)
|
this@SerializerCodegenImpl
|
||||||
|
)
|
||||||
|
) { "Property ${prop.name} must have serializer" }
|
||||||
astore(kSerializerType)
|
astore(kSerializerType)
|
||||||
}
|
}
|
||||||
areturn(kSerializerArrayType)
|
areturn(kSerializerArrayType)
|
||||||
|
|||||||
Reference in New Issue
Block a user