Respect @ContextualSerialization on file

Add common ancestor to all serializable generators
This commit is contained in:
Leonid Startsev
2018-09-20 15:26:26 +03:00
committed by Leonid Startsev
parent 82fa152514
commit f0e81c6eb8
11 changed files with 76 additions and 31 deletions
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlinx.serialization.compiler.backend.common
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.constants.KClassValue
import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgument
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
abstract class AbstractSerialGenerator(val bindingContext: BindingContext, val currentDeclaration: ClassDescriptor) {
private fun getKClassListFromFileAnnotation(annotationFqName: FqName, declarationInFile: DeclarationDescriptor): List<KotlinType> {
val annotation = AnnotationsUtils
.getContainingFileAnnotations(bindingContext, declarationInFile)
.find { it.fqName == annotationFqName }
?: return emptyList()
@Suppress("UNCHECKED_CAST")
val typeList: List<KClassValue> = annotation.firstArgument()?.value as? List<KClassValue> ?: return emptyList()
return typeList.map { it.value }
}
val contextualKClassListInCurrentFile: Set<KotlinType> by lazy {
getKClassListFromFileAnnotation(
SerializationAnnotations.contextualFqName,
currentDeclaration
).toSet()
}
}
@@ -25,8 +25,8 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperti
abstract class SerializableCodegen( abstract class SerializableCodegen(
protected val serializableDescriptor: ClassDescriptor, protected val serializableDescriptor: ClassDescriptor,
private val bindingContext: BindingContext bindingContext: BindingContext
) { ) : AbstractSerialGenerator(bindingContext, serializableDescriptor) {
protected val properties = SerializableProperties(serializableDescriptor, bindingContext) protected val properties = SerializableProperties(serializableDescriptor, bindingContext)
fun generate() { fun generate() {
@@ -19,12 +19,14 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.common
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.psi2ir.findSingleFunction import org.jetbrains.kotlin.psi2ir.findSingleFunction
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIALIZER_PROVIDER_NAME import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIALIZER_PROVIDER_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
abstract class SerializableCompanionCodegen( abstract class SerializableCompanionCodegen(
protected val companionDescriptor: ClassDescriptor protected val companionDescriptor: ClassDescriptor,
) { bindingContext: BindingContext
) : AbstractSerialGenerator(bindingContext, companionDescriptor) {
protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorByCompanion(companionDescriptor)!! protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorByCompanion(companionDescriptor)!!
fun generate() { fun generate() {
@@ -20,8 +20,6 @@ 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.kotlin.name.Name 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.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
@@ -31,7 +29,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescripto
abstract class SerializerCodegen( abstract class SerializerCodegen(
protected val serializerDescriptor: ClassDescriptor, protected val serializerDescriptor: ClassDescriptor,
bindingContext: BindingContext bindingContext: BindingContext
) { ) : AbstractSerialGenerator(bindingContext, serializerDescriptor) {
// protected val serializerDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext) // protected val serializerDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext)
protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!! protected 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()
@@ -49,7 +49,7 @@ open class SerialTypeInfo(
val unit: Boolean = false val unit: Boolean = false
) )
fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo { fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
val T = property.type val T = property.type
val serializableWith = property.serializableWith?.toClassDescriptor val serializableWith = property.serializableWith?.toClassDescriptor
if (serializableWith != null) return SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializableWith) if (serializableWith != null) return SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializableWith)
@@ -81,7 +81,7 @@ fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
} }
} }
fun findTypeSerializerOrContext( fun AbstractSerialGenerator.findTypeSerializerOrContext(
module: ModuleDescriptor, module: ModuleDescriptor,
kType: KotlinType, kType: KotlinType,
annotations: Annotations = kType.annotations, annotations: Annotations = kType.annotations,
@@ -89,7 +89,7 @@ fun findTypeSerializerOrContext(
): ClassDescriptor? { ): ClassDescriptor? {
if (kType.isTypeParameter()) return null if (kType.isTypeParameter()) return null
fun getContextualSerializer() = fun getContextualSerializer() =
if (annotations.hasAnnotation(SerializationAnnotations.contextualFqName)) if (annotations.hasAnnotation(SerializationAnnotations.contextualFqName) || kType in contextualKClassListInCurrentFile)
module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer) module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer)
else else
throw CompilationException( throw CompilationException(
@@ -20,7 +20,7 @@ class SerializableCompanionIrGenerator(
val irClass: IrClass, val irClass: IrClass,
override val compilerContext: BackendContext, override val compilerContext: BackendContext,
bindingContext: BindingContext bindingContext: BindingContext
) : SerializableCompanionCodegen(irClass.descriptor), IrBuilderExtension { ) : SerializableCompanionCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
override val translator: TypeTranslator = compilerContext.createTypeTranslator(serializableDescriptor.module) override val translator: TypeTranslator = compilerContext.createTypeTranslator(serializableDescriptor.module)
private val _table = SymbolTable() private val _table = SymbolTable()
override val BackendContext.localSymbolTable: SymbolTable override val BackendContext.localSymbolTable: SymbolTable
@@ -32,7 +32,8 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.*
class SerializableCompanionJsTranslator( class SerializableCompanionJsTranslator(
declaration: ClassDescriptor, declaration: ClassDescriptor,
val translator: DeclarationBodyVisitor, val translator: DeclarationBodyVisitor,
val context: TranslationContext): SerializableCompanionCodegen(declaration) { val context: TranslationContext
): 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 ->
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
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.AbstractSerialGenerator
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerialTypeInfo import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerialTypeInfo
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.*
@@ -90,12 +91,15 @@ internal fun InstructionAdapter.genExceptionThrow(exceptionClass: String, messag
athrow() athrow()
} }
fun InstructionAdapter.genKOutputMethodCall(property: SerializableProperty, classCodegen: ImplementationBodyCodegen, expressionCodegen: ExpressionCodegen, fun InstructionAdapter.genKOutputMethodCall(
propertyOwnerType: Type, ownerVar: Int, fromClassStartVar: Int? = null) { property: SerializableProperty, classCodegen: ImplementationBodyCodegen, expressionCodegen: ExpressionCodegen,
propertyOwnerType: Type, ownerVar: Int, fromClassStartVar: Int? = null,
generator: AbstractSerialGenerator
) {
val propertyType = classCodegen.typeMapper.mapType(property.type) val propertyType = classCodegen.typeMapper.mapType(property.type)
val sti = getSerialTypeInfo(property, propertyType) val sti = generator.getSerialTypeInfo(property, propertyType)
val useSerializer = if (fromClassStartVar == null) stackValueSerializerInstanceFromSerializer(classCodegen, sti) val useSerializer = if (fromClassStartVar == null) stackValueSerializerInstanceFromSerializer(classCodegen, sti, generator)
else stackValueSerializerInstanceFromClass(classCodegen, sti, fromClassStartVar) else stackValueSerializerInstanceFromClass(classCodegen, sti, fromClassStartVar, generator)
if (!sti.unit) ImplementationBodyCodegen.genPropertyOnStack( if (!sti.unit) ImplementationBodyCodegen.genPropertyOnStack(
this, this,
expressionCodegen.context, expressionCodegen.context,
@@ -104,11 +108,13 @@ fun InstructionAdapter.genKOutputMethodCall(property: SerializableProperty, clas
ownerVar, ownerVar,
classCodegen.state classCodegen.state
) )
invokeinterface(kOutputType.internalName, invokeinterface(
kOutputType.internalName,
CallingConventions.encode + sti.elementMethodPrefix + (if (useSerializer) "Serializable" else "") + CallingConventions.elementPostfix, CallingConventions.encode + sti.elementMethodPrefix + (if (useSerializer) "Serializable" else "") + CallingConventions.elementPostfix,
"(" + descType.descriptor + "I" + "(" + descType.descriptor + "I" +
(if (useSerializer) kSerialSaverType.descriptor else "") + (if (useSerializer) kSerialSaverType.descriptor else "") +
(if (sti.unit) "" else sti.type.descriptor) + ")V") (if (sti.unit) "" else sti.type.descriptor) + ")V"
)
} }
internal fun InstructionAdapter.buildInternalConstructorDesc(propsStartVar: Int, bitMaskBase: Int, codegen: ClassBodyCodegen, args: List<SerializableProperty>): String { internal fun InstructionAdapter.buildInternalConstructorDesc(propsStartVar: Int, bitMaskBase: Int, codegen: ClassBodyCodegen, args: List<SerializableProperty>): String {
@@ -146,10 +152,11 @@ internal val contextSerializerId = ClassId(packageFqName, Name.identifier(Specia
internal fun InstructionAdapter.stackValueSerializerInstanceFromClass( internal fun InstructionAdapter.stackValueSerializerInstanceFromClass(
codegen: ClassBodyCodegen, codegen: ClassBodyCodegen,
sti: JVMSerialTypeInfo, sti: JVMSerialTypeInfo,
varIndexStart: Int varIndexStart: Int,
serializerCodegen: AbstractSerialGenerator
): Boolean { ): Boolean {
val serializer = sti.serializer val serializer = sti.serializer
return stackValueSerializerInstance( return serializerCodegen.stackValueSerializerInstance(
codegen, codegen,
sti.property.module, sti.property.module,
sti.property.type, sti.property.type,
@@ -161,8 +168,8 @@ internal fun InstructionAdapter.stackValueSerializerInstanceFromClass(
} }
} }
internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo): Boolean { internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo, serializerCodegen: AbstractSerialGenerator): Boolean {
return stackValueSerializerInstance( return serializerCodegen.stackValueSerializerInstance(
codegen, sti.property.module, sti.property.type, codegen, sti.property.module, sti.property.type,
sti.serializer, this, sti.property.genericIndex sti.serializer, this, sti.property.genericIndex
) { idx -> ) { idx ->
@@ -173,7 +180,7 @@ internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(codeg
// returns false is cannot not use serializer // returns false is cannot not use serializer
// use iv == null to check only (do not emit serializer onto stack) // use iv == null to check only (do not emit serializer onto stack)
internal fun stackValueSerializerInstance(codegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?, internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?,
iv: InstructionAdapter?, genericIndex: Int? = null, genericSerializerFieldGetter: (InstructionAdapter.(Int) -> Unit)? = null): Boolean { iv: InstructionAdapter?, genericIndex: Int? = null, genericSerializerFieldGetter: (InstructionAdapter.(Int) -> Unit)? = null): Boolean {
if (genericIndex != null) { if (genericIndex != null) {
// get field from serializer object // get field from serializer object
@@ -262,7 +269,7 @@ class JVMSerialTypeInfo(
unit: Boolean = false unit: Boolean = false
) : SerialTypeInfo(property, nn, serializer, unit) ) : SerialTypeInfo(property, nn, serializer, unit)
fun getSerialTypeInfo(property: SerializableProperty, type: Type): JVMSerialTypeInfo { fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty, type: Type): JVMSerialTypeInfo {
if (property.type.isTypeParameter()) return JVMSerialTypeInfo( if (property.type.isTypeParameter()) return JVMSerialTypeInfo(
property, property,
Type.getType("Ljava/lang/Object;"), Type.getType("Ljava/lang/Object;"),
@@ -100,7 +100,7 @@ class SerializableCodegenImpl(
load(outputI, kOutputType) load(outputI, kOutputType)
load(serialDescI, descType) load(serialDescI, descType)
iconst(i) iconst(i)
genKOutputMethodCall(property, classCodegen, exprCodegen, thisAsmType, thisI, offsetI) genKOutputMethodCall(property, classCodegen, exprCodegen, thisAsmType, thisI, offsetI, generator = this@SerializableCodegenImpl)
} }
areturn(Type.VOID_TYPE) areturn(Type.VOID_TYPE)
@@ -18,12 +18,13 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
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.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.*
class SerializableCompanionCodegenImpl(private val codegen: ImplementationBodyCodegen) : class SerializableCompanionCodegenImpl(private val codegen: ImplementationBodyCodegen) :
SerializableCompanionCodegen(codegen.descriptor) { SerializableCompanionCodegen(codegen.descriptor, codegen.bindingContext) {
companion object { companion object {
fun generateSerializableExtensions(codegen: ImplementationBodyCodegen) { fun generateSerializableExtensions(codegen: ImplementationBodyCodegen) {
@@ -196,7 +196,7 @@ class SerializerCodegenImpl(
load(outputVar, kOutputType) load(outputVar, kOutputType)
load(descVar, descType) load(descVar, descType)
iconst(index) iconst(index)
genKOutputMethodCall(property, codegen, expressionCodegen, objType, objVar) genKOutputMethodCall(property, codegen, expressionCodegen, objType, objVar, generator = this@SerializerCodegenImpl)
} }
} }
// output.writeEnd(classDesc) // output.writeEnd(classDesc)
@@ -303,7 +303,7 @@ class SerializerCodegenImpl(
iconst(labelNum) iconst(labelNum)
val sti = getSerialTypeInfo(property, propertyType) val sti = getSerialTypeInfo(property, propertyType)
val useSerializer = stackValueSerializerInstanceFromSerializer(codegen, sti) val useSerializer = stackValueSerializerInstanceFromSerializer(codegen, sti, this@SerializerCodegenImpl)
val unknownSer = (!useSerializer && sti.elementMethodPrefix.isEmpty()) val unknownSer = (!useSerializer && sti.elementMethodPrefix.isEmpty())
if (unknownSer) { if (unknownSer) {
aconst(codegen.typeMapper.mapType(property.type)) aconst(codegen.typeMapper.mapType(property.type))