Support SerializerFactory in Native

kotlinx.serialization plugin now adds additional function to companions
of generic classes in order to overcome lack of reflection. This
helps retrieving generic serializers from KType.
This commit is contained in:
Leonid Startsev
2019-12-20 18:21:41 +03:00
parent 976db65911
commit 137c500e3a
5 changed files with 133 additions and 21 deletions
@@ -7,12 +7,15 @@ 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.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.constants.KClassValue import org.jetbrains.kotlin.resolve.constants.KClassValue
import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgument import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgument
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.supertypes import org.jetbrains.kotlin.types.typeUtil.supertypes
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
@@ -48,4 +51,7 @@ abstract class AbstractSerialGenerator(val bindingContext: BindingContext, val c
{ it.toClassDescriptor!! } { it.toClassDescriptor!! }
) )
} }
protected fun ClassDescriptor.getFuncDesc(funcName: String): Sequence<FunctionDescriptor> =
unsubstitutedMemberScope.getDescriptorsFiltered { it == Name.identifier(funcName) }.asSequence().filterIsInstance<FunctionDescriptor>()
} }
@@ -148,9 +148,6 @@ abstract class SerializerCodegen(
isReturnTypeOk(property) isReturnTypeOk(property)
} }
protected fun ClassDescriptor.getFuncDesc(funcName: String): Sequence<FunctionDescriptor> =
unsubstitutedMemberScope.getDescriptorsFiltered { it == Name.identifier(funcName) }.asSequence().filterIsInstance<FunctionDescriptor>()
companion object { companion object {
fun getSyntheticLoadMember(serializerDescriptor: ClassDescriptor): FunctionDescriptor? = getMemberToGenerate( fun getSyntheticLoadMember(serializerDescriptor: ClassDescriptor): FunctionDescriptor? = getMemberToGenerate(
serializerDescriptor, SerialEntityNames.LOAD, serializerDescriptor, SerialEntityNames.LOAD,
@@ -1,24 +1,26 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irInt
import org.jetbrains.kotlin.ir.builders.irReturn import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.util.TypeTranslator import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.types.impl.IrTypeProjectionImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
@@ -77,7 +79,7 @@ class SerializableCompanionIrGenerator(
irSerializableClass.annotations.add(annotationCtorCall) irSerializableClass.annotations.add(annotationCtorCall)
} }
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) = override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
irClass.contributeFunction(methodDescriptor) { getter -> irClass.contributeFunction(methodDescriptor) { getter ->
val serializer = requireNotNull( val serializer = requireNotNull(
findTypeSerializer( findTypeSerializer(
@@ -94,5 +96,40 @@ class SerializableCompanionIrGenerator(
patchSerializableClassWithMarkerAnnotation(serializer) patchSerializableClassWithMarkerAnnotation(serializer)
+irReturn(requireNotNull(expr)) +irReturn(requireNotNull(expr))
} }
generateSerializerFactoryIfNeeded(methodDescriptor)
}
private fun generateSerializerFactoryIfNeeded(getterDescriptor: FunctionDescriptor) {
if (serializableDescriptor.declaredTypeParameters.isEmpty()) return
val serialFactoryDescriptor = companionDescriptor.unsubstitutedMemberScope.getContributedFunctions(
SerialEntityNames.SERIALIZER_PROVIDER_NAME,
NoLookupLocation.FROM_BACKEND
).firstOrNull {
it.valueParameters.size == 1
&& it.valueParameters.first().isVararg
&& it.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
&& it.returnType != null && isKSerializer(it.returnType)
} ?: return
irClass.contributeFunction(serialFactoryDescriptor) { factory ->
val array = factory.valueParameters.first()
val argsSize = serializableDescriptor.declaredTypeParameters.size
val arrayGet =
compilerContext.builtIns.array.getFuncDesc("get").single()
val arrayGetSymbol = compilerContext.symbolTable.referenceFunction(arrayGet)
val outAnyNullable = makeTypeProjection(compilerContext.irBuiltIns.anyNType, Variance.OUT_VARIANCE).type
val serializers: List<IrExpression> = (0 until argsSize).map { irInvoke(irGet(array), arrayGetSymbol, irInt(it)) }
val serializerCall = compilerContext.symbolTable.referenceSimpleFunction(getterDescriptor)
val call = irInvoke(
IrGetValueImpl(startOffset, endOffset, factory.dispatchReceiverParameter!!.symbol),
serializerCall,
List(argsSize) { outAnyNullable },
serializers
)
+irReturn(call)
patchSerializableClassWithMarkerAnnotation(companionDescriptor)
}
}
} }
@@ -72,6 +72,7 @@ open class SerializationResolveExtension : SyntheticResolveExtension {
override fun addSyntheticSupertypes(thisDescriptor: ClassDescriptor, supertypes: MutableList<KotlinType>) { override fun addSyntheticSupertypes(thisDescriptor: ClassDescriptor, supertypes: MutableList<KotlinType>) {
KSerializerDescriptorResolver.addSerialInfoSuperType(thisDescriptor, supertypes) KSerializerDescriptorResolver.addSerialInfoSuperType(thisDescriptor, supertypes)
KSerializerDescriptorResolver.addSerializerSupertypes(thisDescriptor, supertypes) KSerializerDescriptorResolver.addSerializerSupertypes(thisDescriptor, supertypes)
KSerializerDescriptorResolver.addSerializerFactorySuperType(thisDescriptor, supertypes)
} }
override fun generateSyntheticSecondaryConstructors( override fun generateSyntheticSecondaryConstructors(
@@ -27,18 +27,20 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.js.isJs
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.platform.konan.isNative
import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptor import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptor
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.descriptorUtil.platform
import org.jetbrains.kotlin.resolve.lazy.LazyClassContext import org.jetbrains.kotlin.resolve.lazy.LazyClassContext
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.KotlinTypeFactory
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.createProjection import org.jetbrains.kotlin.types.typeUtil.createProjection
import org.jetbrains.kotlin.types.typeUtil.makeNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SimpleSyntheticPropertyDescriptor import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SimpleSyntheticPropertyDescriptor
@@ -50,14 +52,17 @@ import java.util.*
object KSerializerDescriptorResolver { object KSerializerDescriptorResolver {
private fun createDeprecatedHiddenAnnotation(module: ModuleDescriptor): AnnotationDescriptor { fun createDeprecatedHiddenAnnotation(module: ModuleDescriptor): AnnotationDescriptor {
return module.builtIns.createDeprecatedAnnotation("This synthesized declaration should not be used directly", level = "HIDDEN") return module.builtIns.createDeprecatedAnnotation(
"This synthesized declaration should not be used directly",
level = "HIDDEN"
)
} }
fun isSerialInfoImpl(thisDescriptor: ClassDescriptor): Boolean { fun isSerialInfoImpl(thisDescriptor: ClassDescriptor): Boolean {
return thisDescriptor.name == IMPL_NAME return thisDescriptor.name == IMPL_NAME
&& thisDescriptor.containingDeclaration is LazyClassDescriptor && thisDescriptor.containingDeclaration is LazyClassDescriptor
&& thisDescriptor.containingDeclaration.annotations.hasAnnotation(serialInfoFqName) && thisDescriptor.containingDeclaration.annotations.hasAnnotation(serialInfoFqName)
} }
fun addSerialInfoSuperType(thisDescriptor: ClassDescriptor, supertypes: MutableList<KotlinType>) { fun addSerialInfoSuperType(thisDescriptor: ClassDescriptor, supertypes: MutableList<KotlinType>) {
@@ -66,6 +71,20 @@ object KSerializerDescriptorResolver {
} }
} }
private fun ClassDescriptor.needSerializerFactory(): Boolean {
if (this.platform?.isNative() != true) return false
val serializableClass = getSerializableClassDescriptorByCompanion(this) ?: return false
if (serializableClass.declaredTypeParameters.isEmpty()) return false
return true
}
fun addSerializerFactorySuperType(classDescriptor: ClassDescriptor, supertypes: MutableList<KotlinType>) {
if (!classDescriptor.needSerializerFactory()) return
val serializerFactoryClass =
classDescriptor.module.getClassFromInternalSerializationPackage("SerializerFactory")
supertypes.add(KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, serializerFactoryClass, listOf()))
}
fun addSerializerSupertypes(classDescriptor: ClassDescriptor, supertypes: MutableList<KotlinType>) { fun addSerializerSupertypes(classDescriptor: ClassDescriptor, supertypes: MutableList<KotlinType>) {
val serializableClassDescriptor = getSerializableClassDescriptorBySerializer(classDescriptor) ?: return val serializableClassDescriptor = getSerializableClassDescriptorBySerializer(classDescriptor) ?: return
if (supertypes.any(::isKSerializer)) return if (supertypes.any(::isKSerializer)) return
@@ -178,6 +197,10 @@ object KSerializerDescriptorResolver {
if (name == SerialEntityNames.SERIALIZER_PROVIDER_NAME && result.none { it.valueParameters.size == classDescriptor.declaredTypeParameters.size }) { if (name == SerialEntityNames.SERIALIZER_PROVIDER_NAME && result.none { it.valueParameters.size == classDescriptor.declaredTypeParameters.size }) {
result.add(createSerializerGetterDescriptor(thisDescriptor, classDescriptor)) result.add(createSerializerGetterDescriptor(thisDescriptor, classDescriptor))
} }
if (thisDescriptor.needSerializerFactory() && name == SerialEntityNames.SERIALIZER_PROVIDER_NAME && result.none { it.valueParameters.size == 1 && it.valueParameters.first().isVararg }) {
result.add(createSerializerFactoryVarargDescriptor(thisDescriptor))
}
} }
fun generateSerializerMethods( fun generateSerializerMethods(
@@ -408,7 +431,55 @@ object KSerializerDescriptorResolver {
return typeArgs to args return typeArgs to args
} }
private fun createSerializerGetterDescriptor(thisClass: ClassDescriptor, serializableClass: ClassDescriptor): SimpleFunctionDescriptor { private fun createSerializerFactoryVarargDescriptor(thisClass: ClassDescriptor): SimpleFunctionDescriptor {
val f = SimpleFunctionDescriptorImpl.create(
thisClass,
Annotations.EMPTY,
SerialEntityNames.SERIALIZER_PROVIDER_NAME,
CallableMemberDescriptor.Kind.SYNTHESIZED,
thisClass.source
)
val serializerClass = thisClass.getClassFromSerializationPackage(SerialEntityNames.KSERIALIZER_CLASS)
val kSerializerStarType =
KotlinTypeFactory.simpleNotNullType(
Annotations.EMPTY,
serializerClass,
listOf(StarProjectionImpl(serializerClass.typeConstructor.parameters.first()))
)
val varargType = thisClass.builtIns.getArrayType(Variance.OUT_VARIANCE, kSerializerStarType)
val vararg = ValueParameterDescriptorImpl(
containingDeclaration = f,
original = null,
index = 0,
annotations = Annotations.EMPTY,
name = Name.identifier("typeParamsSerializers"),
outType = varargType,
declaresDefaultValue = false,
isCrossinline = false,
isNoinline = false,
varargElementType = serializerClass.defaultType,
source = f.source
)
f.initialize(
null,
thisClass.thisAsReceiverParameter,
listOf(),
listOf(vararg),
kSerializerStarType,
Modality.FINAL,
Visibilities.PUBLIC
)
return f
}
private fun createSerializerGetterDescriptor(
thisClass: ClassDescriptor,
serializableClass: ClassDescriptor
): SimpleFunctionDescriptor {
val f = SimpleFunctionDescriptorImpl.create( val f = SimpleFunctionDescriptorImpl.create(
thisClass, thisClass,
Annotations.EMPTY, Annotations.EMPTY,