我有以下代码;
def $q[U](selector: T => U, value: U)(implicit writer: BSONDocumentWriter[U]): BSONDocument = macro MacrosImpl.getBsonExpr[T, U]
getBsonExpr的代码是;
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))
}
}
但是你无法将隐含传递给宏,所以当我编译时,我得到:
macro implementations cannot have implicit parameters other than WeakTypeTag evidences
有办法解决这个问题吗?
答案 0 :(得分:2)
您可以使用
def $q[U](selector: T => U, value: U)(implicit writer: BSONDocumentWriter[U]): BSONDocument = macro MacrosImpl.getBsonExpr[T, U]
与
def getBsonExpr[T, U](c: Context)
(selector: c.Expr[T => Any], value: c.Expr[U])
(writer: c.Expr[BSONDocumentWriter[U]]): c.Expr[BSONDocument] = {
<...>
}
你当然不能将BSONDocumentWriter本身的实例(只有表达式树)传递给宏,因为它是一个宏,并且在你的程序之前编译。
我真的不知道你的宏应该做什么,所以我无法帮助你实现。如果您向我提供更多详细信息,我可以帮助您。
答案 1 :(得分:0)
您应该使用c.inferImplicitValue
。宏不需要传递隐式参数,因为它可以直接查找它们。
您的helper
上存在问题,因为您无法在编译时使用运行时已知的参数。解决这个问题取决于你的意图。
最后提示。使用quasiquotes,因为它们比reify
更灵活。
我会沿着这些方向做某事(未经测试)。
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)
}
}