Remove auto-applying ContextSerializer
This commit is contained in:
committed by
Leonid Startsev
parent
0cfce8bd99
commit
82fa152514
+28
-7
@@ -16,13 +16,19 @@
|
||||
|
||||
package org.jetbrains.kotlinx.serialization.compiler.backend.common
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.codegen.CompilationException
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
||||
import org.jetbrains.kotlin.js.descriptorUtils.nameIfStandardType
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.KtAnonymousInitializer
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -30,7 +36,6 @@ import org.jetbrains.kotlin.types.typeUtil.containsTypeProjectionsInTopLevelArgu
|
||||
import org.jetbrains.kotlin.types.typeUtil.isBoolean
|
||||
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
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
|
||||
@@ -69,15 +74,31 @@ fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
|
||||
SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer)
|
||||
}
|
||||
else -> {
|
||||
val serializer = findTypeSerializerOrContext(property.module, property.type)
|
||||
val serializer =
|
||||
findTypeSerializerOrContext(property.module, property.type, property.descriptor.annotations, property.descriptor.findPsi())
|
||||
SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun findTypeSerializerOrContext(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? {
|
||||
return findTypeSerializer(module, kType)
|
||||
?: module.findClassAcrossModuleDependencies(contextSerializerId)
|
||||
fun findTypeSerializerOrContext(
|
||||
module: ModuleDescriptor,
|
||||
kType: KotlinType,
|
||||
annotations: Annotations = kType.annotations,
|
||||
sourceElement: PsiElement? = null
|
||||
): ClassDescriptor? {
|
||||
if (kType.isTypeParameter()) return null
|
||||
fun getContextualSerializer() =
|
||||
if (annotations.hasAnnotation(SerializationAnnotations.contextualFqName))
|
||||
module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer)
|
||||
else
|
||||
throw CompilationException(
|
||||
"Serializer for element of type $kType has not been found.\n" +
|
||||
"To use context serializer as fallback, explicitly annotate element with @ContextualSerializer",
|
||||
null,
|
||||
sourceElement
|
||||
)
|
||||
return findTypeSerializer(module, kType) ?: getContextualSerializer()
|
||||
}
|
||||
|
||||
fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? {
|
||||
|
||||
+2
-5
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.expressions.mapValueParametersIndexed
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
@@ -140,7 +141,7 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
||||
var args = if (serializerClass.classId == enumSerializerId || serializerClass.classId == contextSerializerId)
|
||||
TODO("enum and context serializer")
|
||||
else kType.arguments.map {
|
||||
val argSer = findTypeSerializerOrContext(module, it.type)
|
||||
val argSer = findTypeSerializerOrContext(module, it.type, sourceElement = serializerClass.findPsi())
|
||||
val expr = serializerInstance(argSer, module, it.type, it.type.genericIndex) ?: return null
|
||||
// todo: smth better than constructors[0] ??
|
||||
if (it.type.isMarkedNullable) irInvoke(null, nullableSerClass.constructors.toList()[0], expr) else expr
|
||||
@@ -208,8 +209,6 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
||||
writeFunc,
|
||||
irGet(localSerialDesc),
|
||||
irInt(index),
|
||||
// todo: direct field access?
|
||||
// irInvoke(irGet(serialObjectSymbol), compilerContext.symbolTable.referenceFunction(property.descriptor.getter!!))
|
||||
irGetField(irGet(serialObjectSymbol), property.irField)
|
||||
)
|
||||
} else {
|
||||
@@ -220,8 +219,6 @@ class SerializerIrGenerator(val irClass: IrClass, override val compilerContext:
|
||||
irGet(localSerialDesc),
|
||||
irInt(index),
|
||||
innerSerial,
|
||||
// todo: direct field access?
|
||||
// irInvoke(irGet(serialObjectSymbol), compilerContext.symbolTable.referenceFunction(property.descriptor.getter!!))
|
||||
irGetField(irGet(serialObjectSymbol), property.irField)
|
||||
)
|
||||
}
|
||||
|
||||
+2
-1
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor
|
||||
@@ -186,7 +187,7 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
||||
var args = if (serializerClass.classId == enumSerializerId || serializerClass.classId == contextSerializerId)
|
||||
listOf(createGetKClassExpression(kType.toClassDescriptor!!))
|
||||
else kType.arguments.map {
|
||||
val argSer = findTypeSerializerOrContext(module, it.type)
|
||||
val argSer = findTypeSerializerOrContext(module, it.type, sourceElement = serializerClass.findPsi())
|
||||
val expr = serializerInstance(argSer, module, it.type, it.type.genericIndex) ?: return null
|
||||
if (it.type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr
|
||||
}
|
||||
|
||||
+53
-48
@@ -19,6 +19,7 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -27,8 +28,9 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerialTypeInfo
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.DECODER_CLASS
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENCODER_CLASS
|
||||
@@ -141,16 +143,29 @@ internal val referenceArraySerializerId = ClassId(internalPackageFqName, Name.id
|
||||
internal val contextSerializerId = ClassId(packageFqName, Name.identifier(SpecialBuiltins.contextSerializer))
|
||||
|
||||
|
||||
internal fun InstructionAdapter.stackValueSerializerInstanceFromClass(codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo, varIndexStart: Int): Boolean {
|
||||
val serializer = sti.serializer ?: return false
|
||||
return stackValueSerializerInstance(codegen, sti.property.module, sti.property.type, serializer, this, sti.property.genericIndex) { idx ->
|
||||
internal fun InstructionAdapter.stackValueSerializerInstanceFromClass(
|
||||
codegen: ClassBodyCodegen,
|
||||
sti: JVMSerialTypeInfo,
|
||||
varIndexStart: Int
|
||||
): Boolean {
|
||||
val serializer = sti.serializer
|
||||
return stackValueSerializerInstance(
|
||||
codegen,
|
||||
sti.property.module,
|
||||
sti.property.type,
|
||||
serializer,
|
||||
this,
|
||||
sti.property.genericIndex
|
||||
) { idx ->
|
||||
load(varIndexStart + idx, kSerializerType)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo): Boolean {
|
||||
val serializer = sti.serializer ?: return false
|
||||
return stackValueSerializerInstance(codegen, sti.property.module, sti.property.type, serializer, this, sti.property.genericIndex) { idx ->
|
||||
return stackValueSerializerInstance(
|
||||
codegen, sti.property.module, sti.property.type,
|
||||
sti.serializer, this, sti.property.genericIndex
|
||||
) { idx ->
|
||||
load(0, kSerializerType)
|
||||
getfield(codegen.typeMapper.mapClass(codegen.descriptor).internalName, "$typeArgPrefix$idx", kSerializerType.descriptor)
|
||||
}
|
||||
@@ -165,7 +180,7 @@ internal fun stackValueSerializerInstance(codegen: ClassBodyCodegen, module: Mod
|
||||
iv?.run { genericSerializerFieldGetter?.invoke(this, genericIndex) }
|
||||
return true
|
||||
}
|
||||
val serializer = requireNotNull(maybeSerializer)
|
||||
val serializer = maybeSerializer ?: return false
|
||||
if (serializer.kind == ClassKind.OBJECT) {
|
||||
// singleton serializer -- just get it
|
||||
if (iv != null)
|
||||
@@ -176,9 +191,21 @@ internal fun stackValueSerializerInstance(codegen: ClassBodyCodegen, module: Mod
|
||||
val argSerializers = kType.arguments.map { projection ->
|
||||
// bail out from stackValueSerializerInstance if any type argument is not serializable
|
||||
val argType = projection.type
|
||||
val argSerializer = findTypeSerializerOrContext(module, argType, codegen.typeMapper.mapType(argType)) ?: return false
|
||||
val argSerializer = if (argType.isTypeParameter()) null else {
|
||||
findTypeSerializerOrContext(module, argType, sourceElement = codegen.descriptor.findPsi())
|
||||
?: return false
|
||||
}
|
||||
// check if it can be properly serialized with its args recursively
|
||||
if (!stackValueSerializerInstance(codegen, module, argType, argSerializer, null, argType.genericIndex, genericSerializerFieldGetter))
|
||||
if (!stackValueSerializerInstance(
|
||||
codegen,
|
||||
module,
|
||||
argType,
|
||||
argSerializer,
|
||||
null,
|
||||
argType.genericIndex,
|
||||
genericSerializerFieldGetter
|
||||
)
|
||||
)
|
||||
return false
|
||||
Pair(argType, argSerializer)
|
||||
}
|
||||
@@ -228,14 +255,20 @@ internal fun stackValueSerializerInstance(codegen: ClassBodyCodegen, module: Mod
|
||||
|
||||
|
||||
class JVMSerialTypeInfo(
|
||||
property: SerializableProperty,
|
||||
val type: Type,
|
||||
nn: String,
|
||||
serializer: ClassDescriptor? = null,
|
||||
unit: Boolean = false
|
||||
property: SerializableProperty,
|
||||
val type: Type,
|
||||
nn: String,
|
||||
serializer: ClassDescriptor? = null,
|
||||
unit: Boolean = false
|
||||
) : SerialTypeInfo(property, nn, serializer, unit)
|
||||
|
||||
fun getSerialTypeInfo(property: SerializableProperty, type: Type): JVMSerialTypeInfo {
|
||||
if (property.type.isTypeParameter()) return JVMSerialTypeInfo(
|
||||
property,
|
||||
Type.getType("Ljava/lang/Object;"),
|
||||
if (property.type.isMarkedNullable) "Nullable" else "",
|
||||
null
|
||||
)
|
||||
when (type.sort) {
|
||||
BOOLEAN, BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, CHAR -> {
|
||||
val name = type.className
|
||||
@@ -266,43 +299,15 @@ fun getSerialTypeInfo(property: SerializableProperty, type: Type): JVMSerialType
|
||||
// todo: more efficient enum support here, but only for enums that don't define custom serializer
|
||||
// otherwise, it is a serializer for some other type
|
||||
val serializer = property.serializableWith?.toClassDescriptor
|
||||
?: findTypeSerializerOrContext(property.module, property.type, type)
|
||||
?: findTypeSerializerOrContext(
|
||||
property.module,
|
||||
property.type,
|
||||
property.descriptor.annotations,
|
||||
property.descriptor.findPsi()
|
||||
)
|
||||
return JVMSerialTypeInfo(property, Type.getType("Ljava/lang/Object;"),
|
||||
if (property.type.isMarkedNullable) "Nullable" else "", serializer)
|
||||
}
|
||||
else -> throw AssertionError("Unexpected sort for $type") // should not happen
|
||||
}
|
||||
}
|
||||
|
||||
fun findTypeSerializerOrContext(module: ModuleDescriptor, kType: KotlinType, asmType: Type): ClassDescriptor? {
|
||||
return findTypeSerializer(module, kType)
|
||||
?: findStandardAsmTypeSerializer(module, asmType) // otherwise see if there is a standard serializer
|
||||
?: module.findClassAcrossModuleDependencies(contextSerializerId)
|
||||
}
|
||||
|
||||
fun findStandardAsmTypeSerializer(module: ModuleDescriptor, asmType: Type): ClassDescriptor? {
|
||||
val name = asmType.standardSerializer ?: return null
|
||||
return module.findClassAcrossModuleDependencies(ClassId(internalPackageFqName, Name.identifier(name)))
|
||||
}
|
||||
|
||||
internal val org.jetbrains.org.objectweb.asm.Type.standardSerializer: String? get() = when (this.descriptor) {
|
||||
"Lkotlin/Unit;" -> "UnitSerializer"
|
||||
"Z", "Ljava/lang/Boolean;" -> "BooleanSerializer"
|
||||
"B", "Ljava/lang/Byte;" -> "ByteSerializer"
|
||||
"S", "Ljava/lang/Short;" -> "ShortSerializer"
|
||||
"I", "Ljava/lang/Integer;" -> "IntSerializer"
|
||||
"J", "Ljava/lang/Long;" -> "LongSerializer"
|
||||
"F", "Ljava/lang/Float;" -> "FloatSerializer"
|
||||
"D", "Ljava/lang/Double;" -> "DoubleSerializer"
|
||||
"C", "Ljava/lang/Character;" -> "CharSerializer"
|
||||
"Ljava/lang/String;" -> "StringSerializer"
|
||||
"Ljava/util/Collection;", "Ljava/util/List;", "Ljava/util/ArrayList;" -> "ArrayListSerializer"
|
||||
"Ljava/util/Set;", "Ljava/util/LinkedHashSet;" -> "LinkedHashSetSerializer"
|
||||
"Ljava/util/HashSet;" -> "HashSetSerializer"
|
||||
"Ljava/util/Map;", "Ljava/util/LinkedHashMap;" -> "LinkedHashMapSerializer"
|
||||
"Ljava/util/HashMap;" -> "HashMapSerializer"
|
||||
"Ljava/util/Map\$Entry;" -> "MapEntrySerializer"
|
||||
"Lkotlin/Pair;" -> "PairSerializer"
|
||||
"Lkotlin/Triple;" -> "TripleSerializer"
|
||||
else -> null
|
||||
}
|
||||
|
||||
+2
-5
@@ -28,10 +28,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.anonymousInitializers
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.bodyPropertiesDescriptorsMap
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.primaryPropertiesDescriptorsMap
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
@@ -85,7 +82,7 @@ class SerializableCodegenImpl(
|
||||
load(serialDescI, descType)
|
||||
superTypeArguments.forEach {
|
||||
val genericIdx = serializableDescriptor.defaultType.arguments.indexOf(it).let { if (it == -1) null else it }
|
||||
val serial = findTypeSerializerOrContext(serializableDescriptor.module, it.type, classCodegen.typeMapper.mapType(it.type))
|
||||
val serial = findTypeSerializerOrContext(serializableDescriptor.module, it.type)
|
||||
stackValueSerializerInstance(classCodegen, serializableDescriptor.module, it.type, serial, this, genericIdx) {
|
||||
load(offsetI + it, kSerializerType)
|
||||
}
|
||||
|
||||
+12
-8
@@ -32,7 +32,6 @@ import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.KSERIALIZER_CLASS
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages.packageFqName
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages.internalPackageFqName
|
||||
|
||||
|
||||
fun isKSerializer(type: KotlinType?): Boolean =
|
||||
@@ -176,14 +175,19 @@ fun ClassDescriptor.getKSerializerConstructorMarker(): ClassDescriptor =
|
||||
module.findClassAcrossModuleDependencies(ClassId(packageFqName, SerialEntityNames.SERIAL_CTOR_MARKER_NAME))!!
|
||||
|
||||
fun ModuleDescriptor.getClassFromInternalSerializationPackage(classSimpleName: String) =
|
||||
requireNotNull(
|
||||
findClassAcrossModuleDependencies(
|
||||
ClassId(
|
||||
internalPackageFqName,
|
||||
Name.identifier(classSimpleName)
|
||||
)
|
||||
getFromPackage(SerializationPackages.internalPackageFqName, classSimpleName)
|
||||
|
||||
fun ModuleDescriptor.getClassFromSerializationPackage(classSimpleName: String) =
|
||||
getFromPackage(SerializationPackages.packageFqName, classSimpleName)
|
||||
|
||||
private fun ModuleDescriptor.getFromPackage(packageFqName: FqName, classSimpleName: String) = requireNotNull(
|
||||
findClassAcrossModuleDependencies(
|
||||
ClassId(
|
||||
packageFqName,
|
||||
Name.identifier(classSimpleName)
|
||||
)
|
||||
) { "Can't locate class $classSimpleName" }
|
||||
)
|
||||
) { "Can't locate class $classSimpleName" }
|
||||
|
||||
fun ClassDescriptor.getClassFromSerializationPackage(classSimpleName: String) =
|
||||
requireNotNull(module.findClassAcrossModuleDependencies(ClassId(packageFqName, Name.identifier(classSimpleName)))) {"Can't locate class $classSimpleName"}
|
||||
|
||||
+2
@@ -20,6 +20,8 @@ object SerializationAnnotations {
|
||||
internal val serialOptionalFqName = FqName("kotlinx.serialization.Optional")
|
||||
internal val serialTransientFqName = FqName("kotlinx.serialization.Transient")
|
||||
internal val serialInfoFqName = FqName("kotlinx.serialization.SerialInfo")
|
||||
|
||||
internal val contextualFqName = FqName("kotlinx.serialization.ContextualSerialization")
|
||||
}
|
||||
|
||||
object SerialEntityNames {
|
||||
|
||||
Reference in New Issue
Block a user