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:
+6
@@ -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>()
|
||||||
}
|
}
|
||||||
-3
@@ -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,
|
||||||
|
|||||||
+46
-9
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+1
@@ -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(
|
||||||
|
|||||||
+80
-9
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user