Instantiating of Polymorphic in Companion.serializer() for JS and Native
This commit is contained in:
+20
-13
@@ -12,10 +12,7 @@ import org.jetbrains.kotlin.ir.util.TypeTranslator
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.classSerializer
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.shouldHaveGeneratedMethodsInCompanion
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
|
||||
class SerializableCompanionIrGenerator(
|
||||
val irClass: IrClass,
|
||||
@@ -43,15 +40,25 @@ class SerializableCompanionIrGenerator(
|
||||
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) =
|
||||
irClass.contributeFunction(methodDescriptor, fromStubs = true) { getter ->
|
||||
val serializer = serializableDescriptor.classSerializer!!
|
||||
val expr = if (serializer.kind == ClassKind.OBJECT) {
|
||||
irGetObject(serializer)
|
||||
} else {
|
||||
val desc = requireNotNull(
|
||||
KSerializerDescriptorResolver.findSerializerConstructorForTypeArgumentsSerializers(serializer)
|
||||
) { "Generated serializer does not have constructor with required number of arguments" }
|
||||
val ctor = compilerContext.externalSymbols.referenceConstructor(desc)
|
||||
val args: List<IrExpression> = getter.valueParameters.map { irGet(it) }
|
||||
irInvoke(null, ctor, *args.toTypedArray())
|
||||
val expr = when {
|
||||
serializer.kind == ClassKind.OBJECT -> irGetObject(serializer)
|
||||
serializer.isSerializerWhichRequiersKClass() -> {
|
||||
val serializableType = serializableDescriptor.defaultType
|
||||
irInvoke(
|
||||
null,
|
||||
compilerContext.externalSymbols.referenceConstructor(serializer.unsubstitutedPrimaryConstructor!!),
|
||||
listOf(serializableType.toIrType()),
|
||||
listOf(classReference(serializableType))
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
val desc = requireNotNull(
|
||||
KSerializerDescriptorResolver.findSerializerConstructorForTypeArgumentsSerializers(serializer)
|
||||
) { "Generated serializer does not have constructor with required number of arguments" }
|
||||
val ctor = compilerContext.externalSymbols.referenceConstructor(desc)
|
||||
val args: List<IrExpression> = getter.valueParameters.map { irGet(it) }
|
||||
irInvoke(null, ctor, *args.toTypedArray())
|
||||
}
|
||||
}
|
||||
+irReturn(expr)
|
||||
}
|
||||
|
||||
+1
-6
@@ -33,9 +33,6 @@ import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.bodyPropertiesDescriptorsMap
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.primaryPropertiesDescriptorsMap
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.polymorphicSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
|
||||
@@ -134,8 +131,6 @@ internal fun SerializerJsTranslator.serializerTower(property: SerializableProper
|
||||
?.let { expr -> if (property.type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr }
|
||||
}
|
||||
|
||||
private val classIdsWhichNeedKClass = setOf(enumSerializerId, contextSerializerId, polymorphicSerializerId)
|
||||
|
||||
internal fun SerializerJsTranslator.serializerInstance(
|
||||
serializerClass: ClassDescriptor?,
|
||||
module: ModuleDescriptor,
|
||||
@@ -151,7 +146,7 @@ internal fun SerializerJsTranslator.serializerInstance(
|
||||
if (serializerClass.kind == ClassKind.OBJECT) {
|
||||
return context.serializerObjectGetter(serializerClass)
|
||||
} else {
|
||||
var args = if (serializerClass.classId in classIdsWhichNeedKClass)
|
||||
var args = if (serializerClass.isSerializerWhichRequiersKClass())
|
||||
listOf(ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!))
|
||||
else kType.arguments.map {
|
||||
val argSer = findTypeSerializerOrContext(module, it.type, sourceElement = serializerClass.findPsi())
|
||||
|
||||
+17
-17
@@ -19,18 +19,13 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.js
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsInvocation
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNameRef
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsReturn
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor
|
||||
import org.jetbrains.kotlin.js.translate.expression.ExpressionVisitor
|
||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.classSerializer
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.shouldHaveGeneratedMethodsInCompanion
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
|
||||
class SerializableCompanionJsTranslator(
|
||||
declaration: ClassDescriptor,
|
||||
@@ -41,15 +36,20 @@ class SerializableCompanionJsTranslator(
|
||||
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
|
||||
val f = context.buildFunction(methodDescriptor) {jsFun, context ->
|
||||
val serializer = serializableDescriptor.classSerializer!!
|
||||
val stmt: JsExpression = if (serializer.kind == ClassKind.OBJECT) {
|
||||
context.serializerObjectGetter(serializer)
|
||||
} else {
|
||||
val args = jsFun.parameters.map { JsNameRef(it.name) }
|
||||
val ref = context.getInnerNameForDescriptor(
|
||||
requireNotNull(
|
||||
KSerializerDescriptorResolver.findSerializerConstructorForTypeArgumentsSerializers(serializer)
|
||||
) { "Generated serializer does not have constructor with required number of arguments" })
|
||||
JsInvocation(ref.makeRef(), args)
|
||||
val stmt: JsExpression = when {
|
||||
serializer.kind == ClassKind.OBJECT -> context.serializerObjectGetter(serializer)
|
||||
serializer.isSerializerWhichRequiersKClass() -> JsNew(
|
||||
context.translateQualifiedReference(serializer),
|
||||
listOf(ExpressionVisitor.getObjectKClass(context, serializableDescriptor))
|
||||
)
|
||||
else -> {
|
||||
val args = jsFun.parameters.map { JsNameRef(it.name) }
|
||||
val ref = context.getInnerNameForDescriptor(
|
||||
requireNotNull(
|
||||
KSerializerDescriptorResolver.findSerializerConstructorForTypeArgumentsSerializers(serializer)
|
||||
) { "Generated serializer does not have constructor with required number of arguments" })
|
||||
JsInvocation(ref.makeRef(), args)
|
||||
}
|
||||
}
|
||||
+JsReturn(stmt)
|
||||
}
|
||||
|
||||
+36
-29
@@ -25,17 +25,24 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.ValueArgument
|
||||
import org.jetbrains.kotlin.resolve.constants.KClassValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationDescriptor
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.polymorphicSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.KSERIALIZER_CLASS
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.serialInfoFqName
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages.packageFqName
|
||||
|
||||
fun isAllowedToHaveAutoGeneratedSerializerMethods(classDescriptor: ClassDescriptor, serializableClassDescriptor: ClassDescriptor): Boolean {
|
||||
internal fun isAllowedToHaveAutoGeneratedSerializerMethods(
|
||||
classDescriptor: ClassDescriptor,
|
||||
serializableClassDescriptor: ClassDescriptor
|
||||
): Boolean {
|
||||
// don't generate automatically anything for enums or interfaces or other strange things
|
||||
if (serializableClassDescriptor.kind != ClassKind.CLASS) return false
|
||||
// it is either GeneratedSerializer implementation
|
||||
@@ -44,17 +51,17 @@ fun isAllowedToHaveAutoGeneratedSerializerMethods(classDescriptor: ClassDescript
|
||||
(classDescriptor.typeConstructor.supertypes.any(::isKSerializer) && classDescriptor.declaredTypeParameters.isEmpty())
|
||||
}
|
||||
|
||||
fun isKSerializer(type: KotlinType?): Boolean =
|
||||
internal fun isKSerializer(type: KotlinType?): Boolean =
|
||||
type != null && KotlinBuiltIns.isConstructedFromGivenClass(type, SerialEntityNames.KSERIALIZER_NAME_FQ)
|
||||
|
||||
fun isGeneratedKSerializer(type: KotlinType?): Boolean =
|
||||
internal fun isGeneratedKSerializer(type: KotlinType?): Boolean =
|
||||
type != null && KotlinBuiltIns.isConstructedFromGivenClass(type, SerialEntityNames.GENERATED_SERIALIZER_FQ)
|
||||
|
||||
fun ClassDescriptor.getGeneratedSerializerDescriptor(): ClassDescriptor =
|
||||
internal fun ClassDescriptor.getGeneratedSerializerDescriptor(): ClassDescriptor =
|
||||
module.getClassFromInternalSerializationPackage(SerialEntityNames.GENERATED_SERIALIZER_CLASS.identifier)
|
||||
|
||||
|
||||
fun ClassDescriptor.createSerializerTypeFor(argument: SimpleType, baseSerializerInterface: FqName): SimpleType {
|
||||
internal fun ClassDescriptor.createSerializerTypeFor(argument: SimpleType, baseSerializerInterface: FqName): SimpleType {
|
||||
val projectionType = Variance.INVARIANT
|
||||
val types = listOf(TypeProjectionImpl(projectionType, argument))
|
||||
val descriptor = module.findClassAcrossModuleDependencies(ClassId.topLevel(baseSerializerInterface))
|
||||
@@ -79,16 +86,13 @@ internal val DeclarationDescriptor.serializerForClass: KotlinType?
|
||||
internal val ClassDescriptor.isSerialInfoAnnotation: Boolean
|
||||
get() = annotations.hasAnnotation(serialInfoFqName)
|
||||
|
||||
val Annotations.serialNameValue: String?
|
||||
get() {
|
||||
val value = findAnnotationConstantValue<String?>(SerializationAnnotations.serialNameAnnotationFqName, "value")
|
||||
return value
|
||||
}
|
||||
internal val Annotations.serialNameValue: String?
|
||||
get() = findAnnotationConstantValue(SerializationAnnotations.serialNameAnnotationFqName, "value")
|
||||
|
||||
val Annotations.serialRequired: Boolean
|
||||
internal val Annotations.serialRequired: Boolean
|
||||
get() = hasAnnotation(SerializationAnnotations.requiredAnnotationFqName)
|
||||
|
||||
val Annotations.serialTransient: Boolean
|
||||
internal val Annotations.serialTransient: Boolean
|
||||
get() = hasAnnotation(SerializationAnnotations.serialTransientFqName)
|
||||
|
||||
// ----------------------------------------
|
||||
@@ -100,7 +104,7 @@ val KotlinType?.toClassDescriptor: ClassDescriptor?
|
||||
internal val ClassDescriptor.shouldHaveGeneratedMethodsInCompanion: Boolean
|
||||
get() = this.kind == ClassKind.CLASS && annotations.hasAnnotation(SerializationAnnotations.serializableAnnotationFqName)
|
||||
|
||||
val ClassDescriptor.isInternalSerializable: Boolean //todo normal checking
|
||||
internal val ClassDescriptor.isInternalSerializable: Boolean //todo normal checking
|
||||
get() {
|
||||
if (kind != ClassKind.CLASS) return false
|
||||
return hasSerializableAnnotationWithoutArgs
|
||||
@@ -151,6 +155,8 @@ internal val ClassDescriptor?.classSerializer: ClassDescriptor?
|
||||
internal val ClassDescriptor.hasCompanionObjectAsSerializer: Boolean
|
||||
get() = companionObjectDescriptor?.serializerForClass == this.defaultType
|
||||
|
||||
internal fun ClassDescriptor.isSerializerWhichRequiersKClass() = classId in setOf(enumSerializerId, contextSerializerId, polymorphicSerializerId)
|
||||
|
||||
internal fun checkSerializerNullability(classType: KotlinType, serializerType: KotlinType): KotlinType {
|
||||
val castedToKSerial = requireNotNull(
|
||||
serializerType.supertypes().find { isKSerializer(it) },
|
||||
@@ -162,7 +168,7 @@ internal fun checkSerializerNullability(classType: KotlinType, serializerType: K
|
||||
}
|
||||
|
||||
// returns only user-overriden Serializer
|
||||
val KotlinType.overridenSerializer: KotlinType?
|
||||
internal val KotlinType.overridenSerializer: KotlinType?
|
||||
get() {
|
||||
val desc = this.toClassDescriptor ?: return null
|
||||
(desc.serializableWith)?.let { return checkSerializerNullability(this, it) }
|
||||
@@ -171,17 +177,17 @@ val KotlinType.overridenSerializer: KotlinType?
|
||||
return null
|
||||
}
|
||||
|
||||
val KotlinType.genericIndex: Int?
|
||||
internal val KotlinType.genericIndex: Int?
|
||||
get() = (this.constructor.declarationDescriptor as? TypeParameterDescriptor)?.index
|
||||
|
||||
fun getSerializableClassDescriptorByCompanion(thisDescriptor: ClassDescriptor): ClassDescriptor? {
|
||||
internal fun getSerializableClassDescriptorByCompanion(thisDescriptor: ClassDescriptor): ClassDescriptor? {
|
||||
if (!thisDescriptor.isCompanionObject) return null
|
||||
val classDescriptor = (thisDescriptor.containingDeclaration as? ClassDescriptor) ?: return null
|
||||
if (!classDescriptor.shouldHaveGeneratedMethodsInCompanion) return null
|
||||
return classDescriptor
|
||||
}
|
||||
|
||||
fun getSerializableClassDescriptorBySerializer(serializerDescriptor: ClassDescriptor): ClassDescriptor? {
|
||||
internal fun getSerializableClassDescriptorBySerializer(serializerDescriptor: ClassDescriptor): ClassDescriptor? {
|
||||
val serializerForClass = serializerDescriptor.serializerForClass
|
||||
if (serializerForClass != null) return serializerForClass.toClassDescriptor
|
||||
if (serializerDescriptor.name !in setOf(
|
||||
@@ -194,21 +200,22 @@ fun getSerializableClassDescriptorBySerializer(serializerDescriptor: ClassDescri
|
||||
return classDescriptor
|
||||
}
|
||||
|
||||
fun ClassDescriptor.checkSerializableClassPropertyResult(prop: PropertyDescriptor): Boolean =
|
||||
internal fun ClassDescriptor.checkSerializableClassPropertyResult(prop: PropertyDescriptor): Boolean =
|
||||
prop.returnType!!.isSubtypeOf(getClassFromSerializationPackage(SerialEntityNames.SERIAL_DESCRIPTOR_CLASS).toSimpleType(false)) // todo: cache lookup
|
||||
|
||||
// todo: serialization: do an actual check better that just number of parameters
|
||||
fun ClassDescriptor.checkSaveMethodParameters(parameters: List<ValueParameterDescriptor>): Boolean =
|
||||
internal fun ClassDescriptor.checkSaveMethodParameters(parameters: List<ValueParameterDescriptor>): Boolean =
|
||||
parameters.size == 2
|
||||
|
||||
fun ClassDescriptor.checkSaveMethodResult(type: KotlinType): Boolean =
|
||||
internal fun ClassDescriptor.checkSaveMethodResult(type: KotlinType): Boolean =
|
||||
KotlinBuiltIns.isUnit(type)
|
||||
|
||||
// todo: serialization: do an actual check better that just number of parameters
|
||||
fun ClassDescriptor.checkLoadMethodParameters(parameters: List<ValueParameterDescriptor>): Boolean =
|
||||
internal fun ClassDescriptor.checkLoadMethodParameters(parameters: List<ValueParameterDescriptor>): Boolean =
|
||||
parameters.size == 1
|
||||
|
||||
fun ClassDescriptor.checkLoadMethodResult(type: KotlinType): Boolean = getSerializableClassDescriptorBySerializer(this)?.defaultType == type
|
||||
internal fun ClassDescriptor.checkLoadMethodResult(type: KotlinType): Boolean =
|
||||
getSerializableClassDescriptorBySerializer(this)?.defaultType == type
|
||||
|
||||
// ----------------
|
||||
|
||||
@@ -217,7 +224,7 @@ inline fun <reified R> Annotations.findAnnotationConstantValue(annotationFqName:
|
||||
annotation.allValueArguments.entries.singleOrNull { it.key.asString() == property }?.value?.value
|
||||
} as? R
|
||||
|
||||
fun Annotations.findAnnotationKotlinTypeValue(
|
||||
internal fun Annotations.findAnnotationKotlinTypeValue(
|
||||
annotationFqName: FqName,
|
||||
moduleForResolve: ModuleDescriptor,
|
||||
property: String
|
||||
@@ -229,13 +236,13 @@ fun Annotations.findAnnotationKotlinTypeValue(
|
||||
|
||||
// Search utils
|
||||
|
||||
fun ClassDescriptor.getKSerializerConstructorMarker(): ClassDescriptor =
|
||||
internal fun ClassDescriptor.getKSerializerConstructorMarker(): ClassDescriptor =
|
||||
module.findClassAcrossModuleDependencies(ClassId(packageFqName, SerialEntityNames.SERIAL_CTOR_MARKER_NAME))!!
|
||||
|
||||
fun ModuleDescriptor.getClassFromInternalSerializationPackage(classSimpleName: String) =
|
||||
internal fun ModuleDescriptor.getClassFromInternalSerializationPackage(classSimpleName: String) =
|
||||
getFromPackage(SerializationPackages.internalPackageFqName, classSimpleName)
|
||||
|
||||
fun ModuleDescriptor.getClassFromSerializationPackage(classSimpleName: String) =
|
||||
internal fun ModuleDescriptor.getClassFromSerializationPackage(classSimpleName: String) =
|
||||
getFromPackage(SerializationPackages.packageFqName, classSimpleName)
|
||||
|
||||
private fun ModuleDescriptor.getFromPackage(packageFqName: FqName, classSimpleName: String) = requireNotNull(
|
||||
@@ -247,15 +254,15 @@ private fun ModuleDescriptor.getFromPackage(packageFqName: FqName, classSimpleNa
|
||||
)
|
||||
) { "Can't locate class $classSimpleName from package $packageFqName" }
|
||||
|
||||
fun ClassDescriptor.getClassFromSerializationPackage(classSimpleName: String) =
|
||||
internal fun ClassDescriptor.getClassFromSerializationPackage(classSimpleName: String) =
|
||||
requireNotNull(module.findClassAcrossModuleDependencies(ClassId(packageFqName, Name.identifier(classSimpleName)))) {"Can't locate class $classSimpleName"}
|
||||
|
||||
fun ClassDescriptor.getClassFromInternalSerializationPackage(classSimpleName: String) =
|
||||
internal fun ClassDescriptor.getClassFromInternalSerializationPackage(classSimpleName: String) =
|
||||
module.getClassFromInternalSerializationPackage(classSimpleName)
|
||||
|
||||
fun ClassDescriptor.toSimpleType(nullable: Boolean = true) = KotlinTypeFactory.simpleType(Annotations.EMPTY, this.typeConstructor, emptyList(), nullable)
|
||||
|
||||
fun Annotated.annotationsWithArguments(): List<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> =
|
||||
internal fun Annotated.annotationsWithArguments(): List<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> =
|
||||
annotations.asSequence()
|
||||
.filter { it.type.toClassDescriptor?.isSerialInfoAnnotation == true }
|
||||
.filterIsInstance<LazyAnnotationDescriptor>()
|
||||
|
||||
Reference in New Issue
Block a user