[SERIALIZATION] Fix kotlinx.serialization plugin

This commit is contained in:
Roman Artemev
2020-04-08 18:51:35 +03:00
committed by romanart
parent a9788f9506
commit cd931796bc
3 changed files with 71 additions and 46 deletions
@@ -422,8 +422,7 @@ abstract class KotlinIrLinker(
} }
protected open fun resolveModuleDeserializer(moduleDescriptor: ModuleDescriptor): IrModuleDeserializer { protected open fun resolveModuleDeserializer(moduleDescriptor: ModuleDescriptor): IrModuleDeserializer {
return deserializersForModules[moduleDescriptor] ?: return deserializersForModules[moduleDescriptor] ?: error("No module deserializer found for $moduleDescriptor")
error("No module deserializer found for $moduleDescriptor")
} }
protected abstract fun createModuleDeserializer( protected abstract fun createModuleDeserializer(
@@ -49,12 +49,23 @@ interface IrBuilderExtension {
val compilerContext: SerializationPluginContext val compilerContext: SerializationPluginContext
private fun IrClass.declareSimpleFunctionWithExternalOverrides(descriptor: FunctionDescriptor): IrSimpleFunction { private fun IrClass.declareSimpleFunctionWithExternalOverrides(descriptor: FunctionDescriptor): IrSimpleFunction {
return compilerContext.symbolTable.declareSimpleFunction(startOffset, endOffset, SERIALIZABLE_PLUGIN_ORIGIN, descriptor) val functionSymbol = compilerContext.symbolTable.referenceSimpleFunction(descriptor)
.also { f -> val function = if (functionSymbol.isBound) functionSymbol.owner else {
f.overriddenSymbols = descriptor.overriddenDescriptors.map { compilerContext.symbolTable.declareSimpleFunction(
compilerContext.symbolTable.referenceSimpleFunction(it.original) startOffset,
} endOffset,
SERIALIZABLE_PLUGIN_ORIGIN,
descriptor
).also {
it.parent = this
addMember(it)
} }
}
return function.also { f ->
f.overriddenSymbols = descriptor.overriddenDescriptors.map {
compilerContext.symbolTable.referenceSimpleFunction(it.original)
}
}
} }
private fun createFunctionGenerator(): FunctionGenerator = with(compilerContext) { private fun createFunctionGenerator(): FunctionGenerator = with(compilerContext) {
@@ -77,24 +88,17 @@ interface IrBuilderExtension {
fun IrClass.contributeFunction( fun IrClass.contributeFunction(
descriptor: FunctionDescriptor, descriptor: FunctionDescriptor,
declareNew: Boolean = true,
bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit
) { ) {
val f: IrSimpleFunction = if (declareNew) declareSimpleFunctionWithExternalOverrides( val f: IrSimpleFunction = declareSimpleFunctionWithExternalOverrides(descriptor)
descriptor f.buildWithScope {
) else compilerContext.symbolTable.referenceSimpleFunction(descriptor).owner createFunctionGenerator().generateFunctionParameterDeclarationsAndReturnType(f, null, null)
f.parent = this
if (declareNew) {
f.buildWithScope {
createFunctionGenerator().generateFunctionParameterDeclarationsAndReturnType(f, null, null)
}
} }
f.body = DeclarationIrBuilder(compilerContext, f.symbol, this.startOffset, this.endOffset).irBlockBody( f.body = DeclarationIrBuilder(compilerContext, f.symbol, this.startOffset, this.endOffset).irBlockBody(
this.startOffset, this.startOffset,
this.endOffset this.endOffset
) { bodyGen(f) } ) { bodyGen(f) }
this.addMember(f)
} }
fun IrClass.contributeConstructor( fun IrClass.contributeConstructor(
@@ -103,21 +107,32 @@ interface IrBuilderExtension {
overwriteValueParameters: Boolean = false, overwriteValueParameters: Boolean = false,
bodyGen: IrBlockBodyBuilder.(IrConstructor) -> Unit bodyGen: IrBlockBodyBuilder.(IrConstructor) -> Unit
) { ) {
val c = if (declareNew) compilerContext.symbolTable.declareConstructor( val ctorSymbol = compilerContext.symbolTable.referenceConstructor(descriptor)
this.startOffset, val c = if (ctorSymbol.isBound) {
this.endOffset, ctorSymbol.owner
SERIALIZABLE_PLUGIN_ORIGIN, } else {
descriptor compilerContext.symbolTable.declareConstructor(
) else compilerContext.symbolTable.referenceConstructor(descriptor).owner this.startOffset,
c.parent = this this.endOffset,
SERIALIZABLE_PLUGIN_ORIGIN,
descriptor
).also {
it.parent = this
addMember(it)
}
}
c.returnType = descriptor.returnType.toIrType() c.returnType = descriptor.returnType.toIrType()
if (declareNew || overwriteValueParameters) c.createParameterDeclarations( if (declareNew || overwriteValueParameters)
c.createParameterDeclarations(
receiver = null, receiver = null,
overwriteValueParameters = overwriteValueParameters, overwriteValueParameters = overwriteValueParameters,
copyTypeParameters = false copyTypeParameters = false
) )
c.body = DeclarationIrBuilder(compilerContext, c.symbol, this.startOffset, this.endOffset).irBlockBody(this.startOffset, this.endOffset) { bodyGen(c) } c.body = DeclarationIrBuilder(compilerContext, c.symbol, this.startOffset, this.endOffset).irBlockBody(
this.addMember(c) this.startOffset,
this.endOffset
) { bodyGen(c) }
} }
fun IrBuilderWithScope.irInvoke( fun IrBuilderWithScope.irInvoke(
@@ -126,7 +141,7 @@ interface IrBuilderExtension {
vararg args: IrExpression, vararg args: IrExpression,
typeHint: IrType? = null typeHint: IrType? = null
): IrMemberAccessExpression { ): IrMemberAccessExpression {
val returnType = typeHint ?: callee.descriptor.returnType!!.toIrType() val returnType = typeHint ?: callee.run { if (isBound) owner.returnType else descriptor.returnType!!.toIrType() }
val call = irCall(callee, type = returnType) val call = irCall(callee, type = returnType)
call.dispatchReceiver = dispatchReceiver call.dispatchReceiver = dispatchReceiver
args.forEachIndexed(call::putValueArgument) args.forEachIndexed(call::putValueArgument)
@@ -253,12 +268,15 @@ interface IrBuilderExtension {
propertyDescriptor: PropertyDescriptor, propertyDescriptor: PropertyDescriptor,
propertyParent: IrClass propertyParent: IrClass
): IrProperty { ): IrProperty {
val irProperty = IrPropertyImpl( val symbol = compilerContext.symbolTable.referenceProperty(propertyDescriptor)
propertyParent.startOffset, propertyParent.endOffset, val irProperty = if (symbol.isBound) symbol.owner else {
SERIALIZABLE_PLUGIN_ORIGIN, false, compilerContext.symbolTable.declareProperty(propertyParent.startOffset, propertyParent.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, propertyDescriptor) {
propertyDescriptor IrPropertyImpl(propertyParent.startOffset, propertyParent.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, it)
) }.also {
irProperty.parent = propertyParent it.parent = propertyParent
propertyParent.addMember(it)
}
}
irProperty.backingField = generatePropertyBackingField(propertyDescriptor, irProperty).apply { irProperty.backingField = generatePropertyBackingField(propertyDescriptor, irProperty).apply {
parent = propertyParent parent = propertyParent
correspondingPropertySymbol = irProperty.symbol correspondingPropertySymbol = irProperty.symbol
@@ -288,9 +306,12 @@ interface IrBuilderExtension {
descriptor: PropertyAccessorDescriptor, descriptor: PropertyAccessorDescriptor,
fieldSymbol: IrFieldSymbol fieldSymbol: IrFieldSymbol
): IrSimpleFunction { ): IrSimpleFunction {
val declaration = compilerContext.symbolTable.declareSimpleFunctionWithOverrides(fieldSymbol.owner.startOffset, val symbol = compilerContext.symbolTable.referenceSimpleFunction(descriptor)
fieldSymbol.owner.endOffset,
SERIALIZABLE_PLUGIN_ORIGIN, descriptor) val declaration = if (symbol.isBound) symbol.owner.also { generateOverriddenFunctionSymbols(it, compilerContext.symbolTable) } else compilerContext.symbolTable.declareSimpleFunctionWithOverrides(fieldSymbol.owner.startOffset,
fieldSymbol.owner.endOffset,
SERIALIZABLE_PLUGIN_ORIGIN, descriptor)
return declaration.buildWithScope { irAccessor -> return declaration.buildWithScope { irAccessor ->
irAccessor.createParameterDeclarations(receiver = null) irAccessor.createParameterDeclarations(receiver = null)
irAccessor.returnType = irAccessor.descriptor.returnType!!.toIrType() irAccessor.returnType = irAccessor.descriptor.returnType!!.toIrType()
@@ -496,15 +517,17 @@ interface IrBuilderExtension {
nullableSerializerClass: IrClassSymbol nullableSerializerClass: IrClassSymbol
): IrExpression { ): IrExpression {
return if (type.isMarkedNullable) { return if (type.isMarkedNullable) {
val nullableConstructor = val classDeclaration = nullableSerializerClass.owner
compilerContext.symbolTable.referenceConstructor(nullableSerializerClass.descriptor.constructors.toList().first()) val nullableConstructor = classDeclaration.declarations.first { it is IrConstructor } as IrConstructor
val resultType = type.makeNotNullable() val resultType = type.makeNotNullable()
val typeParameters = classDeclaration.typeParameters
val typeArguments = listOf(resultType.toIrType())
irInvoke( irInvoke(
null, nullableConstructor, null, nullableConstructor.symbol,
typeArguments = listOf(resultType.toIrType()), typeArguments = typeArguments,
valueArguments = listOf(expression), valueArguments = listOf(expression),
// Return type should be correctly substituted // Return type should be correctly substituted
returnTypeHint = nullableConstructor.descriptor.returnType.replace(listOf(resultType.asTypeProjection())).toIrType() returnTypeHint = nullableConstructor.returnType.substitute(typeParameters, typeArguments)
) )
} else { } else {
expression expression
@@ -663,7 +686,11 @@ interface IrBuilderExtension {
compilerContext.symbolTable.referenceConstructor(serializerClass.unsubstitutedPrimaryConstructor!!) compilerContext.symbolTable.referenceConstructor(serializerClass.unsubstitutedPrimaryConstructor!!)
} }
// Return type should be correctly substituted // Return type should be correctly substituted
val substitutedReturnType = ctor.descriptor.returnType.replace(typeArgs.map { it.toKotlinType().asTypeProjection() }).toIrType() val substitutedReturnType = if (ctor.isBound) {
val ctorDecl = ctor.owner
val typeParameters = ctorDecl.parentAsClass.typeParameters
ctor.owner.returnType.substitute(typeParameters, typeArgs)
} else ctor.descriptor.returnType.replace(typeArgs.map { it.toKotlinType().asTypeProjection() }).toIrType()
return irInvoke(null, ctor, typeArguments = typeArgs, valueArguments = args, returnTypeHint = substitutedReturnType) return irInvoke(null, ctor, typeArguments = typeArgs, valueArguments = args, returnTypeHint = substitutedReturnType)
} }
} }
@@ -60,10 +60,9 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
introduceValueParameter(thisAsReceiverParameter) introduceValueParameter(thisAsReceiverParameter)
prop = generateSimplePropertyWithBackingField(thisAsReceiverParameter.symbol, desc, irClass) prop = generateSimplePropertyWithBackingField(thisAsReceiverParameter.symbol, desc, irClass)
irClass.addMember(prop)
localSerializersFieldsDescriptors.forEach { localSerializersFieldsDescriptors.forEach {
irClass.addMember(generateSimplePropertyWithBackingField(thisAsReceiverParameter.symbol, it, irClass)) generateSimplePropertyWithBackingField(thisAsReceiverParameter.symbol, it, irClass)
} }
} }
@@ -233,7 +232,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
// fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): StructureEncoder // fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): StructureEncoder
val beginFunc = encoderClass.referenceMethod(CallingConventions.begin) { it.valueParameters.size == 1 } val beginFunc = encoderClass.referenceMethod(CallingConventions.begin) { it.valueParameters.size == 1 }
val call = irCall(beginFunc, type = beginFunc.descriptor.returnType!!.toIrType()).mapValueParametersIndexed { _, _ -> val call = irCall(beginFunc, type = beginFunc.owner.returnType).mapValueParametersIndexed { _, _ ->
irGet(localSerialDesc) irGet(localSerialDesc)
} }
// can it be done in more concise way? e.g. additional builder function? // can it be done in more concise way? e.g. additional builder function?