Hi, folks! I am testing my compiler plugin and I w...
# compiler
g
Hi, folks! I am testing my compiler plugin and I would like to dump all generated IR. Until some moment in the past, I needed only
CodegenTestDirectives.DUMP_IR
directive. But now it does not dump IR of generated top-level declarations (that are not placed in user files, but in generated file instead). What directive should I add to see generated top-level functions again?
d
What do you mean by "now"? I've just checked the kotlin master, and files for generated declarations are successfully dumped:
Copy code
// DUMP_IR
package foo

@org.jetbrains.kotlin.plugin.sandbox.TestTopLevelPrivateSuspendFun
fun box(): String = "OK"
Copy code
FILE fqName:foo fileName:/topLevelPrivateSuspendFun.kt
  FUN name:box visibility:public modality:FINAL returnType:kotlin.String
    annotations:
      TestTopLevelPrivateSuspendFun
    BLOCK_BODY
      RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in foo'
        CONST String type=kotlin.String value="OK"
FILE fqName:foo fileName:foo/__GENERATED__CALLABLES__.kt
  FUN GENERATED[org.jetbrains.kotlin.plugin.sandbox.fir.generators.TopLevelPrivateSuspendFunctionGenerator.TopLevelPrivateSuspendFunctionGeneratorKey] name:testFun_generated visibility:private modality:FINAL returnType:kotlin.Unit [suspend]
    BLOCK_BODY
g
The story is that I recently opened my old code that used older Kotlin version. I updated Kotlin version (now I use Kotlin 2.3.20-RC3) and replaced usages of deprecated Kotlin APIs. Then I suddenly saw that in both FIR and IR generated top-level declarations are not printed for some reason. For FIR, I found that I needed to add
FirDiagnosticsDirectives.EXPLICITLY_GENERATE_PLUGIN_FILES
to my test configuration. (I do all the directives specification in test code generator.) But it still does not print the declarations in IR. For example:
Copy code
// SUPPRESS_WARNINGS: PRE_RELEASE_CLASS

package foo.bar

import dev.lounres.kone.suppliedTypes.*


@Suppliable
fun <@Supply Gee> baz(): Gee? = null
Copy code
FILE: function1.kt
    package foo.bar

    @R|dev/lounres/kone/suppliedTypes/Suppliable|() public final fun <@R|dev/lounres/kone/suppliedTypes/Supply|() Gee> baz(): R|Gee?| {
        ^baz Null(null)
    }
FILE: foo/bar/__GENERATED__CALLABLES__.kt
    package foo.bar

    @R|dev/lounres/kone/suppliedTypes/SupplianceProvided|() public final fun <Gee> baz(@R|dev/lounres/kone/suppliedTypes/SupplianceProvided|() suppliedTypeParameterForGee: R|dev/lounres/kone/suppliedTypes/SuppliedType| = throw R|kotlin/Throwable.Throwable|(String(Stub for declaration generated by Plugin[SuppliableFunctionsDuplicatesGenerationExtension.Key]))): R|Gee?|
Copy code
FILE fqName:foo.bar fileName:/function1.kt
  FUN name:baz visibility:public modality:FINAL returnType:Gee of foo.bar.baz?
    TYPE_PARAMETER name:Gee index:0 variance: superTypes:[kotlin.Any?] reified:false
      annotations:
        Supply
    annotations:
      Suppliable
    BLOCK_BODY
      RETURN type=kotlin.Nothing from='public final fun baz <Gee> (): Gee of foo.bar.baz? declared in foo.bar'
        CONST Null type=kotlin.Nothing? value=null
