I've created compiler plugin that in IR phase add ...
# compiler
p
I've created compiler plugin that in IR phase add secondary constructor for those two classes. Part of code related to constructor creation: val c = klass.addConstructor { visibility = Visibilities.PUBLIC } c.addValueParameter { this.index = 0 this.name = Name.identifier("stub") this.type = pluginContext.irBuiltIns.unitType } c.body = IrBlockBodyImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, listOf( IrDelegatingConstructorCallImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, superConstructor.returnType, superConstructor.symbol, superConstructor.typeParameters.size, if (superClassIsAny) 0 else 1 ).also { constructorCall -> val anyType = pluginContext.irBuiltIns.anyType for (param in superConstructor.typeParameters.withIndex()) { constructorCall.putTypeArgument(param.index, anyType) } if (!superClassIsAny) { constructorCall.putValueArgument(0, pluginContext.unitValue) } } ) ) When compiling it got exception stack trace (only for JS, JVM compiles successfully): e: java.lang.IllegalStateException: Not found Idx for public my.package/A|null[0] at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker$IrDeserializerForFile.resolveSignatureIndex(KotlinIrLinker.kt:289) at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker$IrDeserializerForFile.loadTopLevelDeclarationProto(KotlinIrLinker.kt:296) at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker$IrDeserializerForFile.deserializeDeclaration(KotlinIrLinker.kt:268) at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker$IrDeserializerForFile$FileDeserializationState.processPendingDeclarations(KotlinIrLinker.kt:256) at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker$IrDeserializerForFile.deserializeAllFileReachableTopLevel(KotlinIrLinker.kt:431) at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker$BasicIrModuleDeserializer$ModuleDeserializationState.processPendingDeclarations(KotlinIrLinker.kt:99) at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker$BasicIrModuleDeserializer.deserializeReachableDeclarations(KotlinIrLinker.kt:208) at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker.deserializeAllReachableTopLevels(KotlinIrLinker.kt:501) at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker.findDeserializedDeclarationForSymbol(KotlinIrLinker.kt:520) at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker.getDeclaration(KotlinIrLinker.kt:554) at org.jetbrains.kotlin.ir.util.ExternalDependenciesGeneratorKt.getDeclaration(ExternalDependenciesGenerator.kt:66) at org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator.generateUnboundSymbolsAsDependencies(ExternalDependenciesGenerator.kt:56) at org.jetbrains.kotlin.ir.backend.js.KlibKt.loadIr(klib.kt:282) at org.jetbrains.kotlin.ir.backend.js.CompilerKt.compile(compiler.kt:53) at org.jetbrains.kotlin.ir.backend.js.CompilerKt.compile$default(compiler.kt:48) at org.jetbrains.kotlin.cli.js.K2JsIrCompiler.doExecute(K2JsIrCompiler.kt:221) at org.jetbrains.kotlin.cli.js.K2JSCompiler.doExecute(K2JSCompiler.java:181) at org.jetbrains.kotlin.cli.js.K2JSCompiler.doExecute(K2JSCompiler.java:74) at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:86) at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:44) at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:98) at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1549) at jdk.internal.reflect.GeneratedMethodAccessor28.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:567) at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:359) at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200) at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197) at java.base/java.security.AccessController.doPrivileged(AccessController.java:691) at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196) at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:562) at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:796) at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:677) at java.base/java.security.AccessController.doPrivileged(AccessController.java:391) at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:676) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:830) If remove type parameter, or move B class to first module then compilation succed.
✔️ 1
r
Hi, could you please check that there is no cross-module type parameters usage. It’s kind of invariant that type parameter declaration accessible only inside scope where it’s defined
BTW, in case of
B : A<Any>
there is no need for any type argument in constructor call. Such construction is being implemented through substituted type in
IrClass.superTypes
p
@Roman Artemev [JB] i checked T with Any, public top level class in first module, public top level class in second module. Exception is the same.
This exception happens only for IR->JS case.
r
Could you please show what code are you trying to generate? I mean in kotlin
The problem is that type parameter is being used in scope where it is inaccessible
p
For reproduce: Module1: package test1 abstract class TestBase<T> //////////////////////////////////////////////////////////////////////////////// Module2 package test2 class TestDerived: TestBase<Any> fun main() { console.info(TestDerived().toString()) } //////////////////////////////////////////////////////////////////////////////// SyntheticResolveExtension override fun generateSyntheticSecondaryConstructors(thisDescriptor: ClassDescriptor, bindingContext: BindingContext, result: MutableCollection<ClassConstructorDescriptor>) { super.generateSyntheticSecondaryConstructors(thisDescriptor, bindingContext, result) if (thisDescriptor.fqNameOrNull() in arrayOf(FqName("test1.TestBase"), FqName("test2.TestDerived"))) { result.add(ClassConstructorDescriptorImpl.createSynthesized( thisDescriptor, Annotations.EMPTY, false, thisDescriptor.source ).apply { initialize( null, null, ArrayList(thisDescriptor.declaredTypeParameters), mutableListOf( ValueParameterDescriptorImpl( this, null, 0, Annotations.EMPTY, Name.identifier("stub"), thisDescriptor.module.builtIns.unitType, false, false, false, null, thisDescriptor.source ) as ValueParameterDescriptor ), thisDescriptor.defaultType, Modality.OPEN, Visibilities.PUBLIC ) }) } } //////////////////////////////////////////////////////////////////////////////// IrGenerationExtension override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) { moduleFragment.transformChildren(object : IrElementTransformer<Unit> { override fun visitClass(declaration: IrClass, data: Unit): IrStatement { if (declaration.fqNameWhenAvailable() in arrayOf(FqName("test1.TestBase"), FqName("test2.TestDerived"))) { generateTestConstructor(declaration, pluginContext) } return super.visitClass(declaration, data) } } } private fun generateTestConstructor(klass: IrClass, pluginContext: IrPluginContext) { val constructor = klass.constructors.find { it.valueParameters.size == 1 && it.valueParameters[0].type.isUnit() }!! val superClass = klass.superTypes.find { it.classOrNull != null }!!.classOrNull!!.owner val superClassIsAny = superClass.symbol == pluginContext.irBuiltIns.anyClass val superConstructor = if (superClassIsAny) { superClass.constructors.find { it.valueParameters.isEmpty() }!! } else { superClass.constructors.find { it.valueParameters.size == 1 && it.valueParameters[0].type.isUnit() }!! } constructor.body = IrBlockBodyImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, listOf( IrDelegatingConstructorCallImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, superConstructor.returnType, superConstructor.symbol, superConstructor.typeParameters.size, if (superClassIsAny) 0 else 1 ).also { constructorCall -> val anyType = pluginContext.irBuiltIns.anyType for (param in superConstructor.typeParameters.withIndex()) { constructorCall.putTypeArgument(param.index, anyType) } if (!superClassIsAny) { constructorCall.putValueArgument(0, pluginContext.unitValue) } } ) ) }
r
I am not sure that there is a bug in compiler API. As it was said before I suspect incorrect type parameters usage. Could you please provide kotlin code equivalent of what you are trying to generate in plugin?
p
What do you mean by incorrect type parameters usage? I provided usage and code generation in previous message where you can check how type parameter is used, it is reproducing this exception for IR->JS. IR->JVM compiled correctly and successfully.
r
Could you please check whether replacing
superConstructor.returnType
with
pluginContext.irBuiltIns.unitType
fixes your issue? I suspect that unsubstituted type is being used which leads to leak of type parameters outside their scope.
p
@Roman Artemev [JB] Thank you! Your suggestion helps. But frankly speaking I don't understand why my case throws exception and only fo JS. 🙂 Anyway now it works.
r
Let me try to explain, “substituted type” means that proper type arguments are substituted into IrType, in contrast “unsubstituted” type uses original type parameters instead of arguments. In other words there will be references to that type parameters. Since type parameters are local and accessible only in scope (class) where they are defined such references kind of incorrect. I would agree that there should be something like diagnostic but that haven’t been done yet 😔
p
I understand! It is about actual type parameters. Thank you!