A call to a macro method is executed during the compiler phase called macro expansion to generate a part of the program—an abstract syntax tree.
The Scala 2.13 macro API is closely tied to the Scala 2.13 compiler internals. Therefore it is not possible for the Scala 3 compiler to expand any Scala 2.13 macro.
In contrast, Scala 3 introduces a new principled approach of metaprogramming that is designed for stability. Scala 3 macros, and inline methods in general, will be compatible with future versions of the Scala 3 compiler. While this is an uncontested improvement, it also means that all Scala 2.13 macros have to be rewritten from the ground up, by using the new metaprogramming features.
A Scala 3 module can depend on a Scala 2.13 artifact even if it contains a macro definition but the compiler will not be able to expand its macros. When you try to, it simply returns an error.
Let’s note that using
-Xignore-scala2-macros is helpful to type check the code but it produces incomplete class files.
When this error appears in your project, you have eventually no other choice than upgrading to a Scala 3-compiled version of the macro artifact.
Porting the Macro Ecosystem
While being experimental, the Scala community has largely adopted the Scala 2 macro feature in multiple ways: code generation, optimizations, ergonomic DSLs…
A large part of the ecosystem now depends on Scala 2.13 macros defined in external libraries. Identifying and porting those libraries is key to move the ecosystem forward.
A migration status of many open-source macro libraries is available in this page.
Rewriting a Macro
The new metaprogramming features are completely different from Scala 2. They are comprised of:
- Inline Methods
- Compile-time operations
- Quoted code
- Reflection over Abstract Syntax Trees (AST)
Before getting deep into reimplementing a macro you should ask yourself:
- Can I use
scala.compiletimeoperations to reimplement my logic?
- Can I use the simpler and safer expression based macros?
- Do I really need to access the AST?
- Can I use a match type as return type?
You can learn all the new metaprogramming concepts by reading the Macro Tutorial.
Cross-building a Macro Library
You have written a wonderful macro library and you would like it to be available in Scala 2.13 and Scala 3. There are two different approaches, the traditional cross-building technique and the more recent mixing macro technique. You can learn about them by reading these tutorials:
Blog posts and talks: