Implicits和blackbox宏

时间:2014-10-28 14:21:27

标签: scala macros

我有以下代码;

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

有办法解决这个问题吗?

2 个答案:

答案 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)

  }

}