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