Hello, I would like to generate a class IR as part...
# arrow-meta
k
Hello, I would like to generate a class IR as part of the backend IR process. Are there any examples on how to do this? E.g. if I had a class
Copy code
class Foo {
    val abc = "abc"

    fun hello() = "Hello World"
}
and then wanted to create the following, but not modifying Foo class
Copy code
class Bar {
    fun hello(name: String) = "Hello $name"
}
Resulting in a Foo.class and a Bar.class If there are no examples, any advice would be great please.
r
Hi Karim, as usual with the Kotlin compilers the answer is: It depends. If you are planning on using
Bar
or it's members in other parts of your code in your local module then you will need to do more than just an IR transformation. If you are not planning to use the generated declaration
Bar
in your local module you can use an IR transformation.
The current meta api is changing both in frontend and backend to adapt to K2 FIR which I think it may come stable in Kotlin 1.10 o some time around there. ~1-2years
It's not a good time to make stable compiler plugins because the compiler does not have a stable public compiler plugin API
If you are gonna use just IR the way to go at the moment is to create your extension based of
org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
and register that in your plugin
That calls your compiler plugin on
fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext)
with the moduleFragment you can access files and declarations in IR and use a
org.jetbrains.kotlin.ir.visitors.IrElementTransformer
to transform every declaration and expression
Most IR nodes are mutable and can be mutated in place. It's a trial and error journey packed with frustration and you may need the entire kotlin project loaded so you can learn at the same time the compiler APIs and search in the compiler codebase to understand how to mutate, copy, or in general perform operation on the tree
If you need to do frontend stuff as in you are planning to depend on that generation for resolution somewhere else in your module the current issue is that FIR is not yet stable so you would have to write two plugins one for the current frontend and another for FIR K2.
k
Hi Raul, thank you for your answers! The intention would be to use the generated code in a different module, i.e. package
Bar
into a jar and use in another project.
the
org.jetbrains.kotlin.ir.visitors.IrElementTransformer
which you mention, could you generate a new IrClass (e.g.
Bar
in the example) using that?
d
Actually if you generate some declaration only in IR, without frontend part, it still be invisible for other modules because of KT-53122 (description says it's about noarg plugin, but actually the problem is general)
k
Thanks for your reply. I see mentioned in the issue a workaround. Is that a general workaround or do you know if there is another way around this for my use case?
in my example if I had an annotation similar to
NoArg
and annotated Foo, would you expect it to work? Also, if necessary I would be fine for the IDE not to resolve the generated class, but would a class in another module compile successfully referencing the generated class?
d
No, that workaround is specific to NoArg implementation The only way to achieve what you want with vanila compiler plugins is to generate your declarations on frontend too
Workaround works for
NoArg
because of how is check if
@NoArg
annotation applicable to to some class. It checks if at least one of two things is true: 1. Parent class has constructor without arguments 2. Parent class is annotated with
@NoArg
So since generated constructor is invisible for frontend, changing
@NoArg
retention fixes this particular issue
k
Ah I see. And just to check my understanding, to generate the frontend declarations would I use a SyntheticResolveExtension? Do you know of any public code examples that I could look at?
d
For existing compiler it's indeed
SyntheticResolveExtension
. But for K2 you need to use
FirDeclarationGenerationExtension
You can check how it's done for both frontends for
kotlinx.serialization
(
.k1
and
.k2
directories respectively)
k
awesome, thank you!
131 Views