Maybe something is wrong with my setup... But I don't know where to start to investigate the issue.
d
There are no special directives requried for IR dump handler actually. > But I don't know where to start to investigate the issue. You can debug the dump handler itself. Find
IrTextDumpHandler
in dependencies and put the breakpoint at processModule function.
g
Thanks for the advise! I found out that the lost declaration is missing in the
info
argument. There is only one file with only one declaration in the
info
. I am trying to find out why the function disappears from the
IrModuleFragment
. But for now I have to go : ( I'll continue investigation some time later.
d
Curious, it seems like the file was generated at the FIR level but for some reason was not converted to IR. And nothing failed (which is even stranger).
I have an idea. Could you show which test facades are you using in your tests? The behavior you've observing could happen if you're still on legacy hand-written facades instead of CLI-based facades. They should be
::FirCliJvmFacade
,
::Fir2IrCliJvmFacade
and
::BackendCliJvmFacade
respectfully.
g
I am back. Sorry for the delay. Indeed, I used
baseFirDiagnosticTestConfiguration
(which uses
::FirFrontendFacade
by default),
::Fir2IrResultsConverter
, and
::JvmIrBackendFacade
. I replaced them with the ones you mentioned and removed
+FirDiagnosticsDirectives.EXPLICITLY_GENERATE_PLUGIN_FILES
, and now both FIR and IR are dumped correctly! Thank you! But now multimodule tests are not working : ( For example, test
Copy code
// SUPPRESS_WARNINGS: PRE_RELEASE_CLASS

// MODULE: foo
import dev.lounres.kone.suppliedTypes.*


@Suppliable
interface Foo<@Supply T>

// MODULE: bar(foo)
import dev.lounres.kone.suppliedTypes.*


@Suppliable
interface Bar<@Supply U> : Foo<Map<out U, *>>
fails with
Copy code
// SUPPRESS_WARNINGS: PRE_RELEASE_CLASS

// MODULE: foo
import dev.lounres.kone.suppliedTypes.*


@Suppliable
interface Foo<@Supply T>

// MODULE: bar(foo)
import dev.lounres.kone.suppliedTypes.*


@Suppliable
interface Bar<@Supply U> : <!UNRESOLVED_REFERENCE!>Foo<!><Map<out U, *>>
d
Do you have it published somewhere? At this point it's hard for me to just guess.
g
Wait a minute, please. I'll commit it and push to GitHub.
It is a part of big project: https://github.com/lounres/Kone/tree/experiment I am working on it in
experiment
branch. I just pushed a commit with last changes. The plugin lies in
/plugins/suppliedTypes
directory. All test generation logic is placed in
testGeneration
subdirectory.
d
CLI-based test facade support only binary dependencies between modules. But in your configuration you have only frontend facade, so binaries are not produced and dependent modules don't see any .class files to depend on. To fix it you need to register all three facades (frontend, fir2ir, backend), similar to codegen test. But as you probably now in reporting some error at the frontend causes the codegen test to fail. To workaround this we have a
// RUN_PIPELINE_TILL: PHASE
directive, where
PHASE
is
FRONTEND
,
FIR2IR
or
BACKEND
(link). You put it in each test to define until which phase the latest module is expected to be compiled (note that all previous modules should be compilable, otherwise binary artifact won't be produced). This functionality is implemented in PhasedPipelineChecker after analysis checker. As a reference you could check the AbstractFirPhasedDiagnosticTest which is currently the base class for all diagnostic tests in the kotlin repo.
Actually the
PhasedPipelineChecker
will automatically suggest you to insert the directive with a proper phase if it's missing. And also it will ensure that the phase should be changed to the next one if there were no compilation errors.
g
Thank you very much @dmitriy.novozhilov! Everything works great now! But I had to apply
+CodegenTestDirectives.IGNORE_DEXING
, because It was throwing
java.lang.NoClassDefFoundError: com/android/tools/r8/origin/Origin
. I guess I have to add Android compiler into compiler test runtime classpath. But I think it's not that necessary, so I just suppressed it. I hope I didn't irritate you much with my silly questions.
👍 1
d
But I had to apply +CodegenTestDirectives.IGNORE_DEXING
That's correct, you don't need this checker.
I hope I didn't irritate you much with my silly questions.
You're welcome.
🔥 1
❤️ 1