Reputation: 9521
I'm trying to use freshName as a parameter name in the following macro:
I.
def test: Unit = macro implTst
def implTst(c: blackbox.Context): c.Expr[Unit] = {
import c.universe._
def withImplicitsM(exprs: List[c.Tree], expr: c.Tree): c.Tree =
exprs match {
case Nil =>
expr
case head :: tail =>
//error here
q"""$head.flatMap(implicit ${c.freshName()} => ${withImplicitsM(tail, expr)})"""
}
val exprsIo = List(q"cats.effect.IO.apply(1)", q"cats.effect.IO.apply(2)")
val resultTree = q"""println(${withImplicitsM(exprsIo, q"cats.effect.IO.apply(3)")}.unsafeRunSync())"""
c.Expr[Unit](resultTree)
}
It throws compile error:
[error] Main.scala:25:9: exception during macro expansion:
[error] java.lang.IllegalArgumentException: "fresh$macro$2" is not valid representation of a parameter, consider reformatting it into q"val $name: $T = $default" shape
II.
Replacing the freshname with hardcoded identifier makes it work:
def test: Unit = macro implTst
def implTst(c: blackbox.Context): c.Expr[Unit] = {
import c.universe._
def withImplicitsM(exprs: List[c.Tree], expr: c.Tree): c.Tree =
exprs match {
case Nil =>
expr
case head :: tail =>
q"""$head.flatMap(implicit i => ${withImplicitsM(tail, expr)})"""
}
val exprsIo = List(q"cats.effect.IO.apply(1)", q"cats.effect.IO.apply(2)")
val resultTree = q"""println(${withImplicitsM(exprsIo, q"cats.effect.IO.apply(3)")}.unsafeRunSync())"""
c.Expr[Unit](resultTree)
}
Is there a way to use implicit ${c.freshName()}
without specifying the parameter type explicitly?
Upvotes: 2
Views: 90
Reputation: 9521
Solution:
Use empty type explicitly with parameter definition.
def withImplicitsM(exprs: List[c.Tree], expr: c.Tree): c.Tree =
exprs match {
case Nil =>
expr
case head :: tail =>
val emptyType = tq""
val v = q"implicit val ${TermName(c.freshName())}: $emptyType"
q"""$head.flatMap($v => ${withImplicitsM(tail, expr)})"""
}
How I figured that out:
I destructured a similar flatMap
call and looked at how the paramter definition looked like:
val flatmapExpression = q"cats.effect.IO.apply(1).flatMap(implicit i => cats.effect.IO.apply(2))"
val q"$foo($args)" = flatmapExpression
val q"(..$params) => $body" = args
val q"$mods val $name: $tpt = $rhs" = params(0)
println(mods)
println(name)
println(tpt)
println(rhs)
Here is what was printed out:
Modifiers(implicit <param>, , Map())
i
<type ?>
<empty>
notice <type ?>
which is an empty type.
Upvotes: 1