[KTX.SERIALIZATION] Refactor plugin once again

This commit is contained in:
Roman Artemev
2020-04-29 20:08:33 +03:00
committed by romanart
parent d41bbbae0d
commit 1949b11bb2
6 changed files with 233 additions and 229 deletions
@@ -11,29 +11,19 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.types.makeNotNull
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
import org.jetbrains.kotlin.psi2ir.generators.DeclarationGenerator
import org.jetbrains.kotlin.psi2ir.generators.FunctionGenerator
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
@@ -48,53 +38,11 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.*
interface IrBuilderExtension { interface IrBuilderExtension {
val compilerContext: SerializationPluginContext val compilerContext: SerializationPluginContext
private fun IrClass.declareSimpleFunctionWithExternalOverrides(descriptor: FunctionDescriptor): IrSimpleFunction { fun IrClass.contributeFunction(descriptor: FunctionDescriptor, bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit) {
val functionSymbol = compilerContext.symbolTable.referenceSimpleFunction(descriptor) val functionSymbol = compilerContext.symbolTable.referenceSimpleFunction(descriptor)
val function = if (functionSymbol.isBound) functionSymbol.owner else { assert(functionSymbol.isBound)
compilerContext.symbolTable.declareSimpleFunction( val f: IrSimpleFunction = functionSymbol.owner
startOffset, // TODO: default parameters
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) {
return FunctionGenerator(
DeclarationGenerator(
GeneratorContext(
Psi2IrConfiguration(),
moduleDescriptor,
bindingContext,
languageVersionSettings,
symbolTable,
GeneratorExtensions(),
typeTranslator,
typeTranslator.constantValueGenerator,
irBuiltIns
)
)
)
}
fun IrClass.contributeFunction(
descriptor: FunctionDescriptor,
bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit
) {
val f: IrSimpleFunction = declareSimpleFunctionWithExternalOverrides(descriptor)
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
@@ -108,27 +56,10 @@ interface IrBuilderExtension {
bodyGen: IrBlockBodyBuilder.(IrConstructor) -> Unit bodyGen: IrBlockBodyBuilder.(IrConstructor) -> Unit
) { ) {
val ctorSymbol = compilerContext.symbolTable.referenceConstructor(descriptor) val ctorSymbol = compilerContext.symbolTable.referenceConstructor(descriptor)
val c = if (ctorSymbol.isBound) { assert(ctorSymbol.isBound)
ctorSymbol.owner
} else { val c = ctorSymbol.owner
compilerContext.symbolTable.declareConstructor(
this.startOffset,
this.endOffset,
SERIALIZABLE_PLUGIN_ORIGIN,
descriptor
).also {
it.parent = this
addMember(it)
}
}
c.returnType = descriptor.returnType.toIrType()
if (declareNew || overwriteValueParameters)
c.createParameterDeclarations(
receiver = null,
overwriteValueParameters = overwriteValueParameters,
copyTypeParameters = false
)
c.body = DeclarationIrBuilder(compilerContext, c.symbol, this.startOffset, this.endOffset).irBlockBody( c.body = DeclarationIrBuilder(compilerContext, c.symbol, this.startOffset, this.endOffset).irBlockBody(
this.startOffset, this.startOffset,
this.endOffset this.endOffset
@@ -141,7 +72,8 @@ interface IrBuilderExtension {
vararg args: IrExpression, vararg args: IrExpression,
typeHint: IrType? = null typeHint: IrType? = null
): IrMemberAccessExpression { ): IrMemberAccessExpression {
val returnType = typeHint ?: callee.run { if (isBound) owner.returnType else descriptor.returnType!!.toIrType() } assert(callee.isBound) { "Symbol $callee expected to be bound" }
val returnType = typeHint ?: callee.run { owner.returnType }
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)
@@ -167,7 +99,7 @@ interface IrBuilderExtension {
arrayElements: List<IrExpression> arrayElements: List<IrExpression>
): IrExpression { ): IrExpression {
val arrayType = compilerContext.symbols.array.typeWith(arrayElementType) val arrayType = compilerContext.irBuiltIns.arrayClass.typeWith(arrayElementType)
val arg0 = IrVarargImpl(startOffset, endOffset, arrayType, arrayElementType, arrayElements) val arg0 = IrVarargImpl(startOffset, endOffset, arrayType, arrayElementType, arrayElements)
val typeArguments = listOf(arrayElementType) val typeArguments = listOf(arrayElementType)
@@ -203,7 +135,7 @@ interface IrBuilderExtension {
fun <T : IrDeclaration> T.buildWithScope(builder: (T) -> Unit): T = fun <T : IrDeclaration> T.buildWithScope(builder: (T) -> Unit): T =
also { irDeclaration -> also { irDeclaration ->
compilerContext.symbolTable.withScope(irDeclaration.descriptor) { compilerContext.symbolTable.withReferenceScope(irDeclaration.descriptor) {
builder(irDeclaration) builder(irDeclaration)
} }
} }
@@ -253,12 +185,12 @@ interface IrBuilderExtension {
*/ */
fun IrBuilderWithScope.generateAnySuperConstructorCall(toBuilder: IrBlockBodyBuilder) { fun IrBuilderWithScope.generateAnySuperConstructorCall(toBuilder: IrBlockBodyBuilder) {
val anyConstructor = compilerContext.builtIns.any.constructors.single() val anyConstructor = compilerContext.irBuiltIns.anyClass.owner.declarations.single { it is IrConstructor } as IrConstructor
with(toBuilder) { with(toBuilder) {
+IrDelegatingConstructorCallImpl( +IrDelegatingConstructorCallImpl(
startOffset, endOffset, startOffset, endOffset,
compilerContext.irBuiltIns.unitType, compilerContext.irBuiltIns.unitType,
compilerContext.symbolTable.referenceConstructor(anyConstructor) anyConstructor.symbol
) )
} }
} }
@@ -266,26 +198,29 @@ interface IrBuilderExtension {
fun generateSimplePropertyWithBackingField( fun generateSimplePropertyWithBackingField(
ownerSymbol: IrValueSymbol, ownerSymbol: IrValueSymbol,
propertyDescriptor: PropertyDescriptor, propertyDescriptor: PropertyDescriptor,
propertyParent: IrClass propertyParent: IrClass,
declare: Boolean
): IrProperty { ): IrProperty {
val symbol = compilerContext.symbolTable.referenceProperty(propertyDescriptor) val irPropertySymbol = compilerContext.symbolTable.referenceProperty(propertyDescriptor)
val irProperty = if (symbol.isBound) symbol.owner else { assert(irPropertySymbol.isBound || declare)
compilerContext.symbolTable.declareProperty(propertyParent.startOffset, propertyParent.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, propertyDescriptor) {
IrPropertyImpl(propertyParent.startOffset, propertyParent.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, it) if (declare) {
}.also { IrPropertyImpl(propertyParent.startOffset, propertyParent.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, irPropertySymbol).also {
it.parent = propertyParent it.parent = propertyParent
propertyParent.addMember(it) propertyParent.addMember(it)
} }
} }
val irProperty = irPropertySymbol.owner
irProperty.backingField = generatePropertyBackingField(propertyDescriptor, irProperty).apply { irProperty.backingField = generatePropertyBackingField(propertyDescriptor, irProperty).apply {
parent = propertyParent parent = propertyParent
correspondingPropertySymbol = irProperty.symbol correspondingPropertySymbol = irPropertySymbol
} }
val fieldSymbol = irProperty.backingField!!.symbol val fieldSymbol = irProperty.backingField!!.symbol
irProperty.getter = propertyDescriptor.getter?.let { generatePropertyAccessor(it, fieldSymbol) } irProperty.getter = propertyDescriptor.getter?.let { generatePropertyAccessor(it, fieldSymbol, declare) }
?.apply { parent = propertyParent; correspondingPropertySymbol = irProperty.symbol } ?.apply { parent = propertyParent }
irProperty.setter = propertyDescriptor.setter?.let { generatePropertyAccessor(it, fieldSymbol) } irProperty.setter = propertyDescriptor.setter?.let { generatePropertyAccessor(it, fieldSymbol, declare) }
?.apply { parent = propertyParent; correspondingPropertySymbol = irProperty.symbol } ?.apply { parent = propertyParent }
return irProperty return irProperty
} }
@@ -293,34 +228,47 @@ interface IrBuilderExtension {
propertyDescriptor: PropertyDescriptor, propertyDescriptor: PropertyDescriptor,
originProperty: IrProperty originProperty: IrProperty
): IrField { ): IrField {
return compilerContext.symbolTable.declareField( val fieldSymbol = compilerContext.symbolTable.referenceField(propertyDescriptor)
originProperty.startOffset,
originProperty.endOffset, if (fieldSymbol.isBound) return fieldSymbol.owner
SERIALIZABLE_PLUGIN_ORIGIN,
propertyDescriptor, return originProperty.run {
propertyDescriptor.type.toIrType() // TODO: type parameters
) IrFieldImpl(startOffset, endOffset, SERIALIZABLE_PLUGIN_ORIGIN, fieldSymbol, propertyDescriptor.type.toIrType())
}
} }
fun generatePropertyAccessor( fun generatePropertyAccessor(
descriptor: PropertyAccessorDescriptor, descriptor: PropertyAccessorDescriptor,
fieldSymbol: IrFieldSymbol fieldSymbol: IrFieldSymbol,
declare: Boolean
): IrSimpleFunction { ): IrSimpleFunction {
val symbol = compilerContext.symbolTable.referenceSimpleFunction(descriptor) val symbol = compilerContext.symbolTable.referenceSimpleFunction(descriptor)
assert(symbol.isBound || declare)
val declaration = if (symbol.isBound) symbol.owner.also { generateOverriddenFunctionSymbols(it, compilerContext.symbolTable) } else compilerContext.symbolTable.declareSimpleFunctionWithOverrides(fieldSymbol.owner.startOffset, if (declare) {
IrFunctionImpl(
fieldSymbol.owner.startOffset,
fieldSymbol.owner.endOffset, fieldSymbol.owner.endOffset,
SERIALIZABLE_PLUGIN_ORIGIN, descriptor) SERIALIZABLE_PLUGIN_ORIGIN,
symbol,
return declaration.buildWithScope { irAccessor -> descriptor.returnType!!.toIrType()
irAccessor.createParameterDeclarations(receiver = null) ).also { f ->
irAccessor.returnType = irAccessor.descriptor.returnType!!.toIrType() generateOverriddenFunctionSymbols(f, compilerContext.symbolTable)
irAccessor.body = when (descriptor) { f.createParameterDeclarations(receiver = null)
is PropertyGetterDescriptor -> generateDefaultGetterBody(descriptor, irAccessor) f.returnType = descriptor.returnType!!.toIrType()
is PropertySetterDescriptor -> generateDefaultSetterBody(descriptor, irAccessor) f.correspondingPropertySymbol = fieldSymbol.owner.correspondingPropertySymbol
else -> throw AssertionError("Should be getter or setter: $descriptor")
} }
} }
val irAccessor = symbol.owner
irAccessor.body = when (descriptor) {
is PropertyGetterDescriptor -> generateDefaultGetterBody(descriptor, irAccessor)
is PropertySetterDescriptor -> generateDefaultSetterBody(descriptor, irAccessor)
else -> throw AssertionError("Should be getter or setter: $descriptor")
}
return irAccessor
} }
private fun generateDefaultGetterBody( private fun generateDefaultGetterBody(
@@ -328,6 +276,7 @@ interface IrBuilderExtension {
irAccessor: IrSimpleFunction irAccessor: IrSimpleFunction
): IrBlockBody { ): IrBlockBody {
val property = getter.correspondingProperty val property = getter.correspondingProperty
val irProperty = irAccessor.correspondingPropertySymbol?.owner ?: error("Expected property for $getter")
val startOffset = irAccessor.startOffset val startOffset = irAccessor.startOffset
val endOffset = irAccessor.endOffset val endOffset = irAccessor.endOffset
@@ -341,7 +290,7 @@ interface IrBuilderExtension {
irAccessor.symbol, irAccessor.symbol,
IrGetFieldImpl( IrGetFieldImpl(
startOffset, endOffset, startOffset, endOffset,
compilerContext.symbolTable.referenceField(property), irProperty.backingField?.symbol ?: error("Property expected to have backing field"),
property.type.toIrType(), property.type.toIrType(),
receiver receiver
) )
@@ -355,7 +304,7 @@ interface IrBuilderExtension {
irAccessor: IrSimpleFunction irAccessor: IrSimpleFunction
): IrBlockBody { ): IrBlockBody {
val property = setter.correspondingProperty val property = setter.correspondingProperty
val irProperty = irAccessor.correspondingPropertySymbol?.owner ?: error("Expected corresponding property for accessor $setter")
val startOffset = irAccessor.startOffset val startOffset = irAccessor.startOffset
val endOffset = irAccessor.endOffset val endOffset = irAccessor.endOffset
val irBody = IrBlockBodyImpl(startOffset, endOffset) val irBody = IrBlockBodyImpl(startOffset, endOffset)
@@ -366,7 +315,7 @@ interface IrBuilderExtension {
irBody.statements.add( irBody.statements.add(
IrSetFieldImpl( IrSetFieldImpl(
startOffset, endOffset, startOffset, endOffset,
compilerContext.symbolTable.referenceField(property), irProperty.backingField?.symbol ?: error("Property $property expected to have backing field"),
receiver, receiver,
IrGetValueImpl(startOffset, endOffset, irValueParameter.type, irValueParameter.symbol), IrGetValueImpl(startOffset, endOffset, irValueParameter.type, irValueParameter.symbol),
compilerContext.irBuiltIns.unitType compilerContext.irBuiltIns.unitType
@@ -405,6 +354,11 @@ interface IrBuilderExtension {
it.parent = this@createParameterDeclarations it.parent = this@createParameterDeclarations
} }
if (copyTypeParameters) {
assert(typeParameters.isEmpty())
copyTypeParamsFromDescriptor()
}
dispatchReceiverParameter = descriptor.dispatchReceiverParameter?.irValueParameter() dispatchReceiverParameter = descriptor.dispatchReceiverParameter?.irValueParameter()
extensionReceiverParameter = descriptor.extensionReceiverParameter?.irValueParameter() extensionReceiverParameter = descriptor.extensionReceiverParameter?.irValueParameter()
@@ -412,22 +366,24 @@ interface IrBuilderExtension {
assert(valueParameters.isEmpty()) assert(valueParameters.isEmpty())
valueParameters = descriptor.valueParameters.map { it.irValueParameter() } valueParameters = descriptor.valueParameters.map { it.irValueParameter() }
assert(typeParameters.isEmpty())
if (copyTypeParameters) copyTypeParamsFromDescriptor()
} }
fun IrFunction.copyTypeParamsFromDescriptor() { fun IrFunction.copyTypeParamsFromDescriptor() {
typeParameters += descriptor.typeParameters.map { val newTypeParameters = descriptor.typeParameters.map {
IrTypeParameterImpl( IrTypeParameterImpl(
startOffset, endOffset, startOffset, endOffset,
SERIALIZABLE_PLUGIN_ORIGIN, SERIALIZABLE_PLUGIN_ORIGIN,
it it
).also { typeParameter -> ).also { typeParameter ->
typeParameter.parent = this typeParameter.parent = this
typeParameter.superTypes.addAll(it.upperBounds.map { it.toIrType() })
} }
} }
newTypeParameters.forEach { typeParameter ->
typeParameter.superTypes.addAll(typeParameter.descriptor.upperBounds.map { it.toIrType() })
}
typeParameters = newTypeParameters
} }
fun kClassTypeFor(projection: TypeProjection): SimpleType { fun kClassTypeFor(projection: TypeProjection): SimpleType {
@@ -443,7 +399,7 @@ interface IrBuilderExtension {
startOffset, startOffset,
endOffset, endOffset,
returnType.toIrType(), returnType.toIrType(),
compilerContext.symbolTable.referenceClassifier(clazz), compilerContext.referenceClass(clazz.fqNameSafe) ?: error("Couldn't load class $clazz"),
classType.toIrType() classType.toIrType()
) )
} }
@@ -471,9 +427,10 @@ interface IrBuilderExtension {
fun findEnumValuesMethod(enumClass: ClassDescriptor): IrFunction { fun findEnumValuesMethod(enumClass: ClassDescriptor): IrFunction {
assert(enumClass.kind == ClassKind.ENUM_CLASS) assert(enumClass.kind == ClassKind.ENUM_CLASS)
return compilerContext.symbolTable.referenceClass(enumClass).owner.functions return compilerContext.referenceClass(enumClass.fqNameSafe)?.let {
.find { it.origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER && it.name == Name.identifier("values") } it.owner.functions.find { it.origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER && it.name == Name.identifier("values") }
?: throw AssertionError("Enum class does not have .values() function") ?: throw AssertionError("Enum class does not have .values() function")
} ?: error("Couldn't load class $enumClass")
} }
private fun getEnumMembersNames(enumClass: ClassDescriptor): Sequence<String> { private fun getEnumMembersNames(enumClass: ClassDescriptor): Sequence<String> {
@@ -490,8 +447,8 @@ interface IrBuilderExtension {
dispatchReceiverParameter: IrValueParameter, dispatchReceiverParameter: IrValueParameter,
property: SerializableProperty property: SerializableProperty
): IrExpression? { ): IrExpression? {
val nullableSerClass = val nullableSerializerFqn = getInternalPackageFqn(SpecialBuiltins.nullableSerializer)
compilerContext.symbolTable.referenceClass(property.module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer)) val nullableSerClass = compilerContext.referenceClass(nullableSerializerFqn) ?: error("Couldn't find class $nullableSerializerFqn")
val serializer = val serializer =
property.serializableWith?.toClassDescriptor property.serializableWith?.toClassDescriptor
?: if (!property.type.isTypeParameter()) generator.findTypeSerializerOrContext( ?: if (!property.type.isTypeParameter()) generator.findTypeSerializerOrContext(
@@ -517,15 +474,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
@@ -534,8 +493,8 @@ interface IrBuilderExtension {
fun wrapIrTypeIntoKSerializerIrType(module: ModuleDescriptor, type: IrType, variance: Variance = Variance.INVARIANT): IrType { fun wrapIrTypeIntoKSerializerIrType(module: ModuleDescriptor, type: IrType, variance: Variance = Variance.INVARIANT): IrType {
val kSerClass = val serializerFqn = getSerializationPackageFqn(SerialEntityNames.KSERIALIZER_CLASS)
compilerContext.symbolTable.referenceClass(module.getClassFromSerializationPackage(SerialEntityNames.KSERIALIZER_CLASS)) val kSerClass = compilerContext.referenceClass(serializerFqn) ?: error("Couldn't find class $serializerFqn")
return IrSimpleTypeImpl( return IrSimpleTypeImpl(
kSerClass, hasQuestionMark = false, arguments = listOf( kSerClass, hasQuestionMark = false, arguments = listOf(
makeTypeProjection(type, variance) makeTypeProjection(type, variance)
@@ -569,8 +528,8 @@ interface IrBuilderExtension {
genericIndex: Int? = null, genericIndex: Int? = null,
genericGetter: ((Int, KotlinType) -> IrExpression)? = null genericGetter: ((Int, KotlinType) -> IrExpression)? = null
): IrExpression? { ): IrExpression? {
val nullableSerClass = val nullableClassFqn = getInternalPackageFqn(SpecialBuiltins.nullableSerializer)
compilerContext.symbolTable.referenceClass(module.getClassFromInternalSerializationPackage(SpecialBuiltins.nullableSerializer)) val nullableSerClass = compilerContext.referenceClass(nullableClassFqn) ?: error("Expecting class $nullableClassFqn")
if (serializerClassOriginal == null) { if (serializerClassOriginal == null) {
if (genericIndex == null) return null if (genericIndex == null) return null
return genericGetter?.invoke(genericIndex, kType) return genericGetter?.invoke(genericIndex, kType)
@@ -679,20 +638,48 @@ interface IrBuilderExtension {
requireNotNull( requireNotNull(
findSerializerConstructorForTypeArgumentsSerializers(serializerClass) findSerializerConstructorForTypeArgumentsSerializers(serializerClass)
) { "Generated serializer does not have constructor with required number of arguments" } ) { "Generated serializer does not have constructor with required number of arguments" }
.let { compilerContext.symbolTable.referenceConstructor(it) }
} else { } else {
compilerContext.symbolTable.referenceConstructor(serializerClass.unsubstitutedPrimaryConstructor!!) compilerContext.referenceConstructors(serializerClass.fqNameSafe).single { it.owner.isPrimary }
} }
// Return type should be correctly substituted // Return type should be correctly substituted
val substitutedReturnType = if (ctor.isBound) { assert(ctor.isBound)
val ctorDecl = ctor.owner val ctorDecl = ctor.owner
val typeParameters = ctorDecl.parentAsClass.typeParameters val typeParameters = ctorDecl.parentAsClass.typeParameters
ctor.owner.returnType.substitute(typeParameters, typeArgs) val substitutedReturnType = ctorDecl.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)
} }
} }
fun ReferenceSymbolTable.serializableSyntheticConstructor(forClass: ClassDescriptor): IrConstructorSymbol = private fun findSerializerConstructorForTypeArgumentsSerializers(serializer: ClassDescriptor): IrConstructorSymbol? {
referenceConstructor(forClass.constructors.single { it.isSerializationCtor() }) val serializableImplementationTypeArguments = extractKSerializerArgumentFromImplementation(serializer)?.arguments
} ?: throw AssertionError("Serializer does not implement KSerializer??")
val typeParamsCount = serializableImplementationTypeArguments.size
if (typeParamsCount == 0) return null //don't need it
val constructors = compilerContext.referenceConstructors(serializer.fqNameSafe)
fun isKSerializer(type: IrType): Boolean {
val simpleType = type as? IrSimpleType ?: return false
val classifier = simpleType.classifier as? IrClassSymbol ?: return false
return classifier.owner.fqNameWhenAvailable == SerialEntityNames.KSERIALIZER_NAME_FQ
}
return constructors.singleOrNull {
it.owner.valueParameters.let { vps -> vps.size == typeParamsCount && vps.all { vp -> isKSerializer(vp.type) } }
}
}
private fun IrConstructor.isSerializationCtor(): Boolean {
val serialMarker =
compilerContext.referenceClass(SerializationPackages.packageFqName.child(SerialEntityNames.SERIAL_CTOR_MARKER_NAME))
return valueParameters.lastOrNull()?.run {
name == SerialEntityNames.dummyParamName && type.classifierOrNull == serialMarker
} == true
}
fun serializableSyntheticConstructor(forClass: IrClass): IrConstructorSymbol {
return forClass.declarations.filterIsInstance<IrConstructor>().single { it.isSerializationCtor() }.symbol
}
}
@@ -12,19 +12,17 @@ import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irInt import org.jetbrains.kotlin.ir.builders.irInt
import org.jetbrains.kotlin.ir.builders.irReturn import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.components.isVararg import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
@@ -63,16 +61,13 @@ class SerializableCompanionIrGenerator(
) )
) ?: return ) ?: return
val irSerializableClass = compilerContext.symbolTable.referenceClass(serializableDescriptor).takeIf { it.isBound }?.owner ?: return val irSerializableClass = compilerContext.referenceClass(serializableDescriptor.fqNameSafe)?.owner ?: return
val serializableWithAlreadyPresent = irSerializableClass.annotations.any { val serializableWithAlreadyPresent = irSerializableClass.annotations.any {
it.symbol.descriptor.constructedClass.fqNameSafe == annotationMarkerClass.fqNameSafe it.symbol.descriptor.constructedClass.fqNameSafe == annotationMarkerClass.fqNameSafe
} }
if (serializableWithAlreadyPresent) return if (serializableWithAlreadyPresent) return
val annotationCtor = requireNotNull(annotationMarkerClass.unsubstitutedPrimaryConstructor?.let { val annotationCtor = compilerContext.referenceConstructors(annotationMarkerClass.fqNameSafe).single { it.owner.isPrimary }
compilerContext.symbolTable.referenceConstructor(it)
})
val annotationType = annotationMarkerClass.defaultType.toIrType() val annotationType = annotationMarkerClass.defaultType.toIrType()
val annotationCtorCall = IrConstructorCallImpl.fromSymbolDescriptor(startOffset, endOffset, annotationType, annotationCtor).apply { val annotationCtorCall = IrConstructorCallImpl.fromSymbolDescriptor(startOffset, endOffset, annotationType, annotationCtor).apply {
val serializerType = serializer.toSimpleType(false) val serializerType = serializer.toSimpleType(false)
@@ -124,12 +119,11 @@ class SerializableCompanionIrGenerator(
val kSerializerStarType = factory.returnType val kSerializerStarType = factory.returnType
val array = factory.valueParameters.first() val array = factory.valueParameters.first()
val argsSize = serializableDescriptor.declaredTypeParameters.size val argsSize = serializableDescriptor.declaredTypeParameters.size
val arrayGet = val arrayGet = compilerContext.irBuiltIns.arrayClass.owner.declarations.filterIsInstance<IrSimpleFunction>()
compilerContext.builtIns.array.getFuncDesc("get").single() .single { it.name.asString() == "get" }
val arrayGetSymbol = compilerContext.symbolTable.referenceFunction(arrayGet)
val serializers: List<IrExpression> = (0 until argsSize).map { val serializers: List<IrExpression> = (0 until argsSize).map {
irInvoke(irGet(array), arrayGetSymbol, irInt(it), typeHint = kSerializerStarType) irInvoke(irGet(array), arrayGet.symbol, irInt(it), typeHint = kSerializerStarType)
} }
val serializerCall = compilerContext.symbolTable.referenceSimpleFunction(getterDescriptor) val serializerCall = compilerContext.symbolTable.referenceSimpleFunction(getterDescriptor)
val call = irInvoke( val call = irInvoke(
@@ -1,30 +1,22 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.lower.irThrow import org.jetbrains.kotlin.backend.common.lower.irThrow
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.CompilationException import org.jetbrains.kotlin.codegen.CompilationException
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrAnonymousInitializer import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrTypeProjection import org.jetbrains.kotlin.ir.types.IrTypeProjection
import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.getAnnotation
import org.jetbrains.kotlin.ir.util.TypeTranslator
import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless
@@ -38,26 +30,42 @@ class SerializableIrGenerator(
bindingContext: BindingContext bindingContext: BindingContext
) : SerializableCodegen(irClass.descriptor, bindingContext), IrBuilderExtension { ) : SerializableCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
private fun IrClass.getSuperClassOrAny(): IrClass {
val superClasses = superTypes.mapNotNull { it.classOrNull }.map { it.owner }
return superClasses.singleOrNull { it.kind == ClassKind.CLASS } ?: compilerContext.irBuiltIns.anyClass.owner
}
private fun IrClass.hasSerializableAnnotationWithoutArgs(): Boolean {
val annot = getAnnotation(SerializationAnnotations.serializableAnnotationFqName) ?: return false
for (i in 0 until annot.valueArgumentsCount) {
if (annot.getValueArgument(i) != null) return false
}
return true
}
private val IrClass.isInternalSerializable: Boolean get() = kind == ClassKind.CLASS && hasSerializableAnnotationWithoutArgs()
override fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor) = override fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor) =
irClass.contributeConstructor(constructorDescriptor, overwriteValueParameters = true) { ctor -> irClass.contributeConstructor(constructorDescriptor) { ctor ->
val transformFieldInitializer = buildInitializersRemapping(irClass) val transformFieldInitializer = buildInitializersRemapping(irClass)
// Missing field exception parts // Missing field exception parts
val exceptionCtor = val exceptionFqn = getSerializationPackageFqn(MISSING_FIELD_EXC)
serializableDescriptor.getClassFromSerializationPackage(MISSING_FIELD_EXC) val exceptionCtorRef = compilerContext.referenceConstructors(exceptionFqn).single { it.owner.isPrimary }
.unsubstitutedPrimaryConstructor!! val exceptionType = exceptionCtorRef.owner.returnType
val exceptionCtorRef = compilerContext.symbolTable.referenceConstructor(exceptionCtor)
val exceptionType = exceptionCtor.returnType.toIrType()
val serializableProperties = properties.serializableProperties val serializableProperties = properties.serializableProperties
val seenVarsOffset = serializableProperties.bitMaskSlotCount() val seenVarsOffset = serializableProperties.bitMaskSlotCount()
val seenVars = (0 until seenVarsOffset).map { ctor.valueParameters[it] } val seenVars = (0 until seenVarsOffset).map { ctor.valueParameters[it] }
val thiz = irClass.thisReceiver!! val thiz = irClass.thisReceiver!!
val superClass = irClass.descriptor.getSuperClassOrAny() val superClass = irClass.getSuperClassOrAny()
var startPropOffset: Int = 0 var startPropOffset: Int = 0
when { when {
KotlinBuiltIns.isAny(superClass) -> generateAnySuperConstructorCall(toBuilder = this@contributeConstructor) superClass.symbol == compilerContext.irBuiltIns.anyClass -> generateAnySuperConstructorCall(toBuilder = this@contributeConstructor)
superClass.isInternalSerializable -> { superClass.isInternalSerializable -> {
startPropOffset = generateSuperSerializableCall(superClass, ctor.valueParameters, seenVarsOffset) startPropOffset = generateSuperSerializableCall(superClass, ctor.valueParameters, seenVarsOffset)
} }
@@ -108,22 +116,23 @@ class SerializableIrGenerator(
} }
} }
private fun IrBlockBodyBuilder.generateSuperNonSerializableCall(superClass: ClassDescriptor) { private fun IrBlockBodyBuilder.generateSuperNonSerializableCall(superClass: IrClass) {
val suitableCtor = superClass.constructors.singleOrNull { it.valueParameters.size == 0 } val ctorRef = superClass.declarations.filterIsInstance<IrConstructor>().singleOrNull { it.valueParameters.isEmpty() }
?: throw IllegalArgumentException("Non-serializable parent of serializable $serializableDescriptor must have no arg constructor") ?: error("Non-serializable parent of serializable $serializableDescriptor must have no arg constructor")
val ctorRef = compilerContext.symbolTable.referenceConstructor(suitableCtor)
val call = IrDelegatingConstructorCallImpl( val call = IrDelegatingConstructorCallImpl(
startOffset, startOffset,
endOffset, endOffset,
compilerContext.irBuiltIns.unitType, compilerContext.irBuiltIns.unitType,
ctorRef ctorRef.symbol
) )
call.insertTypeArgumentsForSuperClass(superClass) call.insertTypeArgumentsForSuperClass(superClass)
+call +call
} }
private fun IrDelegatingConstructorCallImpl.insertTypeArgumentsForSuperClass(superClass: ClassDescriptor) { private fun IrDelegatingConstructorCallImpl.insertTypeArgumentsForSuperClass(superClass: IrClass) {
val superTypeCallArguments = (irClass.superTypes.find { it.classOrNull?.descriptor == superClass } as? IrSimpleType)?.arguments val superTypeCallArguments = (irClass.superTypes.find { it.classOrNull == superClass.symbol } as IrSimpleType?)?.arguments
superTypeCallArguments?.forEachIndexed { index, irTypeArgument -> superTypeCallArguments?.forEachIndexed { index, irTypeArgument ->
val argType = val argType =
irTypeArgument as? IrTypeProjection ?: throw IllegalStateException("Star projection in immediate argument for supertype") irTypeArgument as? IrTypeProjection ?: throw IllegalStateException("Star projection in immediate argument for supertype")
@@ -133,13 +142,13 @@ class SerializableIrGenerator(
// returns offset in serializable properties array // returns offset in serializable properties array
private fun IrBlockBodyBuilder.generateSuperSerializableCall( private fun IrBlockBodyBuilder.generateSuperSerializableCall(
superClass: ClassDescriptor, superClass: IrClass,
allValueParameters: List<IrValueParameter>, allValueParameters: List<IrValueParameter>,
propertiesStart: Int propertiesStart: Int
): Int { ): Int {
check(superClass.isInternalSerializable) check(superClass.isInternalSerializable)
val superCtorRef = compilerContext.symbolTable.serializableSyntheticConstructor(superClass) val superCtorRef = serializableSyntheticConstructor(superClass)
val superProperties = bindingContext.serializablePropertiesFor(superClass).serializableProperties val superProperties = bindingContext.serializablePropertiesFor(superClass.descriptor).serializableProperties
val superSlots = superProperties.bitMaskSlotCount() val superSlots = superProperties.bitMaskSlotCount()
val arguments = allValueParameters.subList(0, superSlots) + val arguments = allValueParameters.subList(0, superSlots) +
allValueParameters.subList(propertiesStart, propertiesStart + superProperties.size) + allValueParameters.subList(propertiesStart, propertiesStart + superProperties.size) +
@@ -9,10 +9,13 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.types.isSubtypeOfClass
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.functions import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.util.properties import org.jetbrains.kotlin.ir.util.properties
@@ -20,6 +23,7 @@ import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.*
@@ -35,7 +39,7 @@ class SerializerForEnumsGenerator(
IrGetValueImpl(startOffset, endOffset, saveFunc.dispatchReceiverParameter!!.symbol) IrGetValueImpl(startOffset, endOffset, saveFunc.dispatchReceiverParameter!!.symbol)
val encoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.ENCODER_CLASS) val encoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.ENCODER_CLASS)
val descriptorGetterSymbol = compilerContext.symbolTable.referenceFunction(anySerialDescProperty?.getter!!) val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol
val encodeEnum = encoderClass.referenceMethod(CallingConventions.encodeEnum) val encodeEnum = encoderClass.referenceMethod(CallingConventions.encodeEnum)
val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol) val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol)
@@ -51,7 +55,7 @@ class SerializerForEnumsGenerator(
IrGetValueImpl(startOffset, endOffset, loadFunc.dispatchReceiverParameter!!.symbol) IrGetValueImpl(startOffset, endOffset, loadFunc.dispatchReceiverParameter!!.symbol)
val decoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.DECODER_CLASS) val decoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.DECODER_CLASS)
val descriptorGetterSymbol = compilerContext.symbolTable.referenceFunction(anySerialDescProperty?.getter!!) val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol
val decode = decoderClass.referenceMethod(CallingConventions.decodeEnum) val decode = decoderClass.referenceMethod(CallingConventions.decodeEnum)
val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol) val serialDescGetter = irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol)
@@ -59,13 +63,14 @@ class SerializerForEnumsGenerator(
val valuesF = serializableIrClass.functions.single { it.name == DescriptorUtils.ENUM_VALUES } val valuesF = serializableIrClass.functions.single { it.name == DescriptorUtils.ENUM_VALUES }
val getValues = irInvoke(dispatchReceiver = null, callee = valuesF.symbol) val getValues = irInvoke(dispatchReceiver = null, callee = valuesF.symbol)
val arrayGet =
compilerContext.builtIns.array.getFuncDesc("get").single() val arrayGet = compilerContext.irBuiltIns.arrayClass.owner.declarations.filterIsInstance<IrSimpleFunction>()
val arrayGetSymbol = compilerContext.symbolTable.referenceFunction(arrayGet) .single { it.name.asString() == "get" }
val getValueByOrdinal = val getValueByOrdinal =
irInvoke( irInvoke(
getValues, getValues,
arrayGetSymbol, arrayGet.symbol,
irInvoke(irGet(loadFunc.valueParameters[0]), decode, serialDescGetter), irInvoke(irGet(loadFunc.valueParameters[0]), decode, serialDescGetter),
typeHint = serializableIrClass.defaultType typeHint = serializableIrClass.defaultType
) )
@@ -78,8 +83,7 @@ class SerializerForEnumsGenerator(
): IrExpression { ): IrExpression {
val serialDescForEnums = serializerDescriptor val serialDescForEnums = serializerDescriptor
.getClassFromInternalSerializationPackage(SerialEntityNames.SERIAL_DESCRIPTOR_FOR_ENUM) .getClassFromInternalSerializationPackage(SerialEntityNames.SERIAL_DESCRIPTOR_FOR_ENUM)
val ctor = val ctor = compilerContext.referenceConstructors(serialDescForEnums.fqNameSafe).single { it.owner.isPrimary }
compilerContext.symbolTable.referenceConstructor(serialDescForEnums.unsubstitutedPrimaryConstructor!!)
return irInvoke( return irInvoke(
null, ctor, null, ctor,
irString(serialName), irString(serialName),
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.common.lower.irThrow
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrAnonymousInitializerImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrBranchImpl import org.jetbrains.kotlin.ir.expressions.impl.IrBranchImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
@@ -19,12 +20,11 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.ir.util.withScope
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
@@ -43,7 +43,10 @@ object SERIALIZABLE_PLUGIN_ORIGIN : IrDeclarationOriginImpl("SERIALIZER")
open class SerializerIrGenerator(val irClass: IrClass, final override val compilerContext: SerializationPluginContext, bindingContext: BindingContext) : open class SerializerIrGenerator(val irClass: IrClass, final override val compilerContext: SerializationPluginContext, bindingContext: BindingContext) :
SerializerCodegen(irClass.descriptor, bindingContext), IrBuilderExtension { SerializerCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
protected val serializableIrClass = compilerContext.symbolTable.referenceClass(serializableDescriptor).takeIf { it.isBound }?.owner
protected val serializableIrClass = compilerContext.symbolTable.referenceClass(serializableDescriptor).owner
protected val irAnySerialDescProperty = anySerialDescProperty?.let { compilerContext.symbolTable.referenceProperty(it) }
override fun generateSerialDesc() { override fun generateSerialDesc() {
val desc: PropertyDescriptor = generatedSerialDescPropertyDescriptor ?: return val desc: PropertyDescriptor = generatedSerialDescPropertyDescriptor ?: return
@@ -56,23 +59,26 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
lateinit var prop: IrProperty lateinit var prop: IrProperty
// how to (auto)create backing field and getter/setter? // how to (auto)create backing field and getter/setter?
compilerContext.symbolTable.withScope(irClass.descriptor) { compilerContext.symbolTable.withReferenceScope(irClass.descriptor) {
introduceValueParameter(thisAsReceiverParameter) prop = generateSimplePropertyWithBackingField(thisAsReceiverParameter.symbol, desc, irClass, false)
prop = generateSimplePropertyWithBackingField(thisAsReceiverParameter.symbol, desc, irClass)
// TODO: Do not use descriptors here
localSerializersFieldsDescriptors.forEach { localSerializersFieldsDescriptors.forEach {
generateSimplePropertyWithBackingField(thisAsReceiverParameter.symbol, it, irClass) generateSimplePropertyWithBackingField(thisAsReceiverParameter.symbol, it, irClass, true)
} }
} }
compilerContext.symbolTable.declareAnonymousInitializer( val annonimousInit = irClass.run {
irClass.startOffset, irClass.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, irClass.descriptor val symbol = IrAnonymousInitializerSymbolImpl(descriptor)
).buildWithScope { initIrBody -> IrAnonymousInitializerImpl(startOffset, endOffset, SERIALIZABLE_PLUGIN_ORIGIN, symbol).also {
initIrBody.parent = irClass it.parent = this
val ctor = irClass.declarations.filterIsInstance<IrConstructor>().find { it.isPrimary } declarations.add(it)
?: throw AssertionError("Serializer must have primary constructor") }
compilerContext.symbolTable.withScope(initIrBody.descriptor) { }
annonimousInit.buildWithScope { initIrBody ->
compilerContext.symbolTable.withReferenceScope(initIrBody.descriptor) {
initIrBody.body = initIrBody.body =
DeclarationIrBuilder(compilerContext, initIrBody.symbol, initIrBody.startOffset, initIrBody.endOffset).irBlockBody { DeclarationIrBuilder(compilerContext, initIrBody.symbol, initIrBody.startOffset, initIrBody.endOffset).irBlockBody {
val localDesc = irTemporary( val localDesc = irTemporary(
@@ -83,7 +89,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
addElementsContentToDescriptor(serialDescImplClass, localDesc, addFuncS) addElementsContentToDescriptor(serialDescImplClass, localDesc, addFuncS)
// add class annotations // add class annotations
copySerialInfoAnnotationsToDescriptor( copySerialInfoAnnotationsToDescriptor(
serializableIrClass?.annotations.orEmpty(), serializableIrClass.annotations,
localDesc, localDesc,
serialDescImplClass.referenceMethod(CallingConventions.addClassAnnotation) serialDescImplClass.referenceMethod(CallingConventions.addClassAnnotation)
) )
@@ -98,7 +104,6 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
irGet(localDesc) irGet(localDesc)
) )
} }
(ctor.body as? IrBlockBody)?.statements?.addAll(initIrBody.body.statements)
} }
} }
} }
@@ -107,9 +112,8 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
serialDescImplClass: ClassDescriptor, serialDescImplClass: ClassDescriptor,
correctThis: IrExpression correctThis: IrExpression
): IrExpression { ): IrExpression {
val serialDescImplConstructor = serialDescImplClass val classConstructors = compilerContext.referenceConstructors(serialDescImplClass.fqNameSafe)
.unsubstitutedPrimaryConstructor!! val serialClassDescImplCtor = classConstructors.single { it.owner.isPrimary }
val serialClassDescImplCtor = compilerContext.symbolTable.referenceConstructor(serialDescImplConstructor)
return irInvoke( return irInvoke(
null, serialClassDescImplCtor, null, serialClassDescImplCtor,
irString(serialName), if (isGeneratedSerializer) correctThis else irNull(), irInt(serializableProperties.size) irString(serialName), if (isGeneratedSerializer) correctThis else irNull(), irInt(serializableProperties.size)
@@ -209,15 +213,16 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
/* Already implemented in .generateSerialClassDesc ? */ /* Already implemented in .generateSerialClassDesc ? */
} }
protected inline fun ClassDescriptor.referenceMethod(methodName: String, predicate: (FunctionDescriptor) -> Boolean = { true }) = protected inline fun ClassDescriptor.referenceMethod(methodName: String, predicate: (IrSimpleFunction) -> Boolean = { true }): IrFunctionSymbol {
getFuncDesc(methodName).single(predicate).let { compilerContext.symbolTable.referenceFunction(it) } val irClass = compilerContext.referenceClass(fqNameSafe)?.owner ?: error("Couldn't load class $this")
val simpleFunctions = irClass.declarations.filterIsInstance<IrSimpleFunction>()
return simpleFunctions.filter { it.name.asString() == methodName }.single { predicate(it) }.symbol
}
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc -> override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc ->
val fieldInitializer: (SerializableProperty) -> IrExpression? = val fieldInitializer: (SerializableProperty) -> IrExpression? =
buildInitializersRemapping( buildInitializersRemapping(serializableIrClass).run { { invoke(it.irField) } }
serializableIrClass ?: error("Please provide implementation of .deserialize method for external class")
).run { { invoke(it.irField) } }
fun irThis(): IrExpression = fun irThis(): IrExpression =
IrGetValueImpl(startOffset, endOffset, saveFunc.dispatchReceiverParameter!!.symbol) IrGetValueImpl(startOffset, endOffset, saveFunc.dispatchReceiverParameter!!.symbol)
@@ -225,7 +230,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
val kOutputClass = serializerDescriptor.getClassFromSerializationPackage(STRUCTURE_ENCODER_CLASS) val kOutputClass = serializerDescriptor.getClassFromSerializationPackage(STRUCTURE_ENCODER_CLASS)
val encoderClass = serializerDescriptor.getClassFromSerializationPackage(ENCODER_CLASS) val encoderClass = serializerDescriptor.getClassFromSerializationPackage(ENCODER_CLASS)
val descriptorGetterSymbol = compilerContext.symbolTable.referenceFunction(anySerialDescProperty?.getter!!) //??? val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol
val localSerialDesc = irTemporary(irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol), "desc") val localSerialDesc = irTemporary(irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol), "desc")
@@ -337,7 +342,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
val inputClass = serializerDescriptor.getClassFromSerializationPackage(STRUCTURE_DECODER_CLASS) val inputClass = serializerDescriptor.getClassFromSerializationPackage(STRUCTURE_DECODER_CLASS)
val decoderClass = serializerDescriptor.getClassFromSerializationPackage(DECODER_CLASS) val decoderClass = serializerDescriptor.getClassFromSerializationPackage(DECODER_CLASS)
val descriptorGetterSymbol = compilerContext.symbolTable.referenceFunction(anySerialDescProperty?.getter!!) //??? val descriptorGetterSymbol = irAnySerialDescProperty?.owner?.getter!!.symbol
val localSerialDesc = irTemporary(irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol), "desc") val localSerialDesc = irTemporary(irGet(descriptorGetterSymbol.owner.returnType, irThis(), descriptorGetterSymbol), "desc")
// workaround due to unavailability of labels (KT-25386) // workaround due to unavailability of labels (KT-25386)
@@ -430,10 +435,9 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
decoderCalls.forEach { (i, e) -> +IrBranchImpl(irEquals(indexVar.get(), irInt(i)), e) } decoderCalls.forEach { (i, e) -> +IrBranchImpl(irEquals(indexVar.get(), irInt(i)), e) }
// throw exception on unknown field // throw exception on unknown field
val exceptionCtor =
serializableDescriptor.getClassFromSerializationPackage(UNKNOWN_FIELD_EXC) val exceptionFqn = getSerializationPackageFqn(UNKNOWN_FIELD_EXC)
.unsubstitutedPrimaryConstructor!! val excClassRef = compilerContext.referenceConstructors(exceptionFqn).single { it.owner.isPrimary }
val excClassRef = compilerContext.symbolTable.referenceConstructor(exceptionCtor)
+elseBranch( +elseBranch(
irThrow( irThrow(
irInvoke( irInvoke(
@@ -462,9 +466,9 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
val typeArgs = (loadFunc.returnType as IrSimpleType).arguments.map { (it as IrTypeProjection).type } val typeArgs = (loadFunc.returnType as IrSimpleType).arguments.map { (it as IrTypeProjection).type }
val ctor: IrConstructorSymbol = if (serializableDescriptor.isInternalSerializable) { val ctor: IrConstructorSymbol = if (serializableDescriptor.isInternalSerializable) {
args = bitMasks.map { irGet(it) } + args + irNull() args = bitMasks.map { irGet(it) } + args + irNull()
compilerContext.symbolTable.serializableSyntheticConstructor(serializableDescriptor) serializableSyntheticConstructor(serializableIrClass)
} else { } else {
compilerContext.symbolTable.referenceConstructor(serializableDescriptor.unsubstitutedPrimaryConstructor!!) compilerContext.referenceConstructors(serializableDescriptor.fqNameSafe).single { it.owner.isPrimary }
} }
+irReturn(irInvoke(null, ctor, typeArgs, args)) +irReturn(irInvoke(null, ctor, typeArgs, args))
@@ -63,9 +63,15 @@ internal fun Annotations.findAnnotationKotlinTypeValue(
internal fun ClassDescriptor.getKSerializerConstructorMarker(): ClassDescriptor = internal fun ClassDescriptor.getKSerializerConstructorMarker(): ClassDescriptor =
module.findClassAcrossModuleDependencies(ClassId(SerializationPackages.packageFqName, SerialEntityNames.SERIAL_CTOR_MARKER_NAME))!! module.findClassAcrossModuleDependencies(ClassId(SerializationPackages.packageFqName, SerialEntityNames.SERIAL_CTOR_MARKER_NAME))!!
internal fun getInternalPackageFqn(classSimpleName: String): FqName =
SerializationPackages.internalPackageFqName.child(Name.identifier(classSimpleName))
internal fun ModuleDescriptor.getClassFromInternalSerializationPackage(classSimpleName: String) = internal fun ModuleDescriptor.getClassFromInternalSerializationPackage(classSimpleName: String) =
getFromPackage(SerializationPackages.internalPackageFqName, classSimpleName) getFromPackage(SerializationPackages.internalPackageFqName, classSimpleName)
internal fun getSerializationPackageFqn(classSimpleName: String): FqName =
SerializationPackages.packageFqName.child(Name.identifier(classSimpleName))
internal fun ModuleDescriptor.getClassFromSerializationPackage(classSimpleName: String) = internal fun ModuleDescriptor.getClassFromSerializationPackage(classSimpleName: String) =
getFromPackage(SerializationPackages.packageFqName, classSimpleName) getFromPackage(SerializationPackages.packageFqName, classSimpleName)