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:
Leonid Startsev
2019-01-16 17:37:32 +03:00
parent cca03e9586
commit 08f983ef52
3 changed files with 44 additions and 33 deletions
@@ -18,7 +18,6 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi 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 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
class SerializableCodegenImpl( class SerializableCodegenImpl(
private val classCodegen: ImplementationBodyCodegen, private val classCodegen: ImplementationBodyCodegen
serializableClass: ClassDescriptor
) : SerializableCodegen(classCodegen.descriptor, classCodegen.bindingContext) { ) : SerializableCodegen(classCodegen.descriptor, classCodegen.bindingContext) {
private val thisAsmType = classCodegen.typeMapper.mapClass(serializableDescriptor) private val thisAsmType = classCodegen.typeMapper.mapClass(serializableDescriptor)
@@ -46,7 +44,7 @@ class SerializableCodegenImpl(
fun generateSerializableExtensions(codegen: ImplementationBodyCodegen) { fun generateSerializableExtensions(codegen: ImplementationBodyCodegen) {
val serializableClass = codegen.descriptor val serializableClass = codegen.descriptor
if (serializableClass.isInternalSerializable) if (serializableClass.isInternalSerializable)
SerializableCodegenImpl(codegen, serializableClass).generate() SerializableCodegenImpl(codegen).generate()
else if (serializableClass.hasSerializableAnnotationWithoutArgs && !serializableClass.hasCompanionObjectAsSerializer) { else if (serializableClass.hasSerializableAnnotationWithoutArgs && !serializableClass.hasCompanionObjectAsSerializer) {
throw CompilationException( throw CompilationException(
"@Serializable annotation on $serializableClass would be ignored because it is impossible to serialize it automatically. " + "@Serializable annotation on $serializableClass would be ignored because it is impossible to serialize it automatically. " +
@@ -96,7 +94,8 @@ class SerializableCodegenImpl(
val myPropsStart: Int val myPropsStart: Int
if (superClass.isInternalSerializable) { if (superClass.isInternalSerializable) {
myPropsStart = SerializableProperties(superClass, classCodegen.bindingContext).serializableProperties.size 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) //super.writeSelf(output, serialDesc)
load(thisI, thisAsmType) load(thisI, thisAsmType)
load(outputI, kOutputType) load(outputI, kOutputType)
@@ -108,10 +107,15 @@ class SerializableCodegenImpl(
load(offsetI + it, kSerializerType) load(offsetI + it, kSerializerType)
} }
} }
val superSignature = classCodegen.typeMapper.mapSignatureSkipGeneric(KSerializerDescriptorResolver.createWriteSelfFunctionDescriptor(superClass)) val superSignature =
invokespecial(classCodegen.typeMapper.mapType(superClass).internalName, superSignature.asmMethod.name, superSignature.asmMethod.descriptor, false) classCodegen.typeMapper.mapSignatureSkipGeneric(KSerializerDescriptorResolver.createWriteSelfFunctionDescriptor(superClass))
} invokespecial(
else { classCodegen.typeMapper.mapType(superClass).internalName,
superSignature.asmMethod.name,
superSignature.asmMethod.descriptor,
false
)
} else {
myPropsStart = 0 myPropsStart = 0
} }
@@ -174,16 +178,9 @@ class SerializableCodegenImpl(
private fun InstructionAdapter.doGenerateConstructorImpl(exprCodegen: ExpressionCodegen) { private fun InstructionAdapter.doGenerateConstructorImpl(exprCodegen: ExpressionCodegen) {
val seenMask = 1 val seenMask = 1
// var propOffset = 2
var (propIndex, propOffset) = generateSuperSerializableCall(2) var (propIndex, propOffset) = generateSuperSerializableCall(2)
for (i in propIndex until properties.serializableProperties.size) { for (i in propIndex until properties.serializableProperties.size) {
val prop = properties[i] 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 val propType = prop.asmType
if (!prop.optional) { if (!prop.optional) {
// primary were validated before constructor call // primary were validated before constructor call
@@ -196,8 +193,7 @@ class SerializableCodegenImpl(
load(0, thisAsmType) load(0, thisAsmType)
load(propOffset, propType) load(propOffset, propType)
putfield(thisAsmType.internalName, prop.descriptor.name.asString(), propType.descriptor) putfield(thisAsmType.internalName, prop.descriptor.name.asString(), propType.descriptor)
} } else {
else {
genValidateProperty(i) { seenMask } genValidateProperty(i) { seenMask }
val setLbl = Label() val setLbl = Label()
val nextLabel = Label() val nextLabel = Label()
@@ -211,7 +207,11 @@ class SerializableCodegenImpl(
visitLabel(setLbl) visitLabel(setLbl)
// setting defaultValue // setting defaultValue
if (classCodegen.bindingContext[BindingContext.BACKING_FIELD_REQUIRED, prop.descriptor] != true) 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) exprCodegen.genInitProperty(prop)
visitLabel(nextLabel) visitLabel(nextLabel)
} }
@@ -222,15 +222,15 @@ class SerializableCodegenImpl(
val serializedProps = properties.serializableProperties.map { it.descriptor } val serializedProps = properties.serializableProperties.map { it.descriptor }
(descToProps - serializedProps) (descToProps - serializedProps)
.filter { classCodegen.shouldInitializeProperty(it.value) } .filter { classCodegen.shouldInitializeProperty(it.value) }
.forEach { (_, prop) -> classCodegen.initializeProperty(exprCodegen, prop) } .forEach { (_, prop) -> classCodegen.initializeProperty(exprCodegen, prop) }
(paramsToProps - serializedProps) (paramsToProps - serializedProps)
.forEach { (t, u) -> exprCodegen.genInitParam(t, u) } .forEach { (t, u) -> exprCodegen.genInitParam(t, u) }
// init blocks // init blocks
// todo: proper order with other initializers // todo: proper order with other initializers
classCodegen.myClass.anonymousInitializers() classCodegen.myClass.anonymousInitializers()
.forEach { exprCodegen.gen(it, Type.VOID_TYPE) } .forEach { exprCodegen.gen(it, Type.VOID_TYPE) }
areturn(Type.VOID_TYPE) areturn(Type.VOID_TYPE)
} }
@@ -255,8 +255,7 @@ class SerializableCodegenImpl(
} }
invokespecial(superType, "<init>", desc, false) invokespecial(superType, "<init>", desc, false)
return 0 to propStartVar return 0 to propStartVar
} } else {
else {
val superProps = SerializableProperties(superClass, classCodegen.bindingContext).serializableProperties val superProps = SerializableProperties(superClass, classCodegen.bindingContext).serializableProperties
val creator = buildInternalConstructorDesc(propStartVar, 1, classCodegen, superProps) val creator = buildInternalConstructorDesc(propStartVar, 1, classCodegen, superProps)
invokespecial(superType, "<init>", creator, false) 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 { private fun ExpressionCodegen.genInitProperty(prop: SerializableProperty) = getProp(prop)?.let {
classCodegen.initializeProperty(this, it) classCodegen.initializeProperty(this, it)
} }
@@ -19,6 +19,7 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.hasBackingField
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) { class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) {
@@ -40,7 +41,8 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
.filterIsInstance<PropertyDescriptor>() .filterIsInstance<PropertyDescriptor>()
.filter { it.kind == CallableMemberDescriptor.Kind.DECLARATION } .filter { it.kind == CallableMemberDescriptor.Kind.DECLARATION }
.filter(this::isPropSerializable) .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) } .partition { primaryConstructorProperties.contains(it.descriptor) }
.run { .run {
val supers = serializableClass.getSuperClassNotAny() val supers = serializableClass.getSuperClassNotAny()
@@ -66,7 +68,6 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
serializableProperties.minus(serializableConstructorProperties) serializableProperties.minus(serializableConstructorProperties)
val size = serializableProperties.size val size = serializableProperties.size
val indices = serializableProperties.indices
operator fun get(index: Int) = serializableProperties[index] operator fun get(index: Int) = serializableProperties[index]
operator fun iterator() = serializableProperties.iterator() operator fun iterator() = serializableProperties.iterator()
@@ -20,18 +20,25 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations 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.psi.ValueArgument
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.KotlinType 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 name = descriptor.annotations.serialNameValue ?: descriptor.name.asString()
val type = descriptor.type val type = descriptor.type
val genericIndex = type.genericIndex val genericIndex = type.genericIndex
val module = descriptor.module val module = descriptor.module
val serializableWith = extractSerializableWith(descriptor.annotations) val serializableWith = extractSerializableWith(descriptor.annotations)
val optional = descriptor.annotations.serialOptional val optional = descriptor.declaresDefaultValue
val transient = descriptor.annotations.serialTransient val transient = descriptor.annotations.serialTransient || !hasBackingField
val annotationsWithArguments: List<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> = val annotationsWithArguments: List<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> =
descriptor.annotationsWithArguments() descriptor.annotationsWithArguments()
@@ -42,3 +49,10 @@ class SerializableProperty(val descriptor: PropertyDescriptor, val isConstructor
else null 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
}