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.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.constants.KClassValue
import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgument
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.typeUtil.supertypes
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
@@ -48,4 +51,7 @@ abstract class AbstractSerialGenerator(val bindingContext: BindingContext, val c
{ 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)
}
protected fun ClassDescriptor.getFuncDesc(funcName: String): Sequence<FunctionDescriptor> =
unsubstitutedMemberScope.getDescriptorsFiltered { it == Name.identifier(funcName) }.asSequence().filterIsInstance<FunctionDescriptor>()
companion object {
fun getSyntheticLoadMember(serializerDescriptor: ClassDescriptor): FunctionDescriptor? = getMemberToGenerate(
serializerDescriptor, SerialEntityNames.LOAD,
@@ -1,24 +1,26 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
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.declarations.IrClass
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.TypeTranslator
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
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.referenceFunction
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
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.types.Variance
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
@@ -77,7 +79,7 @@ class SerializableCompanionIrGenerator(
irSerializableClass.annotations.add(annotationCtorCall)
}
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) =
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
irClass.contributeFunction(methodDescriptor) { getter ->
val serializer = requireNotNull(
findTypeSerializer(
@@ -94,5 +96,40 @@ class SerializableCompanionIrGenerator(
patchSerializableClassWithMarkerAnnotation(serializer)
+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>) {
KSerializerDescriptorResolver.addSerialInfoSuperType(thisDescriptor, supertypes)
KSerializerDescriptorResolver.addSerializerSupertypes(thisDescriptor, supertypes)
KSerializerDescriptorResolver.addSerializerFactorySuperType(thisDescriptor, supertypes)
}
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.FqName
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.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
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.declarations.ClassMemberDeclarationProvider
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.KotlinTypeFactory
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.createProjection
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SimpleSyntheticPropertyDescriptor
@@ -50,14 +52,17 @@ import java.util.*
object KSerializerDescriptorResolver {
private fun createDeprecatedHiddenAnnotation(module: ModuleDescriptor): AnnotationDescriptor {
return module.builtIns.createDeprecatedAnnotation("This synthesized declaration should not be used directly", level = "HIDDEN")
fun createDeprecatedHiddenAnnotation(module: ModuleDescriptor): AnnotationDescriptor {
return module.builtIns.createDeprecatedAnnotation(
"This synthesized declaration should not be used directly",
level = "HIDDEN"
)
}
fun isSerialInfoImpl(thisDescriptor: ClassDescriptor): Boolean {
return thisDescriptor.name == IMPL_NAME
&& thisDescriptor.containingDeclaration is LazyClassDescriptor
&& thisDescriptor.containingDeclaration.annotations.hasAnnotation(serialInfoFqName)
&& thisDescriptor.containingDeclaration is LazyClassDescriptor
&& thisDescriptor.containingDeclaration.annotations.hasAnnotation(serialInfoFqName)
}
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>) {
val serializableClassDescriptor = getSerializableClassDescriptorBySerializer(classDescriptor) ?: 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 }) {
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(
@@ -408,7 +431,55 @@ object KSerializerDescriptorResolver {
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(
thisClass,
Annotations.EMPTY,