Oleg Yukhnevich
05/23/2023, 9:41 AM@Ann
external fun doSomething() // in common
into
expect fun doSomething() // in common
actual fun doSomething() {...} // in jvm
actual fun doSomething() {...} // in native
Overall how it will be done under the hood doesn’t matter, the idea is to generate different implementations for different targets, while still having common function
is it possible ? 🙂
as for use case - “multiplatform cinterop” - https://github.com/whyoleg/ffi-kotlin/tree/gradle-plugin#compiler-pluginOleg Yukhnevich
05/23/2023, 9:46 AMdmitriy.novozhilov
05/23/2023, 10:16 AMOleg Yukhnevich
05/23/2023, 10:32 AMOleg Yukhnevich
05/23/2023, 10:14 PMexpect
in common and generation of actual
in platform (source code of FIR extensions)
• It’s super hacky now, just to try, and Im not sure, that it’s ok to access common
session like this: session._moduleData_.dependsOnDependencies._firstOrNull_()?.session
. Of course if there will be more shared sourcesets I will need to iterate over all of them, but may be somewhere exists other way to access declarations from other sessions? In my case I need to get declaration annotated in common
session, but use it in platform
session to generate declaration based on it. I haven’t found any example of something similar in kotlin repository 🙂 All plugins there looks like just use single session, and it’s ok for them, but not in my case.
• I was even able to then generate simple platform dependent IR body for this function . (the simplest part here, hehe)
• But… It runs only on JVM 😞 for JS and Native it fails trying to serialize IR output to klib. F.e. JS fails on this line. Native fails on line with same semantic in different file. Any thoughts, on where I should look to understand, what I’m doing wrong?
And BTW, looking at fir-plugin-prototype
module is super helpful to understand how to do something (both FIR and IR). Thx!dmitriy.novozhilov
05/24/2023, 7:00 AMIt’s super hacky now, just to try, and Im not sure, that it’s ok to access common session like thisActually, it's quite correct, I don't see any issues related to usages of compiler structures
F.e. JS fails on this line.Could you please report an issue about it? Looks like we never tested compiler plugins which generate new top-level declarations on platforms which differ from JVM
dmitriy.novozhilov
05/24/2023, 7:02 AMAnd BTW, looking at fir-plugin-prototype module is super helpful to understand how to do something (both FIR and IR)The original purpose of this module is having some sandbox for testing all FIR extension points. Good to know that it also helps to understand compiler API IMO this module is quite a mess, but actually it can be transformed into some sample compiler plugin project
Oleg Yukhnevich
05/24/2023, 7:21 AMActually, it’s quite correctGood to know this!
Could you please report an issue about itYes, will create it. Will it be enough to create 1 issue for K/JS and K/N? (stacktrace is different, but check is the same)
Good to know that it also helps to understand compiler APIIt’s super helpful, as all other compiler plugins in the repository or super simple (noarg, allopen) or super complex (serialization). But this module provides short intro into most of the available extensions with simple code samples for both FIR and IR! It’s really great to understand the basics. For me it’s second time Im trying to do IR plugin and first time with FIR, and it was smooth! While we are here, I have 2 small questions: • I saw in fir-plugins doc, that there is no yet possibility to generate bodies for existing function. But may be there is some possibility now to just add some stub to body in FIR? ◦ When generating new
actual
declarations I also don’t add body, but it works ok
◦ Now, Im not able to expand @ForeignCCall fun doSmth(): String
into full blown declaration in platform code but only create expect/actual. So strange, but it’s possible now only to declare it in common and actualize in platform, but not just declare in platform 😞
• Is there some deterministic possibility to understand is session is from shared
sourceset or from leaf platform
sourceset in FIR?
◦ It’s needed for same thing as upper point. while now I can just check, that dependsOnDependencies
is empty (common) but if there will be hierarchy it will be not possible, as intermidiate
sourceset (like native) will have dependsOn
relations. I can’t also use TargetPlatform
from FirModuleData
as looks like now (or forever) it is the same for all sessions created in single compilation.dmitriy.novozhilov
05/24/2023, 9:42 AMWill it be enough to create 1 issue for K/JS and K/N?Yeah, it will be It would be quite useful if you point out both problematic places in the description
I saw in fir-plugins doc, that there is no yet possibility to generate bodies for existing function. But may be there is some possibility now to just add some stub to body in FIR?There is no difference in stub body and lack of body for generated declarations If declaration has no body then
IrFunction.body
just will be empty, and you will be able to fill it like you want
If it will have some stub body, then fir2ir generate some stub ir body, which you'll also replace with something meaningful
So there is no sense in stub bodies
Now, Im not able to expandCould you please elaborate? I didn't fully understand the caseinto full blown declaration in platform code but only create expect/actual. So strange, but it’s possible now only to declare it in common and actualize in platform, but not just declare in platform@ForeignCCall fun doSmth(): String
Is there some deterministic possibility to understand is session is from shared sourceset or from leaf platform sourceset in FIR?There is no simple way to do it, because of following reasons: 1. there is no need in such API in compiler right now 2. scheme of compilation is subject to change (we plan to separately compile
common
modules to klib once and them use them as regular binary dependencies, but ETA of this is unknown)
3. layout of module data may be quite different in IDE (because it contains information about all modules in project), so there might be some inconsistencies (I'm not sure)
I can’t also useThis is by design of how MPP modules are compiled right nowfromTargetPlatform
as looks like now (or forever) it is the same for all sessions created in single compilation.FirModuleData
dmitriy.novozhilov
05/24/2023, 9:45 AMCompilerConfiguration
and you can access it from CompilerPluginRegistrar
Names for module datas are matched 1 to 1 to names from HmppModuleStucture
, so you can use it
But note that it won't work in IDE, because CompilerPluginRegistrar
is not called during setup of plugins inside itOleg Yukhnevich
05/24/2023, 10:04 AMIt would be quite useful if you point out both problematic places in the descriptiongot it, will do later today
Could you please elaborate? I didn’t fully understand the caseNow there is checker for top level functions, that require bodies for nonExpect functions with existing source. And as there is now no possibility to add body in FIR via extension, I can’t generate body for
@ForeignCCall fun doSmth(): String
in IR plugin, because it fails by this checker, because function has no body.
In case of generating platform declaration in FIR plugin, I mark existing declaration with isExpect=true
(so checker don’t fail) and generating new declaration with source == null
(so checker don’t fail)
But in case I want to just modify body of existing declaration checker fails, as it should not be expect
and have source != null
.
I see now, that there is FirPlatformDiagnosticSuppressor
and I believe I can use it now to ignore body check
and generate IR body, though I haven’t tried it, as single usage of this suppressor is for JS 🙂
There is no simple way to do it, because of following reasons:Got it, sound logical, I will investigate other ways of doing what I want
But note that it won’t work in IDE, becauseOk, from IDE side for my use case the only thing, that I need is to allow to compile functions (and may be classes) with annotations without body, similar to howis not called during setup of plugins inside itCompilerPluginRegistrar
external
modifier works.
Will continue investigation of K2 possibilities for my use cases and report here (or in new threads if there will be different theme)
Big thx for helping and providing a lot of useful information!dmitriy.novozhilov
05/24/2023, 10:19 AMNow there is checker for top level functions, that require bodies for nonExpect functions with existing source.Oh, it's indeed a problem. Could you please file an issue about it too? As a workaround you actually can generate a body for function by calling
replaceBody
on function returned from createTopLevelFunction
. As a stub body I recommend to use return null!!
or return TODO()
Oleg Yukhnevich
05/24/2023, 10:23 AMcreateTopLevelFunction
it works as it have source==null
and checker works fine
It doesn’t work for EXISTING declarations without body, as there is no extension to change it
or may be it’s possible to replace it while generating in FirDeclarationGenerationExtension
?Oleg Yukhnevich
05/24/2023, 4:47 PMdmitriy.novozhilov
05/25/2023, 7:28 AM