Search code examples
scalaimplicitscala-macros

what should a scala implicit macro have to return to tell the compiler "forget my result, continue your search"


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 Cs 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.


Solution

  • 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).