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
This commit is contained in:
Leonid Startsev
2018-05-04 16:23:12 +03:00
parent 97694e65aa
commit 114fb5790a
5 changed files with 27 additions and 25 deletions
@@ -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<KtAnonymousInitializer>()
.mapNotNull { it.body }
.toList()
fun SerializableProperty.annotationVarsAndDesc(annotationClass: ClassDescriptor): Pair<List<ValueArgument>, List<ValueParameterDescriptor>> {
val args: List<ValueArgument> = (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
}
@@ -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)
}
@@ -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? {
@@ -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]
@@ -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<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> =
descriptor.annotations.asSequence()
.filter { it.type.toClassDescriptor?.annotations?.hasAnnotation(serialInfoFqName) == true }
.filterIsInstance<LazyAnnotationDescriptor>()
.mapNotNull { annDesc ->
annDesc.type.toClassDescriptor?.let {
Triple(it, annDesc.annotationEntry.valueArguments, it.unsubstitutedPrimaryConstructor?.valueParameters.orEmpty())
}
}
.toList()
}