Reputation: 1830
So, lets say I have a few things before hand:
case class M[A](val value: A) {
def apply(as: M[A]*) = macro applyImpl[A]
}
def tpAware(implicit ev: Context[A]): M[A]
val ma: M[X] = ???
I want to do:
ma(tpAware)
Where applyImpl
is defined something like
def applyVG[A : c.WeakTypeTag, V](c: MacroContext)(vs: c.Expr[M[V]]*): c.Expr[M[A]] = {
import c.universe._
val container = c.prefix.tree.collect {
case a@Apply(n, xs) => xs
}.flatten.apply(1)
val expr = reify {
M {
implicit val ev = Context[A]()
val container = c.Expr[A](container).splice
sequence(c)(vs).splice foreach { c =>
container.add(c.value)
}
container
}
}
expr
}
The problem now, is that the typer runs before the macro is expanded, and my Context[A]
is not visible prior to the application of apply
Wat do?
Upvotes: 0
Views: 149
Reputation: 1830
Rather than injecting an implicit parameter into the argument list, the only approach that works is to create @compileTimeOnly
functions which will have an alternative AST injected in their place by the apply
macro.
The argument list of the @compileTimeOnly
function will be spliced into into the generated AST and that generated AST will be spliced into the overall program at large.
Particular care must be taken to fix symbol ownership and type checking of the generated and spliced syntax trees. See macrology201
part 1 steps 19 through 30 for more information on how to fix the trees properly.
This approach is used by scala-async, sbt, and others to have cooperation occur between macros and their children.
Upvotes: 1