Reputation: 994
I have the following code;
def $q[U](selector: T => U, value: U)(implicit writer: BSONDocumentWriter[U]): BSONDocument = macro MacrosImpl.getBsonExpr[T, U]
The code of getBsonExpr is;
def getBsonExpr[T, U](c: Context)(selector: c.Expr[T => Any], value: c.Expr[U])(implicit writer: BSONDocumentWriter[U]): c.Expr[BSONDocument] = {
import c.universe._
val helper = new Helper[c.type, T](c, selector)
reify {
val p = helper.pathStringExpr().splice
val v = value.splice
BSONDocument(p -> writer.write(v))
}
}
However you can't pass implicits to a macro, so when I compile I get:
macro implementations cannot have implicit parameters other than WeakTypeTag evidences
Is there a way to work around this?
Upvotes: 2
Views: 222
Reputation: 767
You should be using c.inferImplicitValue
. A macro does not need to be passed implicit parameters, as it can directly look them up.
You have a problem on your helper
, as you can't use params known at runtime during compile time. Fixing this depends on your intent.
Last tip. Use quasiquotes, as they are much more flexible than reify
.
I would do something along these lines (not tested).
class A[T] {
def $q[U](selector: T => U, value: U): BSONDocument =
macro MacrosImpl.getBsonExpr[T, U]
}
object MacrosImpl {
def getBsonExpr[T, U: c.WeakTypeTag](c: Context)(selector: c.Expr[T => Any], value: c.Expr[U]): c.Expr[BSONDocument] = {
import c.universe._
// cannot work as selector is not known at compile time (only its tree his)
// and macro code is evaluated at compile time
val helper = new Helper[c.type, T](c, selector)
// Look for implicit BSONDocumentWrite
val writer = c.inferImplicitValue(appliedType(typeOf[BSONDocumentWriter[_]], List(weakTypeOf[U])))
// In case no implicit
if(writer = EmptyTree) sys.error("No implicit BSONDocumentWriter!")
val tree = q"""
val p = ${helper.pathStringExpr()}
val v = $value
BSONDocument(p -> $writer.write(v)
"""
c.Expr[BSONDocument](tree)
}
}
Upvotes: 0
Reputation: 5426
You can use
def $q[U](selector: T => U, value: U)(implicit writer: BSONDocumentWriter[U]): BSONDocument = macro MacrosImpl.getBsonExpr[T, U]
with
def getBsonExpr[T, U](c: Context)
(selector: c.Expr[T => Any], value: c.Expr[U])
(writer: c.Expr[BSONDocumentWriter[U]]): c.Expr[BSONDocument] = {
<...>
}
You can of course not pass the instance of BSONDocumentWriter itself (only the expression tree) to the macro because, well it is a macro and does get compiled before your program.
I don't really know what your macro should do so I can't help you with the implementation. If you provide me with more details I can help you there.
Upvotes: 2