With Scala2 I could implement a macro and generate types using tq quasiquote syntax, for eg:
q"""
new Foo {
type Bar = ${tq"(..$params)"}
}
"""
I am able to do two things with this syntax -
- Able to define a type
Barbased on theparams. - Able to spread the
paramsas a tuple.
How can I achieve this with Scala 3?
There are no quasiquotes (
q"...",tq"...",pq"...",cq"...",fq"...") in Scala 3. Feel yourself like in early days of macros in Scala 2.10 :)Scala 3 quotations
'{...}(and splicing${...}) must typecheck not only at compile time of the main code (i.e. runtime of macros, the time when macros expand) but also earlier at compile time of macros themselves. This is similar toreify {...}(and.splice) in Scala 2.new Foo {...}is actually an instance of an anonymous class extendingFoo. So see your previous question Macro class name expansion in Scala 3, Method Override with Scala 3 MacrosEverything depends on whether
Fooandparamsare known statically. If so then everything is easy:or
or
In comments @Jasper-M advises how to handle the case when we have
Foostatically butparamsnot statically:or
Now suppose that
Foois not known statically. Since there are no quasiquotes the only different way of constructing trees in Scala 3 is to go deeper to Tasty reflection level and build a tree manually. So you can print a tree of statically typechecked code and try to reconstruct it manually. The codeprints
And
prints
One more complication here is that Scala 3 macros accept typed trees and must return typed trees. So we must handle symbols as well.
Actually, in reflection API I can see
Symbol.newMethod,Symbol.newClass,Symbol.newVal,Symbol.newBindbut noSymbol.newType. (It turns out a method for new type member is not exposed to the reflection API, so we have to use internaldotty.tools.dotc.core.Symbols.newSymbol.)I can imagine something like
Scala 3 macros are def macros, all generated definitions will be seen only inside the block that a macro expands into.
Maybe if it's enough to generate code at pre-compile time you can consider to use Scalameta. There are quasiquotes there :)
q"...",t"...",p"...",param"...",tparam"...",init"...",self"...",template"...",mod"...",enumerator"...",import"...",importer"...",importee"...",source"...".