Semantic change:
Now properties with default values are @Optional by default, and properties without backing fields are @Transient by default.
This commit is contained in:
+24
-28
@@ -18,7 +18,6 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
|
||||
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||
@@ -36,8 +35,7 @@ import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
class SerializableCodegenImpl(
|
||||
private val classCodegen: ImplementationBodyCodegen,
|
||||
serializableClass: ClassDescriptor
|
||||
private val classCodegen: ImplementationBodyCodegen
|
||||
) : SerializableCodegen(classCodegen.descriptor, classCodegen.bindingContext) {
|
||||
|
||||
private val thisAsmType = classCodegen.typeMapper.mapClass(serializableDescriptor)
|
||||
@@ -46,7 +44,7 @@ class SerializableCodegenImpl(
|
||||
fun generateSerializableExtensions(codegen: ImplementationBodyCodegen) {
|
||||
val serializableClass = codegen.descriptor
|
||||
if (serializableClass.isInternalSerializable)
|
||||
SerializableCodegenImpl(codegen, serializableClass).generate()
|
||||
SerializableCodegenImpl(codegen).generate()
|
||||
else if (serializableClass.hasSerializableAnnotationWithoutArgs && !serializableClass.hasCompanionObjectAsSerializer) {
|
||||
throw CompilationException(
|
||||
"@Serializable annotation on $serializableClass would be ignored because it is impossible to serialize it automatically. " +
|
||||
@@ -96,7 +94,8 @@ class SerializableCodegenImpl(
|
||||
val myPropsStart: Int
|
||||
if (superClass.isInternalSerializable) {
|
||||
myPropsStart = SerializableProperties(superClass, classCodegen.bindingContext).serializableProperties.size
|
||||
val superTypeArguments = serializableDescriptor.typeConstructor.supertypes.single { it.toClassDescriptor?.isInternalSerializable == true }.arguments
|
||||
val superTypeArguments =
|
||||
serializableDescriptor.typeConstructor.supertypes.single { it.toClassDescriptor?.isInternalSerializable == true }.arguments
|
||||
//super.writeSelf(output, serialDesc)
|
||||
load(thisI, thisAsmType)
|
||||
load(outputI, kOutputType)
|
||||
@@ -108,10 +107,15 @@ class SerializableCodegenImpl(
|
||||
load(offsetI + it, kSerializerType)
|
||||
}
|
||||
}
|
||||
val superSignature = classCodegen.typeMapper.mapSignatureSkipGeneric(KSerializerDescriptorResolver.createWriteSelfFunctionDescriptor(superClass))
|
||||
invokespecial(classCodegen.typeMapper.mapType(superClass).internalName, superSignature.asmMethod.name, superSignature.asmMethod.descriptor, false)
|
||||
}
|
||||
else {
|
||||
val superSignature =
|
||||
classCodegen.typeMapper.mapSignatureSkipGeneric(KSerializerDescriptorResolver.createWriteSelfFunctionDescriptor(superClass))
|
||||
invokespecial(
|
||||
classCodegen.typeMapper.mapType(superClass).internalName,
|
||||
superSignature.asmMethod.name,
|
||||
superSignature.asmMethod.descriptor,
|
||||
false
|
||||
)
|
||||
} else {
|
||||
myPropsStart = 0
|
||||
}
|
||||
|
||||
@@ -174,16 +178,9 @@ class SerializableCodegenImpl(
|
||||
|
||||
private fun InstructionAdapter.doGenerateConstructorImpl(exprCodegen: ExpressionCodegen) {
|
||||
val seenMask = 1
|
||||
// var propOffset = 2
|
||||
var (propIndex, propOffset) = generateSuperSerializableCall(2)
|
||||
for (i in propIndex until properties.serializableProperties.size) {
|
||||
val prop = properties[i]
|
||||
if (prop.transient) {
|
||||
if (!needInitProperty(prop)) throw CompilationException("transient without default value", null, null)
|
||||
exprCodegen.genInitProperty(prop)
|
||||
propOffset += prop.asmType.size
|
||||
continue
|
||||
}
|
||||
val propType = prop.asmType
|
||||
if (!prop.optional) {
|
||||
// primary were validated before constructor call
|
||||
@@ -196,8 +193,7 @@ class SerializableCodegenImpl(
|
||||
load(0, thisAsmType)
|
||||
load(propOffset, propType)
|
||||
putfield(thisAsmType.internalName, prop.descriptor.name.asString(), propType.descriptor)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
genValidateProperty(i) { seenMask }
|
||||
val setLbl = Label()
|
||||
val nextLabel = Label()
|
||||
@@ -211,7 +207,11 @@ class SerializableCodegenImpl(
|
||||
visitLabel(setLbl)
|
||||
// setting defaultValue
|
||||
if (classCodegen.bindingContext[BindingContext.BACKING_FIELD_REQUIRED, prop.descriptor] != true)
|
||||
throw CompilationException("Optional properties without backing fields doesn't have much sense, maybe you want transient?", null, getProp(prop))
|
||||
throw CompilationException(
|
||||
"Optional properties without backing fields doesn't have much sense, maybe you want transient?",
|
||||
null,
|
||||
getProp(prop)
|
||||
)
|
||||
exprCodegen.genInitProperty(prop)
|
||||
visitLabel(nextLabel)
|
||||
}
|
||||
@@ -222,15 +222,15 @@ class SerializableCodegenImpl(
|
||||
val serializedProps = properties.serializableProperties.map { it.descriptor }
|
||||
|
||||
(descToProps - serializedProps)
|
||||
.filter { classCodegen.shouldInitializeProperty(it.value) }
|
||||
.forEach { (_, prop) -> classCodegen.initializeProperty(exprCodegen, prop) }
|
||||
.filter { classCodegen.shouldInitializeProperty(it.value) }
|
||||
.forEach { (_, prop) -> classCodegen.initializeProperty(exprCodegen, prop) }
|
||||
(paramsToProps - serializedProps)
|
||||
.forEach { (t, u) -> exprCodegen.genInitParam(t, u) }
|
||||
.forEach { (t, u) -> exprCodegen.genInitParam(t, u) }
|
||||
|
||||
// init blocks
|
||||
// todo: proper order with other initializers
|
||||
classCodegen.myClass.anonymousInitializers()
|
||||
.forEach { exprCodegen.gen(it, Type.VOID_TYPE) }
|
||||
.forEach { exprCodegen.gen(it, Type.VOID_TYPE) }
|
||||
areturn(Type.VOID_TYPE)
|
||||
}
|
||||
|
||||
@@ -255,8 +255,7 @@ class SerializableCodegenImpl(
|
||||
}
|
||||
invokespecial(superType, "<init>", desc, false)
|
||||
return 0 to propStartVar
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val superProps = SerializableProperties(superClass, classCodegen.bindingContext).serializableProperties
|
||||
val creator = buildInternalConstructorDesc(propStartVar, 1, classCodegen, superProps)
|
||||
invokespecial(superType, "<init>", creator, false)
|
||||
@@ -264,9 +263,6 @@ class SerializableCodegenImpl(
|
||||
}
|
||||
}
|
||||
|
||||
private fun needInitProperty(prop: SerializableProperty) = getProp(prop)?.let { classCodegen.shouldInitializeProperty(it) }
|
||||
?: getParam(prop)?.hasDefaultValue() ?: throw IllegalStateException()
|
||||
|
||||
private fun ExpressionCodegen.genInitProperty(prop: SerializableProperty) = getProp(prop)?.let {
|
||||
classCodegen.initializeProperty(this, it)
|
||||
}
|
||||
|
||||
+3
-2
@@ -19,6 +19,7 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.hasBackingField
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
|
||||
class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) {
|
||||
@@ -40,7 +41,8 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
|
||||
.filterIsInstance<PropertyDescriptor>()
|
||||
.filter { it.kind == CallableMemberDescriptor.Kind.DECLARATION }
|
||||
.filter(this::isPropSerializable)
|
||||
.map { prop -> SerializableProperty(prop, primaryConstructorProperties[prop] ?: false) }
|
||||
.map { prop -> SerializableProperty(prop, primaryConstructorProperties[prop] ?: false, prop.hasBackingField(bindingContext)) }
|
||||
.filterNot { it.transient }
|
||||
.partition { primaryConstructorProperties.contains(it.descriptor) }
|
||||
.run {
|
||||
val supers = serializableClass.getSuperClassNotAny()
|
||||
@@ -66,7 +68,6 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
|
||||
serializableProperties.minus(serializableConstructorProperties)
|
||||
|
||||
val size = serializableProperties.size
|
||||
val indices = serializableProperties.indices
|
||||
operator fun get(index: Int) = serializableProperties[index]
|
||||
operator fun iterator() = serializableProperties.iterator()
|
||||
|
||||
|
||||
+17
-3
@@ -20,18 +20,25 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationWithInitializer
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.psi.ValueArgument
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class SerializableProperty(val descriptor: PropertyDescriptor, val isConstructorParameterWithDefault: Boolean) {
|
||||
class SerializableProperty(
|
||||
val descriptor: PropertyDescriptor,
|
||||
val isConstructorParameterWithDefault: Boolean,
|
||||
hasBackingField: Boolean
|
||||
) {
|
||||
val name = descriptor.annotations.serialNameValue ?: descriptor.name.asString()
|
||||
val type = descriptor.type
|
||||
val genericIndex = type.genericIndex
|
||||
val module = descriptor.module
|
||||
val serializableWith = extractSerializableWith(descriptor.annotations)
|
||||
val optional = descriptor.annotations.serialOptional
|
||||
val transient = descriptor.annotations.serialTransient
|
||||
val optional = descriptor.declaresDefaultValue
|
||||
val transient = descriptor.annotations.serialTransient || !hasBackingField
|
||||
val annotationsWithArguments: List<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> =
|
||||
descriptor.annotationsWithArguments()
|
||||
|
||||
@@ -42,3 +49,10 @@ class SerializableProperty(val descriptor: PropertyDescriptor, val isConstructor
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
val PropertyDescriptor.declaresDefaultValue: Boolean
|
||||
get() = when (val declaration = this.source.getPsi()) {
|
||||
is KtDeclarationWithInitializer -> declaration.initializer != null
|
||||
is KtParameter -> declaration.defaultValue != null
|
||||
else -> false
|
||||
}
|
||||
Reference in New Issue
Block a user