Introduce @FirIncompatiblePluginApi

This commit is contained in:
Leonid Startsev
2022-07-22 20:29:46 +02:00
committed by Space
parent 467ff30aac
commit 89329a0e1b
15 changed files with 62 additions and 98 deletions
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.android.synthetic.descriptors.ContainerOptionsProxy
import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticFunction
import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticProperty
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.extensions.FirIncompatiblePluginAPI
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.ir.addDispatchReceiver
@@ -120,7 +121,7 @@ private class AndroidIrTransformer(val extension: AndroidIrExtension, val plugin
}
// NOTE: sparse array version intentionally not implemented; this plugin is deprecated
@Suppress("DEPRECATION") // TODO: check that it still works with FIR
@OptIn(FirIncompatiblePluginAPI::class) // TODO: check that it still works with FIR
private val mapFactory = pluginContext.referenceFunctions(FqName("kotlin.collections.mutableMapOf"))
.single { it.owner.valueParameters.isEmpty() }
private val mapGet = pluginContext.irBuiltIns.mapClass.owner.functions
@@ -22,12 +22,10 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotat
import org.jetbrains.kotlinx.serialization.compiler.resolve.isKSerializer
import org.jetbrains.kotlinx.serialization.compiler.resolve.toClassDescriptor
const val K2_ERR_MESSAGE = "K2 not supported yet.\nBindingContext is null, meaning this function is used from the K2 compiler. Please report to devs so we can support this feature."
abstract class AbstractSerialGenerator(val bindingContext: BindingContext?, val currentDeclaration: ClassDescriptor) {
private fun getKClassListFromFileAnnotation(annotationFqName: FqName, declarationInFile: DeclarationDescriptor): List<KotlinType> {
if (bindingContext == null) return emptyList()// TODO
if (bindingContext == null) return emptyList() // TODO: support @UseSerializers in FIR
val annotation = AnnotationsUtils
.getContainingFileAnnotations(bindingContext, declarationInFile)
.find { it.fqName == annotationFqName }
@@ -16,7 +16,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.*
abstract class SerializableCodegen(
protected val serializableDescriptor: ClassDescriptor,
bindingContext: BindingContext?
bindingContext: BindingContext
) : AbstractSerialGenerator(bindingContext, serializableDescriptor) {
protected val properties = bindingContext.serializablePropertiesFor(serializableDescriptor)
@@ -16,7 +16,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.*
abstract class SerializerCodegen(
protected val serializerDescriptor: ClassDescriptor,
bindingContext: BindingContext?,
bindingContext: BindingContext,
metadataPlugin: SerializationDescriptorSerializerPlugin?
) : AbstractSerialGenerator(bindingContext, serializerDescriptor) {
val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!!
@@ -5,6 +5,7 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.extensions.FirIncompatiblePluginAPI
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
import org.jetbrains.kotlin.ir.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.lower.irIfThen
@@ -24,7 +25,6 @@ import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.backend.jvm.ir.representativeUpperBound
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.name.CallableId
@@ -33,22 +33,17 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.psi
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.*
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.typeConstructor
import org.jetbrains.kotlin.types.model.dependsOnTypeConstructor
import org.jetbrains.kotlin.types.typeUtil.*
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.*
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies.FUNCTION0_FQ
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies.LAZY_FQ
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies.LAZY_FUNC_FQ
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies.LAZY_MODE_FQ
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies.LAZY_PUBLICATION_MODE_NAME
@@ -320,23 +315,13 @@ interface IrBuilderExtension {
result
)
@Deprecated("", level = DeprecationLevel.ERROR)
@FirIncompatiblePluginAPI
fun KotlinType.toIrType() = compilerContext.typeTranslator.translateType(this)
// note: this method should be used only for properties from current module. Fields from other modules are private and inaccessible.
val IrSerializableProperty.irField: IrField?
get() = this.descriptor.backingField
fun IrClass.searchForProperty(descriptor: PropertyDescriptor): IrProperty {
// this API is used to reference both current module descriptors and external ones (because serializable class can be in any of them),
// so we use descriptor api for current module because it is not possible to obtain FQname for e.g. local classes.
return searchForDeclaration(descriptor) ?: if (descriptor.module == compilerContext.moduleDescriptor) {
compilerContext.symbolTable.referenceProperty(descriptor).owner
} else {
@Suppress("DEPRECATION")
compilerContext.referenceProperties(descriptor.fqNameSafe).single().owner
}
}
@@ -347,8 +332,7 @@ interface IrBuilderExtension {
fun IrBuilderWithScope.createPropertyByParamReplacer(
irClass: IrClass,
serialProperties: List<IrSerializableProperty>,
instance: IrValueParameter,
bindingContext: BindingContext?
instance: IrValueParameter
): (ValueParameterDescriptor) -> IrExpression? {
fun IrSerializableProperty.irGet(): IrExpression {
val ownerType = instance.symbol.owner.type
@@ -532,7 +516,7 @@ interface IrBuilderExtension {
val field = with(propertyDescriptor) {
// TODO: type parameters
@Suppress("DEPRECATION_ERROR") // should be called only with old FE
@OptIn(FirIncompatiblePluginAPI::class)// should be called only with old FE
originProperty.factory.createField(
originProperty.startOffset, originProperty.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrFieldSymbolImpl(propertyDescriptor), name, type.toIrType(),
visibility, !isVar, isEffectivelyExternal(), dispatchReceiverParameter == null
@@ -558,7 +542,7 @@ interface IrBuilderExtension {
false -> searchForDeclaration<IrProperty>(propertyDescriptor)?.setter
} ?: run {
with(descriptor) {
@Suppress("DEPRECATION_ERROR") // should never be called after FIR frontend
@OptIn(FirIncompatiblePluginAPI::class) // should never be called after FIR frontend
property.factory.createFunction(
fieldSymbol.owner.startOffset, fieldSymbol.owner.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrSimpleFunctionSymbolImpl(descriptor),
name, visibility, modality, returnType!!.toIrType(),
@@ -567,7 +551,7 @@ interface IrBuilderExtension {
}.also { f ->
generateOverriddenFunctionSymbols(f, compilerContext.symbolTable)
f.createParameterDeclarations(descriptor)
@Suppress("DEPRECATION_ERROR") // should never be called after FIR frontend
@OptIn(FirIncompatiblePluginAPI::class) // should never be called after FIR frontend
f.returnType = descriptor.returnType!!.toIrType()
f.correspondingPropertySymbol = fieldSymbol.owner.correspondingPropertySymbol
}
@@ -662,7 +646,7 @@ interface IrBuilderExtension {
) {
val function = this
fun irValueParameter(descriptor: ParameterDescriptor): IrValueParameter = with(descriptor) {
@Suppress("DEPRECATION_ERROR") // should never be called after FIR frontend
@OptIn(FirIncompatiblePluginAPI::class) // should never be called after FIR frontend
factory.createValueParameter(
function.startOffset, function.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrValueParameterSymbolImpl(this),
name, indexOrMinusOne, type.toIrType(), varargElementType?.toIrType(), isCrossinline, isNoinline,
@@ -697,7 +681,7 @@ interface IrBuilderExtension {
typeParameter.parent = this
}
}
@Suppress("DEPRECATION_ERROR") // should never be called after FIR frontend
@OptIn(FirIncompatiblePluginAPI::class) // should never be called after FIR frontend
newTypeParameters.forEach { typeParameter ->
typeParameter.superTypes = typeParameter.descriptor.upperBounds.map { it.toIrType() }
}
@@ -867,13 +851,6 @@ interface IrBuilderExtension {
expression
}
// private fun IrBuilderWithScope.wrapWithNullableSerializerIfNeeded(
// type: KotlinType,
// expression: IrExpression,
// nullableProp: IrPropertySymbol
// ): IrExpression = wrapWithNullableSerializerIfNeeded(type.toIrType(), expression, nullableProp)
fun wrapIrTypeIntoKSerializerIrType(
type: IrType,
variance: Variance = Variance.INVARIANT
@@ -5,6 +5,7 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.extensions.FirIncompatiblePluginAPI
import org.jetbrains.kotlin.backend.common.ir.addExtensionReceiver
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
@@ -55,7 +56,7 @@ class SerialInfoImplJvmIrGenerator(
fun getImplClass(serialInfoAnnotationClass: IrClass): IrClass =
annotationToImpl.getOrPut(serialInfoAnnotationClass) {
@Suppress("DEPRECATION") // TODO
@OptIn(FirIncompatiblePluginAPI::class) // TODO
val implClassSymbol = context.referenceClass(serialInfoAnnotationClass.kotlinFqName.child(SerialEntityNames.IMPL_NAME))
implClassSymbol!!.owner.apply(this::generate)
}
@@ -36,10 +36,10 @@ class SerializableCompanionIrGenerator(
override val compilerContext: SerializationPluginContext,
) : SerializableCompanionCodegen(irClass.descriptor, null), IrBuilderExtension {
override fun getSerializerGetterDescriptor(): FunctionDescriptor { // todo: remove .toKotlinType()
override fun getSerializerGetterDescriptor(): FunctionDescriptor {
return irClass.findDeclaration<IrSimpleFunction> {
(it.valueParameters.size == serializableDescriptor.declaredTypeParameters.size
&& it.valueParameters.all { p -> isKSerializer(p.type.toKotlinType()) }) && isKSerializer(it.returnType.toKotlinType())
&& it.valueParameters.all { p -> isKSerializer(p.type) }) && isKSerializer(it.returnType)
}?.descriptor ?: throw IllegalStateException(
"Can't find synthesized 'Companion.serializer()' function to generate, " +
"probably clash with user-defined function has occurred"
@@ -8,7 +8,6 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.ir
import org.jetbrains.kotlin.backend.common.lower.irThrow
import org.jetbrains.kotlin.codegen.CompilationException
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
@@ -22,13 +21,7 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.descriptorUtil.secondaryConstructors
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd
import org.jetbrains.kotlin.utils.getOrPutNullable
import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
import org.jetbrains.kotlinx.serialization.compiler.backend.common.isStaticSerializable
@@ -75,7 +68,7 @@ class SerializableIrGenerator(
val serialDescs = serializableProperties.map { it.descriptor }.toSet()
val propertyByParamReplacer: (ValueParameterDescriptor) -> IrExpression? =
createPropertyByParamReplacer(irClass, serializableProperties, thiz, bindingContext)
createPropertyByParamReplacer(irClass, serializableProperties, thiz)
val initializerAdapter: (IrExpressionBody) -> IrExpression = createInitializerAdapter(irClass, propertyByParamReplacer)
@@ -196,9 +189,6 @@ class SerializableIrGenerator(
private fun IrBlockBodyBuilder.getStaticSerialDescriptorExpr(): IrExpression {
val serializerIrClass = irClass.classSerializer(compilerContext)!!.owner
// internally generated serializer always declared inside serializable class
// val serializerIrClass = irClass.declarations
// .filterIsInstanceAnd<IrClass> { it.name == serializer.name }
// .singleOrNull() ?: throw Exception("No class with name ${serializer.fqNameSafe}")
val serialDescriptorGetter =
serializerIrClass.getPropertyGetter(SERIAL_DESC_FIELD)!!
@@ -282,7 +272,7 @@ class SerializableIrGenerator(
): Int {
check(superClass.isInternalSerializable)
val superCtorRef = serializableSyntheticConstructor(superClass)!!
val superProperties = bindingContext.serializablePropertiesFor(superClass.descriptor).serializableProperties
val superProperties = bindingContext.serializablePropertiesForIrBackend(superClass).serializableProperties
val superSlots = superProperties.bitMaskSlotCount()
val arguments = allValueParameters.subList(0, superSlots) +
allValueParameters.subList(propertiesStart, propertiesStart + superProperties.size) +
@@ -308,7 +298,7 @@ class SerializableIrGenerator(
val kOutputClass = compilerContext.getClassFromRuntime(SerialEntityNames.STRUCTURE_ENCODER_CLASS)
val propertyByParamReplacer: (ValueParameterDescriptor) -> IrExpression? =
createPropertyByParamReplacer(irClass, serializableProperties, objectToSerialize, bindingContext)
createPropertyByParamReplacer(irClass, serializableProperties, objectToSerialize)
// Since writeSelf is a static method, we have to replace all references to this in property initializers
val thisSymbol = irClass.thisReceiver!!.symbol
@@ -319,7 +309,7 @@ class SerializableIrGenerator(
var ignoreIndexTo = -1
val superClass = irClass.getSuperClassOrAny()
if (superClass.descriptor.isInternalSerializable) {
ignoreIndexTo = bindingContext.serializablePropertiesFor(superClass.descriptor).size
ignoreIndexTo = bindingContext.serializablePropertiesForIrBackend(superClass).serializableProperties.size
// call super.writeSelf
var superWriteSelfF = superClass.findWriteSelfMethod()
@@ -293,7 +293,7 @@ open class SerializerIrGenerator(
+irInvoke(null, writeSelfFunction.symbol, typeArgs, args)
} else {
val propertyByParamReplacer: (ValueParameterDescriptor) -> IrExpression? =
createPropertyByParamReplacer(serializableIrClass, serializableProperties, objectToSerialize, bindingContext)
createPropertyByParamReplacer(serializableIrClass, serializableProperties, objectToSerialize)
val thisSymbol = serializableIrClass.thisReceiver!!.symbol
val initializerAdapter: (IrExpressionBody) -> IrExpression =
@@ -143,7 +143,7 @@ class SerializableJsTranslator(
): Int {
val constrDesc = superClass.constructors.single(ClassConstructorDescriptor::isSerializationCtor)
val constrRef = context.getInnerNameForDescriptor(constrDesc).makeRef()
val superProperties = bindingContext.serializablePropertiesFor(superClass).serializableProperties
val superProperties = bindingContext!!.serializablePropertiesFor(superClass).serializableProperties
val superSlots = superProperties.bitMaskSlotCount()
val arguments = parameters.subList(0, superSlots) +
parameters.subList(propertiesStart, propertiesStart + superProperties.size) +
@@ -93,7 +93,7 @@ class SerializableCodegenImpl(
val superClass = serializableDescriptor.getSuperClassOrAny()
val myPropsStart: Int
if (superClass.isInternalSerializable) {
myPropsStart = bindingContext.serializablePropertiesFor(superClass).serializableProperties.size
myPropsStart = bindingContext!!.serializablePropertiesFor(superClass).serializableProperties.size
val superTypeArguments =
serializableDescriptor.typeConstructor.supertypes.single { it.toClassDescriptor?.isInternalSerializable == true }.arguments
//super.writeSelf(output, serialDesc)
@@ -293,7 +293,7 @@ class SerializableCodegenImpl(
invokespecial(superType, "<init>", desc, false)
return 0 to propStartVar
} else {
val superProps = bindingContext.serializablePropertiesFor(superClass).serializableProperties
val superProps = bindingContext!!.serializablePropertiesFor(superClass).serializableProperties
val creator = buildInternalConstructorDesc(propStartVar, maskVar, classCodegen, superProps)
invokespecial(superType, "<init>", creator, false)
return superProps.size to propStartVar + superProps.sumOf { it.asmType.size }
@@ -42,7 +42,7 @@ interface ISerializableProperties<D, T, S : ISerializableProperty<D, T>> {
val serializableStandaloneProperties: List<S>
}
class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext?) :
class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) :
ISerializableProperties<PropertyDescriptor, KotlinType, SerializableProperty> {
private val primaryConstructorParameters: List<ValueParameterDescriptor> =
serializableClass.unsubstitutedPrimaryConstructor?.valueParameters ?: emptyList()
@@ -55,15 +55,9 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
val descriptorsSequence = serializableClass.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES)
.asSequence()
// call to any BindingContext.get should be only AFTER MemberScope.getContributedDescriptors
// TODO: fix binding context shit
primaryConstructorProperties =
primaryConstructorParameters.asSequence()
.map { parameter ->
bindingContext?.get(
BindingContext.VALUE_PARAMETER_AS_PROPERTY,
parameter
) to parameter.declaresDefaultValue()
}
.map { parameter -> bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter] to parameter.declaresDefaultValue() }
.mapNotNull { (a, b) -> if (a == null) null else a to b }
.toMap()
@@ -84,8 +78,7 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
prop.hasBackingField(bindingContext) || (prop is DeserializedPropertyDescriptor && prop.backingField != null) // workaround for TODO in .hasBackingField
// workaround for overridden getter (val) and getter+setter (var) - in this case hasBackingField returning false
// but initializer presents only for property with backing field
|| declaresDefaultValue
|| prop.backingField != null, // todo: find out what happens next
|| declaresDefaultValue,
declaresDefaultValue
)
}
@@ -172,11 +165,8 @@ internal val ISerializableProperties<*, *, *>.goldenMaskList: List<Int>
internal fun List<ISerializableProperty<*, *>>.bitMaskSlotCount() = size / 32 + 1
internal fun bitMaskSlotAt(propertyIndex: Int) = propertyIndex / 32
internal fun BindingContext?.serializablePropertiesFor(
classDescriptor: ClassDescriptor,
serializationDescriptorSerializer: SerializationDescriptorSerializerPlugin? = null
): SerializableProperties {
val props = this?.get(SERIALIZABLE_PROPERTIES, classDescriptor) ?: SerializableProperties(classDescriptor, this)
internal fun BindingContext.serializablePropertiesFor(classDescriptor: ClassDescriptor, serializationDescriptorSerializer: SerializationDescriptorSerializerPlugin? = null): SerializableProperties {
val props = this.get(SERIALIZABLE_PROPERTIES, classDescriptor) ?: SerializableProperties(classDescriptor, this)
serializationDescriptorSerializer?.putIfNeeded(classDescriptor, props)
return props
}