From 114fb5790a4929c6aa110da1832cc7c36ce5ee82 Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Fri, 4 May 2018 16:23:12 +0300 Subject: [PATCH] Fix for Kotlin/kotlinx.serialization/118 Fix for Kotlin/kotlinx.serialization/123: resolve annotation parameters in-place Fix for Kotlin/kotlinx.serialization/125 Now polymorphic serializer required by all modalities expect final --- .../compiler/backend/common/TypeUtil.kt | 16 +++++----------- .../backend/js/SerializerJsTranslator.kt | 4 +--- .../compiler/backend/jvm/JVMCodegenUtil.kt | 11 ++++++----- .../backend/jvm/SerializerCodegenImpl.kt | 4 +--- .../compiler/resolve/SerializableProperty.kt | 17 ++++++++++++++--- 5 files changed, 27 insertions(+), 25 deletions(-) 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 5364c03cbe7..af397c8ad7b 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 @@ -75,9 +75,10 @@ fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo { } fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? { - return if (kType.requiresPolymorphism()) findPolymorphicSerializer(module) - else if (kType.isTypeParameter()) return null - else kType.typeSerializer.toClassDescriptor // check for serializer defined on the type + if (kType.requiresPolymorphism()) return findPolymorphicSerializer(module) + if (kType.isTypeParameter()) return null + if (KotlinBuiltIns.isArray(kType)) return module.findClassAcrossModuleDependencies(referenceArraySerializerId) + return kType.typeSerializer.toClassDescriptor // check for serializer defined on the type ?: findStandardKotlinTypeSerializer(module, kType) // otherwise see if there is a standard serializer ?: findEnumTypeSerializer(module, kType) ?: module.findClassAcrossModuleDependencies(contextSerializerId) @@ -116,7 +117,7 @@ fun findEnumTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDe fun KotlinType.requiresPolymorphism(): Boolean { return this.toClassDescriptor?.getSuperClassNotAny()?.isInternalSerializable == true - || (this.toClassDescriptor?.modality == Modality.OPEN && this.toClassDescriptor?.unsubstitutedPrimaryConstructor != null) // open not java class + || (this.toClassDescriptor?.modality != Modality.FINAL && this.toClassDescriptor?.unsubstitutedPrimaryConstructor != null) // open not java class || this.containsTypeProjectionsInTopLevelArguments() // List<*> } @@ -142,10 +143,3 @@ fun KtPureClassOrObject.anonymousInitializers() = declarations .filterIsInstance() .mapNotNull { it.body } .toList() - -fun SerializableProperty.annotationVarsAndDesc(annotationClass: ClassDescriptor): Pair, List> { - val args: List = (this.descriptor.annotations.findAnnotation(annotationClass.fqNameSafe) as? LazyAnnotationDescriptor)?.annotationEntry?.valueArguments.orEmpty() - val consParams = annotationClass.unsubstitutedPrimaryConstructor?.valueParameters.orEmpty() - if (args.size != consParams.size) throw IllegalArgumentException("Can't use arguments with defaults for serializable annotations yet") - return args to consParams -} \ No newline at end of file diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt index 807cdf2d787..5f27437b2e1 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt @@ -34,7 +34,6 @@ import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.builtIns import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen -import org.jetbrains.kotlinx.serialization.compiler.backend.common.annotationVarsAndDesc import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId @@ -75,8 +74,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject, val call = JsInvocation(JsNameRef(context.getNameForDescriptor(addFunc), serialClassDescRef), JsStringLiteral(prop.name)) translator.addInitializerStatement(call.makeStmt()) // serialDesc.pushAnnotation(...) - for (annotationClass in prop.annotations) { - val (args, _) = prop.annotationVarsAndDesc(annotationClass) + for ((annotationClass , args, _) in prop.annotationsWithArguments) { val argExprs = args.map { arg -> Translation.translateAsExpression(arg.getArgumentExpression()!!, 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 bc30e461564..412f016bc6d 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 @@ -252,11 +252,12 @@ fun getSerialTypeInfo(property: SerializableProperty, type: Type): JVMSerialType } fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType, asmType: Type): ClassDescriptor? { - return if (kType.requiresPolymorphism()) findPolymorphicSerializer(module) - else kType.typeSerializer.toClassDescriptor // check for serializer defined on the type - ?: findStandardAsmTypeSerializer(module, asmType) // otherwise see if there is a standard serializer - ?: findEnumTypeSerializer(module, kType) - ?: module.findClassAcrossModuleDependencies(contextSerializerId) + if (kType.requiresPolymorphism()) return findPolymorphicSerializer(module) + if (KotlinBuiltIns.isArray(kType)) return module.findClassAcrossModuleDependencies(referenceArraySerializerId) + return kType.typeSerializer.toClassDescriptor // check for serializer defined on the type + ?: findStandardAsmTypeSerializer(module, asmType) // otherwise see if there is a standard serializer + ?: findEnumTypeSerializer(module, kType) + ?: module.findClassAcrossModuleDependencies(contextSerializerId) } fun findStandardAsmTypeSerializer(module: ModuleDescriptor, asmType: Type): ClassDescriptor? { 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 ce66df5496d..a4249d42526 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 @@ -24,7 +24,6 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen -import org.jetbrains.kotlinx.serialization.compiler.backend.common.annotationVarsAndDesc import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.typeArgPrefix import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorBySerializer @@ -89,14 +88,13 @@ class SerializerCodegenImpl( aconst(property.name) invokevirtual(descImplType.internalName, "addElement", "(Ljava/lang/String;)V", false) // pushing annotations - for (annotationClass in property.annotations) { + for ((annotationClass, args, consParams) in property.annotationsWithArguments) { load(classDescVar, descImplType) val implType = codegen.typeMapper.mapType(annotationClass).internalName + "\$" + KSerializerDescriptorResolver.IMPL_NAME.identifier // new Annotation$Impl(...) anew(Type.getObjectType(implType)) dup() val sb = StringBuilder("(") - val (args, consParams) = property.annotationVarsAndDesc(annotationClass) for (i in consParams.indices) { val decl = args[i] val desc = consParams[i] diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt index 0f82c7616c1..ba6a9dd1972 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt @@ -16,8 +16,12 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.psi.ValueArgument import org.jetbrains.kotlin.resolve.descriptorUtil.module +import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationDescriptor class SerializableProperty(val descriptor: PropertyDescriptor, val isConstructorParameterWithDefault: Boolean) { val name = descriptor.annotations.serialNameValue ?: descriptor.name.asString() @@ -27,7 +31,14 @@ class SerializableProperty(val descriptor: PropertyDescriptor, val isConstructor val serializableWith = descriptor.annotations.serializableWith?.let { checkSerializerNullability(type, it) } val optional = descriptor.annotations.serialOptional val transient = descriptor.annotations.serialTransient - val annotations = descriptor.annotations - .mapNotNull { it.type.toClassDescriptor } - .filter { it.annotations.hasAnnotation(serialInfoFqName) } + val annotationsWithArguments: List, List>> = + descriptor.annotations.asSequence() + .filter { it.type.toClassDescriptor?.annotations?.hasAnnotation(serialInfoFqName) == true } + .filterIsInstance() + .mapNotNull { annDesc -> + annDesc.type.toClassDescriptor?.let { + Triple(it, annDesc.annotationEntry.valueArguments, it.unsubstitutedPrimaryConstructor?.valueParameters.orEmpty()) + } + } + .toList() }