From 3e18350a1f4ffe295756dc68250d5d7bf78278cb Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Fri, 15 Nov 2019 18:33:46 +0300 Subject: [PATCH] Rewrite IR plugin infrastructure (and serialization plugin) so it won't emit LazyIR. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LazyIR was emitted because plugin was not able to declare symbols, only to reference them. Moreover, declarations added by frontend plugin were also unbound symbols produced by psi2ir, and declaration stub generator was stubbing them with LazyIR – therefore access to global symbol table is not enough for plugins. IrProvider won't help here, because some functions produced by plugin have circular dependencies. By moving compiler plugins step between psi2ir and declaration stub generator, both problems are resolved – unbound symbols produced by psi2ir and compiler plugins are declared where they would be declared if this was a user code, and only unbound symbols left are external dependencies, which is a correct input for lazy ir. --- .../extensions/IrGenerationExtension.kt | 23 +++-- .../kotlin/backend/common/lower/LowerUtils.kt | 6 +- .../kotlin/backend/jvm/JvmBackendFacade.kt | 25 ++++-- .../kotlin/psi2ir/Psi2IrTranslator.kt | 17 ++-- .../jetbrains/kotlin/ir/backend/js/klib.kt | 1 + .../compiler/backend/ir/GeneratorHelpers.kt | 81 +++++++++++------- .../ir/SerializableCompanionIrGenerator.kt | 15 ++-- .../backend/ir/SerializableIrGenerator.kt | 13 ++- .../backend/ir/SerializerForEnumsGenerator.kt | 21 +++-- .../backend/ir/SerializerIrGenerator.kt | 85 +++++++++---------- .../SerializationLoweringExtension.kt | 24 +++--- .../testData/codegen/Basic.ir.txt | 14 ++- .../SerializationIDECodegenExtensions.kt | 7 +- 13 files changed, 187 insertions(+), 145 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrGenerationExtension.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrGenerationExtension.kt index 3a811ff2e1d..23a99acc201 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrGenerationExtension.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrGenerationExtension.kt @@ -5,18 +5,31 @@ package org.jetbrains.kotlin.backend.common.extensions -import org.jetbrains.kotlin.backend.common.BackendContext +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor -import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.builders.IrGeneratorContext +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns +import org.jetbrains.kotlin.ir.util.SymbolTable +import org.jetbrains.kotlin.ir.util.TypeTranslator import org.jetbrains.kotlin.resolve.BindingContext +class IrPluginContext( + val moduleDescriptor: ModuleDescriptor, + val bindingContext: BindingContext, + val languageVersionSettings: LanguageVersionSettings, + val symbolTable: SymbolTable, + val typeTranslator: TypeTranslator, + override val irBuiltIns: IrBuiltIns +): IrGeneratorContext() + interface IrGenerationExtension { companion object : ProjectExtensionDescriptor("org.jetbrains.kotlin.irGenerationExtension", IrGenerationExtension::class.java) fun generate( - file: IrFile, - backendContext: BackendContext, - bindingContext: BindingContext + moduleFragment: IrModuleFragment, + pluginContext: IrPluginContext ) } \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt index 93d57bb4e7a..960c141469b 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt @@ -39,11 +39,11 @@ import org.jetbrains.kotlin.name.Name class IrLoweringContext(backendContext: BackendContext) : IrGeneratorContextBase(backendContext.irBuiltIns) class DeclarationIrBuilder( - backendContext: BackendContext, + generatorContext: IrGeneratorContext, symbol: IrSymbol, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET ) : IrBuilderWithScope( - IrLoweringContext(backendContext), + generatorContext, Scope(symbol), startOffset, endOffset @@ -73,7 +73,7 @@ fun BackendContext.createIrBuilder( startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET ) = - DeclarationIrBuilder(this, symbol, startOffset, endOffset) + DeclarationIrBuilder(IrLoweringContext(this), symbol, startOffset, endOffset) fun T.at(element: IrElement) = this.at(element.startOffset, element.endOffset) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendFacade.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendFacade.kt index a6a6f04ed43..1ac93357a56 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendFacade.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendFacade.kt @@ -6,6 +6,8 @@ package org.jetbrains.kotlin.backend.jvm import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension +import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.backend.common.ir.createParameterDeclarations import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.jvm.codegen.ClassCodegen import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry @@ -31,6 +33,23 @@ object JvmBackendFacade { val psi2ir = Psi2IrTranslator(state.languageVersionSettings) val psi2irContext = psi2ir.createGeneratorContext(state.module, state.bindingContext, extensions = JvmGeneratorExtensions) val extensions = JvmStubGeneratorExtensions() + + for (extension in IrGenerationExtension.getInstances(state.project)) { + psi2ir.addPostprocessingStep { module -> + extension.generate( + module, + IrPluginContext( + psi2irContext.moduleDescriptor, + psi2irContext.bindingContext, + psi2irContext.languageVersionSettings, + psi2irContext.symbolTable, + psi2irContext.typeTranslator, + psi2irContext.irBuiltIns + ) + ) + } + } + val irModuleFragment = psi2ir.generateModuleFragment(psi2irContext, files, stubGeneratorExtensions = extensions) doGenerateFilesInternal( state, errorHandler, irModuleFragment, psi2irContext.symbolTable, psi2irContext.sourceManager, phaseConfig, extensions @@ -65,12 +84,6 @@ object JvmBackendFacade { context.classNameOverride = extensions.classNameOverride - for (irFile in irModuleFragment.files) { - for (extension in IrGenerationExtension.getInstances(context.state.project)) { - extension.generate(irFile, context, context.state.bindingContext) - } - } - try { JvmLower(context).lower(irModuleFragment) } catch (e: Throwable) { diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt index 8cb1c52860b..f18917826e3 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt @@ -31,17 +31,15 @@ import org.jetbrains.kotlin.psi2ir.transformations.insertImplicitCasts import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.utils.SmartList +typealias Psi2IrPostprocessingStep = (IrModuleFragment) -> Unit + class Psi2IrTranslator( val languageVersionSettings: LanguageVersionSettings, val configuration: Psi2IrConfiguration = Psi2IrConfiguration() ) { - interface PostprocessingStep { - fun postprocess(context: GeneratorContext, irElement: IrElement) - } + private val postprocessingSteps = SmartList() - private val postprocessingSteps = SmartList() - - fun add(step: PostprocessingStep) { + fun addPostprocessingStep(step: Psi2IrPostprocessingStep) { postprocessingSteps.add(step) } @@ -74,20 +72,17 @@ class Psi2IrTranslator( val moduleGenerator = ModuleGenerator(context) val irModule = moduleGenerator.generateModuleFragment(ktFiles) - // This is required for implicit casts insertion on IrTypes (work-in-progress). - moduleGenerator.generateUnboundSymbolsAsDependencies(irModule, deserializer, irProviders, stubGeneratorExtensions) irModule.patchDeclarationParents() - postprocess(context, irModule) moduleGenerator.generateUnboundSymbolsAsDependencies(irModule, deserializer, irProviders, stubGeneratorExtensions) return irModule } - private fun postprocess(context: GeneratorContext, irElement: IrElement) { + private fun postprocess(context: GeneratorContext, irElement: IrModuleFragment) { insertImplicitCasts(irElement, context) generateAnnotationsForDeclarations(context, irElement) - postprocessingSteps.forEach { it.postprocess(context, irElement) } + postprocessingSteps.forEach { it(irElement) } irElement.patchDeclarationParents() } diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt index 5eaeb7ee6f2..7b11ddd7f47 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt @@ -177,6 +177,7 @@ fun loadIr( } val moduleFragment = psi2IrContext.generateModuleFragment(files, deserializer) + // todo: add postprocessing step return IrModuleInfo(moduleFragment, deserializedModuleFragments, irBuiltIns, symbolTable, deserializer) } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt index 90cc85109eb..ce8b5b50e8d 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt @@ -5,12 +5,11 @@ 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.lower.at -import org.jetbrains.kotlin.backend.common.lower.createIrBuilder +import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl @@ -27,7 +26,9 @@ import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.calls.components.isVararg import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.typeUtil.isTypeParameter @@ -37,21 +38,15 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.common.allSealedSeri import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext import org.jetbrains.kotlinx.serialization.compiler.backend.common.serialName import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.* +import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext import org.jetbrains.kotlinx.serialization.compiler.resolve.* -val BackendContext.externalSymbols: ReferenceSymbolTable get() = ir.symbols.externalSymbolTable - -internal fun BackendContext.createTypeTranslator(moduleDescriptor: ModuleDescriptor): TypeTranslator = - TypeTranslator(externalSymbols, irBuiltIns.languageVersionSettings, moduleDescriptor.builtIns).apply { - constantValueGenerator = ConstantValueGenerator(moduleDescriptor, symbolTable = externalSymbols) - constantValueGenerator.typeTranslator = this - } +val SerializationPluginContext.externalSymbols: SymbolTable get() = symbolTable // Todo: deprecate and remove +val SerializationPluginContext.localSymbolTable: SymbolTable get() = symbolTable // Todo: deprecate and remove interface IrBuilderExtension { - val compilerContext: BackendContext - val translator: TypeTranslator - - val BackendContext.localSymbolTable: SymbolTable + val compilerContext: SerializationPluginContext + val translator: TypeTranslator get() = compilerContext.typeTranslator // Todo: deprecate and remove private fun IrClass.declareSimpleFunctionWithExternalOverrides(descriptor: FunctionDescriptor): IrSimpleFunction { return compilerContext.localSymbolTable.declareSimpleFunction(startOffset, endOffset, SERIALIZABLE_PLUGIN_ORIGIN, descriptor) @@ -64,26 +59,26 @@ interface IrBuilderExtension { fun IrClass.contributeFunction( descriptor: FunctionDescriptor, - fromStubs: Boolean = false, + declareNew: Boolean = true, bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit ) { - val f: IrSimpleFunction = if (!fromStubs) declareSimpleFunctionWithExternalOverrides( + val f: IrSimpleFunction = if (declareNew) declareSimpleFunctionWithExternalOverrides( descriptor ) else compilerContext.externalSymbols.referenceSimpleFunction(descriptor).owner f.parent = this f.returnType = descriptor.returnType!!.toIrType() - if (!fromStubs) f.createParameterDeclarations(this.thisReceiver!!) - f.body = compilerContext.createIrBuilder(f.symbol).at(this).irBlockBody(this.startOffset, this.endOffset) { bodyGen(f) } + if (declareNew) f.createParameterDeclarations(this.thisReceiver!!) + f.body = DeclarationIrBuilder(compilerContext, f.symbol, this.startOffset, this.endOffset).irBlockBody(this.startOffset, this.endOffset) { bodyGen(f) } this.addMember(f) } fun IrClass.contributeConstructor( descriptor: ClassConstructorDescriptor, - fromStubs: Boolean = false, + declareNew: Boolean = true, overwriteValueParameters: Boolean = false, bodyGen: IrBlockBodyBuilder.(IrConstructor) -> Unit ) { - val c = if (!fromStubs) compilerContext.localSymbolTable.declareConstructor( + val c = if (declareNew) compilerContext.localSymbolTable.declareConstructor( this.startOffset, this.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, @@ -91,12 +86,12 @@ interface IrBuilderExtension { ) else compilerContext.externalSymbols.referenceConstructor(descriptor).owner c.parent = this c.returnType = descriptor.returnType.toIrType() - if (!fromStubs || overwriteValueParameters) c.createParameterDeclarations( + if (declareNew || overwriteValueParameters) c.createParameterDeclarations( receiver = null, overwriteValueParameters = overwriteValueParameters, copyTypeParameters = false ) - c.body = compilerContext.createIrBuilder(c.symbol).at(this).irBlockBody(this.startOffset, this.endOffset) { bodyGen(c) } + c.body = DeclarationIrBuilder(compilerContext, c.symbol, this.startOffset, this.endOffset).irBlockBody(this.startOffset, this.endOffset) { bodyGen(c) } this.addMember(c) } @@ -106,7 +101,8 @@ interface IrBuilderExtension { vararg args: IrExpression, typeHint: IrType? = null ): IrMemberAccessExpression { - val call = typeHint?.let { irCall(callee, type = it) } ?: irCall(callee) + val returnType = typeHint ?: callee.descriptor.returnType!!.toIrType() + val call = irCall(callee, type = returnType) call.dispatchReceiver = dispatchReceiver args.forEachIndexed(call::putValueArgument) return call @@ -126,25 +122,44 @@ interface IrBuilderExtension { typeHint = returnTypeHint ).also { call -> typeArguments.forEachIndexed(call::putTypeArgument) } + // todo: remove copypasta + + private fun SerializationPluginContext.builtInsPackage(vararg packageNameSegments: String) = + builtIns.builtInsModule.getPackage(FqName.fromSegments(listOf(*packageNameSegments))).memberScope + + private fun SerializationPluginContext.getSimpleFunction( + name: Name, + vararg packageNameSegments: String = arrayOf("kotlin"), + condition: (SimpleFunctionDescriptor) -> Boolean + ): IrSimpleFunctionSymbol = + symbolTable.referenceSimpleFunction( + builtInsPackage(*packageNameSegments).getContributedFunctions(name, NoLookupLocation.FROM_BACKEND) + .first(condition) + ) + + fun IrBuilderWithScope.createArrayOfExpression( arrayElementType: IrType, arrayElements: List ): IrExpression { - val arrayType = compilerContext.ir.symbols.array.typeWith(arrayElementType) + val arrayType = context.irBuiltIns.arrayClass.typeWith(arrayElementType) val arg0 = IrVarargImpl(startOffset, endOffset, arrayType, arrayElementType, arrayElements) val typeArguments = listOf(arrayElementType) - return irCall(compilerContext.ir.symbols.arrayOf, arrayType, typeArguments = typeArguments).apply { + val arrayOf = compilerContext.getSimpleFunction(Name.identifier("arrayOf")) { + it.extensionReceiverParameter == null && it.dispatchReceiverParameter == null && it.valueParameters.size == 1 && + it.valueParameters[0].isVararg + } + return irCall(arrayOf, arrayType, typeArguments = typeArguments).apply { putValueArgument(0, arg0) } } fun IrBuilderWithScope.irBinOp(name: Name, lhs: IrExpression, rhs: IrExpression): IrExpression { - val symbol = compilerContext.ir.symbols.getBinaryOperator( - name, - lhs.type.toKotlinType(), - rhs.type.toKotlinType() + val symbol = compilerContext.symbolTable.referenceSimpleFunction( + lhs.type.toKotlinType().memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND) + .first { it.valueParameters.size == 1 && it.valueParameters[0].type == rhs.type.toKotlinType() } ) return irInvoke(lhs, symbol, rhs) } @@ -271,9 +286,9 @@ interface IrBuilderExtension { descriptor: PropertyAccessorDescriptor, fieldSymbol: IrFieldSymbol ): IrSimpleFunction { - // Declaration can also be called from user code. Since we lookup descriptor getter in externalSymbols - // (see generateSave/generateLoad), seems it is correct approach to declare getter lazily there. - val declaration = compilerContext.externalSymbols.referenceSimpleFunction(descriptor).owner + val declaration = compilerContext.externalSymbols.declareSimpleFunctionWithOverrides(fieldSymbol.owner.startOffset, + fieldSymbol.owner.endOffset, + SERIALIZABLE_PLUGIN_ORIGIN,descriptor) return declaration.buildWithScope { irAccessor -> irAccessor.createParameterDeclarations(receiver = null) irAccessor.returnType = irAccessor.descriptor.returnType!!.toIrType() @@ -481,7 +496,7 @@ interface IrBuilderExtension { ): IrExpression { return if (type.isMarkedNullable) irInvoke( - null, nullableSerializerClass.constructors.toList()[0], + null, compilerContext.symbolTable.referenceConstructor(nullableSerializerClass.descriptor.constructors.toList().first()), typeArguments = listOf(type.makeNotNullable().toIrType()), valueArguments = listOf(expression), returnTypeHint = wrapIrTypeIntoKSerializerIrType(module, type.toIrType()) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableCompanionIrGenerator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableCompanionIrGenerator.kt index 3d249e26cd6..af69f3ce4e6 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableCompanionIrGenerator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableCompanionIrGenerator.kt @@ -21,22 +21,19 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer +import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext import org.jetbrains.kotlinx.serialization.compiler.resolve.* class SerializableCompanionIrGenerator( val irClass: IrClass, - override val compilerContext: BackendContext, + override val compilerContext: SerializationPluginContext, bindingContext: BindingContext ) : SerializableCompanionCodegen(irClass.descriptor, bindingContext), IrBuilderExtension { - override val translator: TypeTranslator = compilerContext.createTypeTranslator(serializableDescriptor.module) - private val _table = SymbolTable() - override val BackendContext.localSymbolTable: SymbolTable - get() = _table companion object { fun generate( irClass: IrClass, - context: BackendContext, + context: SerializationPluginContext, bindingContext: BindingContext ) { val companionDescriptor = irClass.descriptor @@ -63,9 +60,9 @@ class SerializableCompanionIrGenerator( compilerContext.externalSymbols.referenceConstructor(it) }) - val annotationType = compilerContext.externalSymbols.referenceClass(annotationMarkerClass).owner.defaultType + val annotationType = annotationMarkerClass.defaultType.toIrType() val irSerializableClass = compilerContext.externalSymbols.referenceClass(serializableDescriptor).owner - val annotationCtorCall = IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, annotationType, annotationCtor, annotationMarkerClass.declaredTypeParameters.size).apply { + val annotationCtorCall = IrConstructorCallImpl.fromSymbolDescriptor(startOffset, endOffset, annotationType, annotationCtor).apply { val serializerType = serializer.toSimpleType(false) putValueArgument( 0, @@ -81,7 +78,7 @@ class SerializableCompanionIrGenerator( } override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) = - irClass.contributeFunction(methodDescriptor, fromStubs = true) { getter -> + irClass.contributeFunction(methodDescriptor) { getter -> val serializer = requireNotNull( findTypeSerializer( serializableDescriptor.module, diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableIrGenerator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableIrGenerator.kt index 37066c3f5ca..5ae986c727a 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableIrGenerator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableIrGenerator.kt @@ -28,21 +28,18 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless +import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.MISSING_FIELD_EXC class SerializableIrGenerator( val irClass: IrClass, - override val compilerContext: BackendContext, + override val compilerContext: SerializationPluginContext, bindingContext: BindingContext ) : SerializableCodegen(irClass.descriptor, bindingContext), IrBuilderExtension { - override val translator: TypeTranslator = compilerContext.createTypeTranslator(serializableDescriptor.module) - private val _table = SymbolTable() - override val BackendContext.localSymbolTable: SymbolTable - get() = _table override fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor) = - irClass.contributeConstructor(constructorDescriptor, fromStubs = true, overwriteValueParameters = true) { ctor -> + irClass.contributeConstructor(constructorDescriptor, overwriteValueParameters = true) { ctor -> val transformFieldInitializer = buildInitializersRemapping(irClass) // Missing field exception parts @@ -50,7 +47,7 @@ class SerializableIrGenerator( serializableDescriptor.getClassFromSerializationPackage(MISSING_FIELD_EXC) .unsubstitutedPrimaryConstructor!! val exceptionCtorRef = compilerContext.externalSymbols.referenceConstructor(exceptionCtor) - val exceptionType = exceptionCtorRef.owner.returnType + val exceptionType = exceptionCtor.returnType.toIrType() val serializableProperties = properties.serializableProperties val seenVarsOffset = serializableProperties.bitMaskSlotCount() @@ -166,7 +163,7 @@ class SerializableIrGenerator( companion object { fun generate( irClass: IrClass, - context: BackendContext, + context: SerializationPluginContext, bindingContext: BindingContext ) { val serializableClass = irClass.descriptor diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerForEnumsGenerator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerForEnumsGenerator.kt index ac70d49fc6b..5b169750f9e 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerForEnumsGenerator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerForEnumsGenerator.kt @@ -5,9 +5,9 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.ir -import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrVariable @@ -20,9 +20,14 @@ import org.jetbrains.kotlin.ir.util.referenceFunction import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext import org.jetbrains.kotlinx.serialization.compiler.resolve.* -class SerializerForEnumsGenerator(irClass: IrClass, compilerContext: BackendContext, bindingContext: BindingContext) : +class SerializerForEnumsGenerator( + irClass: IrClass, + compilerContext: SerializationPluginContext, + bindingContext: BindingContext +) : SerializerIrGenerator(irClass, compilerContext, bindingContext) { override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc -> @@ -53,9 +58,13 @@ class SerializerForEnumsGenerator(irClass: IrClass, compilerContext: BackendCont val getValues = irInvoke(dispatchReceiver = null, callee = valuesF.symbol) val arrayGet = - compilerContext.ir.symbols.array.owner.functions.single { it.name == Name.identifier("get") }.symbol + compilerContext.builtIns.array.unsubstitutedMemberScope.getContributedFunctions( + Name.identifier("get"), + NoLookupLocation.FROM_BACKEND + ).single() + val arrayGetSymbol = compilerContext.externalSymbols.referenceFunction(arrayGet) val getValueByOrdinal = - irInvoke(getValues, arrayGet, irInvoke(irGet(loadFunc.valueParameters[0]), decode, serialDescGetter)) + irInvoke(getValues, arrayGetSymbol, irInvoke(irGet(loadFunc.valueParameters[0]), decode, serialDescGetter)) +irReturn(getValueByOrdinal) } @@ -70,7 +79,7 @@ class SerializerForEnumsGenerator(irClass: IrClass, compilerContext: BackendCont return irInvoke( null, ctor, irString(serialName), - typeHint = ctor.owner.returnType + typeHint = ctor.descriptor.returnType.toIrType() ) } @@ -93,7 +102,7 @@ class SerializerForEnumsGenerator(irClass: IrClass, compilerContext: BackendCont +call // serialDesc.pushAnnotation(...) copySerialInfoAnnotationsToDescriptor( - compilerContext.externalSymbols.referenceClass(entry).owner.annotations, + entry.annotations.mapNotNull(compilerContext.typeTranslator.constantValueGenerator::generateAnnotationConstructorCall), localDescriptor, serialDescImplClass.referenceMethod(CallingConventions.addAnnotation) ) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt index 4c637d0a415..e0d23d54fdb 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt @@ -5,9 +5,8 @@ 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.lower.createIrBuilder +import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder import org.jetbrains.kotlin.backend.common.lower.irIfThen import org.jetbrains.kotlin.backend.common.lower.irThrow import org.jetbrains.kotlin.descriptors.* @@ -25,6 +24,7 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo +import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.DECODER_CLASS import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENCODER_CLASS @@ -36,14 +36,8 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.UN // Is creating synthetic origin is a good idea or not? object SERIALIZABLE_PLUGIN_ORIGIN : IrDeclarationOriginImpl("SERIALIZER") -open class SerializerIrGenerator(val irClass: IrClass, final override val compilerContext: BackendContext, bindingContext: BindingContext) : +open class SerializerIrGenerator(val irClass: IrClass, final override val compilerContext: SerializationPluginContext, bindingContext: BindingContext) : SerializerCodegen(irClass.descriptor, bindingContext), IrBuilderExtension { - - final override val translator: TypeTranslator = compilerContext.createTypeTranslator(serializableDescriptor.module) - private val _table = SymbolTable() - final override val BackendContext.localSymbolTable: SymbolTable - get() = _table - protected val serializableIrClass = compilerContext.externalSymbols.referenceClass(serializableDescriptor).owner override fun generateSerialDesc() { @@ -75,30 +69,31 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil val ctor = irClass.declarations.filterIsInstance().find { it.isPrimary } ?: throw AssertionError("Serializer must have primary constructor") compilerContext.localSymbolTable.withScope(initIrBody.descriptor) { - initIrBody.body = compilerContext.createIrBuilder(initIrBody.symbol).irBlockBody { - val localDesc = irTemporary( - instantiateNewDescriptor(serialDescImplClass, irGet(thisAsReceiverParameter)), - nameHint = "serialDesc" - ) + initIrBody.body = + DeclarationIrBuilder(compilerContext, initIrBody.symbol, initIrBody.startOffset, initIrBody.endOffset).irBlockBody { + val localDesc = irTemporary( + instantiateNewDescriptor(serialDescImplClass, irGet(thisAsReceiverParameter)), + nameHint = "serialDesc" + ) - addElementsContentToDescriptor(serialDescImplClass, localDesc, addFuncS) - // add class annotations - copySerialInfoAnnotationsToDescriptor( - serializableIrClass.annotations, - localDesc, - serialDescImplClass.referenceMethod(CallingConventions.addClassAnnotation) - ) + addElementsContentToDescriptor(serialDescImplClass, localDesc, addFuncS) + // add class annotations + copySerialInfoAnnotationsToDescriptor( + serializableIrClass.annotations, + localDesc, + serialDescImplClass.referenceMethod(CallingConventions.addClassAnnotation) + ) - // save local descriptor to field - +irSetField( - generateReceiverExpressionForFieldAccess( - thisAsReceiverParameter.symbol, - generatedSerialDescPropertyDescriptor - ), - prop.backingField!!, - irGet(localDesc) - ) - } + // save local descriptor to field + +irSetField( + generateReceiverExpressionForFieldAccess( + thisAsReceiverParameter.symbol, + generatedSerialDescPropertyDescriptor + ), + prop.backingField!!, + irGet(localDesc) + ) + } (ctor.body as? IrBlockBody)?.statements?.addAll(initIrBody.body.statements) } } @@ -113,8 +108,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil val serialClassDescImplCtor = compilerContext.externalSymbols.referenceConstructor(serialDescImplConstructor) return irInvoke( null, serialClassDescImplCtor, - irString(serialName), if (isGeneratedSerializer) correctThis else irNull(), - typeHint = serialClassDescImplCtor.owner.returnType + irString(serialName), if (isGeneratedSerializer) correctThis else irNull() ) } @@ -155,7 +149,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil } override fun generateGenericFieldsAndConstructor(typedConstructorDescriptor: ClassConstructorDescriptor) = - irClass.contributeConstructor(typedConstructorDescriptor, fromStubs = true) { ctor -> + irClass.contributeConstructor(typedConstructorDescriptor) { ctor -> // generate call to primary ctor to init serialClassDesc and super() val primaryCtor = irClass.constructors.find { it.isPrimary } ?: throw AssertionError("Serializer class must have primary constructor") @@ -183,9 +177,11 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil } - override fun generateChildSerializersGetter(function: FunctionDescriptor) = irClass.contributeFunction(function, fromStubs = true) { irFun -> - val allSerializers = serializableProperties.map { requireNotNull( - serializerTower(this@SerializerIrGenerator, irFun.dispatchReceiverParameter!!, it)) { "Property ${it.name} must have a serializer" } + override fun generateChildSerializersGetter(function: FunctionDescriptor) = irClass.contributeFunction(function) { irFun -> + val allSerializers = serializableProperties.map { + requireNotNull( + serializerTower(this@SerializerIrGenerator, irFun.dispatchReceiverParameter!!, it) + ) { "Property ${it.name} must have a serializer" } } val kSerType = ((irFun.returnType as IrSimpleType).arguments.first() as IrTypeProjection).type @@ -200,7 +196,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil protected fun ClassDescriptor.referenceMethod(methodName: String) = getFuncDesc(methodName).single().let { compilerContext.externalSymbols.referenceFunction(it) } - override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function, fromStubs = true) { saveFunc -> + override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc -> val fieldInitializer: (SerializableProperty) -> IrExpression? = buildInitializersRemapping(serializableIrClass).run { { invoke(it.irField) } } @@ -218,7 +214,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil // fun beginStructure(desc: SerialDescriptor, vararg typeParams: KSerializer<*>): StructureEncoder val beginFunc = kOutputSmallClass.referenceMethod(CallingConventions.begin) // todo: retrieve from actual encoder instead - val call = irCall(beginFunc).mapValueParametersIndexed { i, parameterDescriptor -> + val call = irCall(beginFunc, type = beginFunc.descriptor.returnType!!.toIrType()).mapValueParametersIndexed { i, parameterDescriptor -> if (i == 0) irGet(localSerialDesc) else IrVarargImpl( startOffset, endOffset, @@ -269,7 +265,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil property.irGet() ) } - val typeArgs = if (writeFunc.owner.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf() + val typeArgs = if (writeFunc.descriptor.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf() val elementCall = irInvoke(irGet(localOutput), writeFunc, typeArguments = typeArgs, valueArguments = args) // check for call to .shouldEncodeElementDefault @@ -316,7 +312,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil defaultPrimitive to kType } - override fun generateLoad(function: FunctionDescriptor) = irClass.contributeFunction(function, fromStubs = true) { loadFunc -> + override fun generateLoad(function: FunctionDescriptor) = irClass.contributeFunction(function) { loadFunc -> if (serializableDescriptor.modality == Modality.ABSTRACT || serializableDescriptor.modality == Modality.SEALED) { return@contributeFunction } @@ -393,7 +389,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil inputClass.referenceMethod(it) } val typeArgs = - if (decodeFuncToCall.owner.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf() + if (decodeFuncToCall.descriptor.typeParameters.isNotEmpty()) listOf(property.type.toIrType()) else listOf() val args = mutableListOf(localSerialDesc.get(), irInt(index)) if (innerSerial != null) args.add(innerSerial) @@ -421,8 +417,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil irInvoke( null, excClassRef, - indexVar.get(), - typeHint = excClassRef.owner.returnType + indexVar.get() ) ) ) @@ -454,7 +449,7 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil companion object { fun generate( irClass: IrClass, - context: BackendContext, + context: SerializationPluginContext, bindingContext: BindingContext ) { val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationLoweringExtension.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationLoweringExtension.kt index 67762af8a26..3234d0d81b1 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationLoweringExtension.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationLoweringExtension.kt @@ -5,18 +5,18 @@ package org.jetbrains.kotlinx.serialization.compiler.extensions -import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.backend.common.ClassLoweringPass +import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid -import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializableCompanionIrGenerator import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializableIrGenerator import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializerIrGenerator @@ -37,24 +37,26 @@ fun ClassLoweringPass.runOnFileInOrder(irFile: IrFile) { }) } +typealias SerializationPluginContext = IrPluginContext + private class SerializerClassLowering( - val context: BackendContext, - val bindingContext: BindingContext + val context: SerializationPluginContext ) : IrElementTransformerVoid(), ClassLoweringPass { override fun lower(irClass: IrClass) { - SerializableIrGenerator.generate(irClass, context, bindingContext) - SerializerIrGenerator.generate(irClass, context, bindingContext) - SerializableCompanionIrGenerator.generate(irClass, context, bindingContext) + SerializableIrGenerator.generate(irClass, context, context.bindingContext) + SerializerIrGenerator.generate(irClass, context, context.bindingContext) + SerializableCompanionIrGenerator.generate(irClass, context, context.bindingContext) } } open class SerializationLoweringExtension : IrGenerationExtension { override fun generate( - file: IrFile, - backendContext: BackendContext, - bindingContext: BindingContext + moduleFragment: IrModuleFragment, + pluginContext: IrPluginContext ) { - SerializerClassLowering(backendContext, bindingContext).runOnFileInOrder(file) + val serializerClassLowering = SerializerClassLowering(pluginContext) + for (file in moduleFragment.files) + serializerClassLowering.runOnFileInOrder(file) } } \ No newline at end of file diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen/Basic.ir.txt b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen/Basic.ir.txt index 5934b23bc41..1749899ee82 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen/Basic.ir.txt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/testData/codegen/Basic.ir.txt @@ -186,8 +186,10 @@ public final class ListOfUsers$$serializer : java/lang/Object, kotlinx/serializa ALOAD (4) ALOAD (3) INVOKEINTERFACE (kotlinx/serialization/CompositeEncoder, endStructure, (Lkotlinx/serialization/SerialDescriptor;)V) - RETURN LABEL (L2) + LINENUMBER (13) + RETURN + LABEL (L3) } public void serialize(kotlinx.serialization.Encoder p0, java.lang.Object p1) { @@ -487,8 +489,10 @@ public final class OptionalUser$$serializer : java/lang/Object, kotlinx/serializ ALOAD (4) ALOAD (3) INVOKEINTERFACE (kotlinx/serialization/CompositeEncoder, endStructure, (Lkotlinx/serialization/SerialDescriptor;)V) - RETURN LABEL (L7) + LINENUMBER (10) + RETURN + LABEL (L8) } public void serialize(kotlinx.serialization.Encoder p0, java.lang.Object p1) { @@ -829,8 +833,10 @@ public final class User$$serializer : java/lang/Object, kotlinx/serialization/in ALOAD (4) ALOAD (3) INVOKEINTERFACE (kotlinx/serialization/CompositeEncoder, endStructure, (Lkotlinx/serialization/SerialDescriptor;)V) - RETURN LABEL (L2) + LINENUMBER (7) + RETURN + LABEL (L3) } public void serialize(kotlinx.serialization.Encoder p0, java.lang.Object p1) { @@ -957,4 +963,4 @@ public final class User : java/lang/Object { public final java.lang.String getFirstName() public final java.lang.String getLastName() -} +} \ No newline at end of file diff --git a/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationIDECodegenExtensions.kt b/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationIDECodegenExtensions.kt index f56b83420d5..8467edf5a4d 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationIDECodegenExtensions.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationIDECodegenExtensions.kt @@ -5,14 +5,13 @@ package org.jetbrains.kotlinx.serialization.compiler.extensions -import org.jetbrains.kotlin.backend.common.BackendContext +import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor import org.jetbrains.kotlin.psi.KtPureClassOrObject -import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlinx.serialization.idea.runIfEnabledOn class SerializationIDECodegenExtension : SerializationCodegenExtension() { @@ -32,7 +31,7 @@ class SerializationIDEJsExtension : SerializationJsExtension() { } class SerializationIDEIrExtension : SerializationLoweringExtension() { - override fun generate(file: IrFile, backendContext: BackendContext, bindingContext: BindingContext) { + override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) { /* No-op – don't enable IR extensions in IDE */ } } \ No newline at end of file