[Scala 3] Compiler plugin phase running several times

I’m writing a compiler plugin that is meant to trigger after the genBCode phase, in order to to run some validation over the produced bytecode.

So essentially the phase looks like this :

  override val runsAfter = Set(GenBCode.name)
  override def run(using context: Context): Unit = {
     /// does some stuff 
  }

The compiler plugin triggers as expected once the bytecode has been produced. However, it triggers several times in a row, and I cannot figure out what makes that happen, nor how to prevent it from happening.

For a repro, the project is there : Adds the basis for a compiler-plugin ... by Baccata · Pull Request #2 · neandertech/smithy4s-deriving · GitHub

the sources to the compiler plugin live in the modules/compiler folder, and the examplesJVM project is wired to compile using the compiler, so one just needs to run examplesJVM/clean and examplesJVM/compile in SBT to witness the issue.

Any help troubleshooting and deduplicating would be greatly appreciated :pray:

It would be to some extent expected when using macros. In order to execute macro you need to first compile it. Maybe run the compilation with -Xprint:<phaseName> to check what actually is being compiled. Otherwise I don’t see any other reason that could possibly cause that.

The phase is invoked once per compilation unit, not once per run.

import dotty.tools.dotc.core.Contexts.*
println(s"source ${ctx.source}")

where ctx is the implicit context.

Thanks folks, I had forgotten that files are individual compilation units, which allows macros to be used in the same project they are defined.

Seems like overriding runOn instead of run does the trick, see : Adds the basis for a compiler-plugin ... by Baccata · Pull Request #2 · neandertech/smithy4s-deriving · GitHub