From f0e81c6eb81af51d4c2d28ca4bba04c7b1cefcb0 Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Thu, 20 Sep 2018 15:26:26 +0300 Subject: [PATCH] Respect @ContextualSerialization on file Add common ancestor to all serializable generators --- .../backend/common/AbstractSerialGenerator.kt | 36 ++++++++++++++++++ .../backend/common/SerializableCodegen.kt | 4 +- .../common/SerializableCompanionCodegen.kt | 6 ++- .../backend/common/SerializerCodegen.kt | 4 +- .../compiler/backend/common/TypeUtil.kt | 6 +-- .../ir/SerializableCompanionIrGenerator.kt | 2 +- .../js/SerializableCompanionJsTranslator.kt | 3 +- .../compiler/backend/jvm/JVMCodegenUtil.kt | 37 +++++++++++-------- .../backend/jvm/SerializableCodegenImpl.kt | 2 +- .../jvm/SerializableCompanionCodegenImpl.kt | 3 +- .../backend/jvm/SerializerCodegenImpl.kt | 4 +- 11 files changed, 76 insertions(+), 31 deletions(-) create mode 100644 plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/AbstractSerialGenerator.kt diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/AbstractSerialGenerator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/AbstractSerialGenerator.kt new file mode 100644 index 00000000000..89f378ca0e6 --- /dev/null +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/AbstractSerialGenerator.kt @@ -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 { + val annotation = AnnotationsUtils + .getContainingFileAnnotations(bindingContext, declarationInFile) + .find { it.fqName == annotationFqName } + ?: return emptyList() + @Suppress("UNCHECKED_CAST") + val typeList: List = annotation.firstArgument()?.value as? List ?: return emptyList() + return typeList.map { it.value } + } + + val contextualKClassListInCurrentFile: Set by lazy { + getKClassListFromFileAnnotation( + SerializationAnnotations.contextualFqName, + currentDeclaration + ).toSet() + } +} \ No newline at end of file diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCodegen.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCodegen.kt index 6ffc98dc15c..827d63b367d 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCodegen.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCodegen.kt @@ -25,8 +25,8 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperti abstract class SerializableCodegen( protected val serializableDescriptor: ClassDescriptor, - private val bindingContext: BindingContext -) { + bindingContext: BindingContext +) : AbstractSerialGenerator(bindingContext, serializableDescriptor) { protected val properties = SerializableProperties(serializableDescriptor, bindingContext) fun generate() { diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCompanionCodegen.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCompanionCodegen.kt index a1f2d31cd05..74477246539 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCompanionCodegen.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializableCompanionCodegen.kt @@ -19,12 +19,14 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.common import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor 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.getSerializableClassDescriptorByCompanion abstract class SerializableCompanionCodegen( - protected val companionDescriptor: ClassDescriptor -) { + protected val companionDescriptor: ClassDescriptor, + bindingContext: BindingContext +) : AbstractSerialGenerator(bindingContext, companionDescriptor) { protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorByCompanion(companionDescriptor)!! fun generate() { diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt index c605e57487e..8e4c6bb9934 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt @@ -20,8 +20,6 @@ import org.jetbrains.kotlin.backend.common.CodegenUtil.getMemberToGenerate import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.incremental.components.NoLookupLocation 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.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered @@ -31,7 +29,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescripto abstract class SerializerCodegen( protected val serializerDescriptor: ClassDescriptor, bindingContext: BindingContext -) { +) : AbstractSerialGenerator(bindingContext, serializerDescriptor) { // protected val serializerDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext) protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!! protected val serialName: String = serializableDescriptor.annotations.serialNameValue ?: serializableDescriptor.fqNameUnsafe.asString() diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt index 9759da79f06..3310f421a77 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt @@ -49,7 +49,7 @@ open class SerialTypeInfo( val unit: Boolean = false ) -fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo { +fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo { val T = property.type val serializableWith = property.serializableWith?.toClassDescriptor 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, kType: KotlinType, annotations: Annotations = kType.annotations, @@ -89,7 +89,7 @@ fun findTypeSerializerOrContext( ): ClassDescriptor? { if (kType.isTypeParameter()) return null fun getContextualSerializer() = - if (annotations.hasAnnotation(SerializationAnnotations.contextualFqName)) + if (annotations.hasAnnotation(SerializationAnnotations.contextualFqName) || kType in contextualKClassListInCurrentFile) module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer) else throw CompilationException( diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableCompanionIrGenerator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableCompanionIrGenerator.kt index fe1f59e755b..868bffeb09a 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableCompanionIrGenerator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableCompanionIrGenerator.kt @@ -20,7 +20,7 @@ class SerializableCompanionIrGenerator( val irClass: IrClass, override val compilerContext: BackendContext, bindingContext: BindingContext -) : SerializableCompanionCodegen(irClass.descriptor), IrBuilderExtension { +) : SerializableCompanionCodegen(irClass.descriptor, bindingContext), IrBuilderExtension { override val translator: TypeTranslator = compilerContext.createTypeTranslator(serializableDescriptor.module) private val _table = SymbolTable() override val BackendContext.localSymbolTable: SymbolTable diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableCompanionJsTranslator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableCompanionJsTranslator.kt index 466c29ef8a2..5cf622f7bc4 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableCompanionJsTranslator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializableCompanionJsTranslator.kt @@ -32,7 +32,8 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.* class SerializableCompanionJsTranslator( declaration: ClassDescriptor, val translator: DeclarationBodyVisitor, - val context: TranslationContext): SerializableCompanionCodegen(declaration) { + val context: TranslationContext +): SerializableCompanionCodegen(declaration, context.bindingContext()) { override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) { val f = context.buildFunction(methodDescriptor) {jsFun, context -> diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt index dc5ecef6cde..24e133669c2 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.types.KotlinType 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.findTypeSerializerOrContext import org.jetbrains.kotlinx.serialization.compiler.resolve.* @@ -90,12 +91,15 @@ internal fun InstructionAdapter.genExceptionThrow(exceptionClass: String, messag athrow() } -fun InstructionAdapter.genKOutputMethodCall(property: SerializableProperty, classCodegen: ImplementationBodyCodegen, expressionCodegen: ExpressionCodegen, - propertyOwnerType: Type, ownerVar: Int, fromClassStartVar: Int? = null) { +fun InstructionAdapter.genKOutputMethodCall( + property: SerializableProperty, classCodegen: ImplementationBodyCodegen, expressionCodegen: ExpressionCodegen, + propertyOwnerType: Type, ownerVar: Int, fromClassStartVar: Int? = null, + generator: AbstractSerialGenerator +) { val propertyType = classCodegen.typeMapper.mapType(property.type) - val sti = getSerialTypeInfo(property, propertyType) - val useSerializer = if (fromClassStartVar == null) stackValueSerializerInstanceFromSerializer(classCodegen, sti) - else stackValueSerializerInstanceFromClass(classCodegen, sti, fromClassStartVar) + val sti = generator.getSerialTypeInfo(property, propertyType) + val useSerializer = if (fromClassStartVar == null) stackValueSerializerInstanceFromSerializer(classCodegen, sti, generator) + else stackValueSerializerInstanceFromClass(classCodegen, sti, fromClassStartVar, generator) if (!sti.unit) ImplementationBodyCodegen.genPropertyOnStack( this, expressionCodegen.context, @@ -104,11 +108,13 @@ fun InstructionAdapter.genKOutputMethodCall(property: SerializableProperty, clas ownerVar, classCodegen.state ) - invokeinterface(kOutputType.internalName, + invokeinterface( + kOutputType.internalName, CallingConventions.encode + sti.elementMethodPrefix + (if (useSerializer) "Serializable" else "") + CallingConventions.elementPostfix, - "(" + descType.descriptor + "I" + - (if (useSerializer) kSerialSaverType.descriptor else "") + - (if (sti.unit) "" else sti.type.descriptor) + ")V") + "(" + descType.descriptor + "I" + + (if (useSerializer) kSerialSaverType.descriptor else "") + + (if (sti.unit) "" else sti.type.descriptor) + ")V" + ) } internal fun InstructionAdapter.buildInternalConstructorDesc(propsStartVar: Int, bitMaskBase: Int, codegen: ClassBodyCodegen, args: List): String { @@ -146,10 +152,11 @@ internal val contextSerializerId = ClassId(packageFqName, Name.identifier(Specia internal fun InstructionAdapter.stackValueSerializerInstanceFromClass( codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo, - varIndexStart: Int + varIndexStart: Int, + serializerCodegen: AbstractSerialGenerator ): Boolean { val serializer = sti.serializer - return stackValueSerializerInstance( + return serializerCodegen.stackValueSerializerInstance( codegen, sti.property.module, sti.property.type, @@ -161,8 +168,8 @@ internal fun InstructionAdapter.stackValueSerializerInstanceFromClass( } } -internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo): Boolean { - return stackValueSerializerInstance( +internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo, serializerCodegen: AbstractSerialGenerator): Boolean { + return serializerCodegen.stackValueSerializerInstance( codegen, sti.property.module, sti.property.type, sti.serializer, this, sti.property.genericIndex ) { idx -> @@ -173,7 +180,7 @@ internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(codeg // returns false is cannot not use serializer // 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 { if (genericIndex != null) { // get field from serializer object @@ -262,7 +269,7 @@ class JVMSerialTypeInfo( unit: Boolean = false ) : 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( property, Type.getType("Ljava/lang/Object;"), diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt index f041d5ab986..1984346a84a 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCodegenImpl.kt @@ -100,7 +100,7 @@ class SerializableCodegenImpl( load(outputI, kOutputType) load(serialDescI, descType) iconst(i) - genKOutputMethodCall(property, classCodegen, exprCodegen, thisAsmType, thisI, offsetI) + genKOutputMethodCall(property, classCodegen, exprCodegen, thisAsmType, thisI, offsetI, generator = this@SerializableCodegenImpl) } areturn(Type.VOID_TYPE) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCompanionCodegenImpl.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCompanionCodegenImpl.kt index 748384c44e9..c53d4ec5e47 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCompanionCodegenImpl.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializableCompanionCodegenImpl.kt @@ -18,12 +18,13 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen import org.jetbrains.kotlin.descriptors.FunctionDescriptor +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.* class SerializableCompanionCodegenImpl(private val codegen: ImplementationBodyCodegen) : - SerializableCompanionCodegen(codegen.descriptor) { + SerializableCompanionCodegen(codegen.descriptor, codegen.bindingContext) { companion object { fun generateSerializableExtensions(codegen: ImplementationBodyCodegen) { diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt index 1411bd36c64..88507ddd7c7 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt @@ -196,7 +196,7 @@ class SerializerCodegenImpl( load(outputVar, kOutputType) load(descVar, descType) iconst(index) - genKOutputMethodCall(property, codegen, expressionCodegen, objType, objVar) + genKOutputMethodCall(property, codegen, expressionCodegen, objType, objVar, generator = this@SerializerCodegenImpl) } } // output.writeEnd(classDesc) @@ -303,7 +303,7 @@ class SerializerCodegenImpl( iconst(labelNum) val sti = getSerialTypeInfo(property, propertyType) - val useSerializer = stackValueSerializerInstanceFromSerializer(codegen, sti) + val useSerializer = stackValueSerializerInstanceFromSerializer(codegen, sti, this@SerializerCodegenImpl) val unknownSer = (!useSerializer && sti.elementMethodPrefix.isEmpty()) if (unknownSer) { aconst(codegen.typeMapper.mapType(property.type))