问题
I have an implicit macro with a greedy signature
implicit def materializeHelper[C <: Any]: Helper[C] = macro materializeHelperImpl[C]
def materializeHelperImpl[C <: Any: ctx.WeakTypeTag](ctx: blackbox.Context): ctx.Expr[Helper[C]] = ???
According to it's signature it would materialize a Helper[C]
for any C. But the body is much more picky. It only accepts C
s which are sealed traits.
What should the macro return to tell the compiler "forget my result, continue your implicit search as if I didn't exist"?
Currently I am returning an empty block (q""
), which is not ideal because the compiler materializes a null
when said implicit is used as an intermediate rule. For example, in the following line, the helper
parameter is set to null when the macro returns empty (q""
).
implicit def parser[C <: Any](implicit helper: Helper[C]): Parser[C] = new Parser[C](helper)
And my intention is that, in the case that C
is not a sealed trait, the compiler discards both beforementioned implicit and continue the search for another more specific implicit value.
回答1:
You didn't make your macro materializing type class Helper
whitebox.
Normally implicit macros should be whitebox.
If a blackbox macro (even implicit blackbox macro) throws an exception then it will be a compile error during compilation of main code. If a whitebox implicit macro throws an exception then during compilation of main code the implicit will be silently removed from candidates.
Implicit macro. Default implicit value. How?
https://docs.scala-lang.org/overviews/macros/blackbox-whitebox.html
It's more idiomatical to call c.abort
with custom error message. Throwing an exception, calling c.error
, returning EmptyTree
(it just doesn't typecheck in such case) are also possible although they seem a little less idiomatical (it's better to have clear compile error message).
来源:https://stackoverflow.com/questions/64538997/what-should-a-scala-implicit-macro-have-to-return-to-tell-the-compiler-forget-m