2014-10-28 2 views
2

У меня есть следующий код;Implicits and blackbox 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)) 
    } 
    }

Однако вы не можете передать implicits в макрос, поэтому, когда я скомпилировать я получаю:

macro implementations cannot have implicit parameters other than WeakTypeTag evidences

Есть ли способ обойти это?

ответ

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 к макросу, потому что, ну это макро-и скомпилируется перед вашей программой.

Я действительно не знаю, что должен сделать ваш макрос, я не могу помочь вам в реализации. Если вы предоставите мне более подробную информацию, я могу вам помочь.

0

Вы должны использовать c.inferImplicitValue. Макрос не должен передаваться неявным параметрам, так как он может напрямую искать их.

У вас есть проблема с вашим helper, так как вы не можете использовать параметры, известные во время выполнения во время компиляции. Это зависит от ваших намерений.

Последний отзыв. Используйте квазиквартины, поскольку они намного более гибкие, чем 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) 

    } 

} 
+0

Хотя мне нравится код на первый взгляд, компилятор жалуется 'c.inferImplicitValue (TYPEOF [BSONDocumentWriter])'. Это говорит; 'trait BSONDocumentWriter принимает параметры типа'. Когда я перехожу в 'U', он пропускает' TypeTag'. 'WeakTypeTag' недостаточно, кажется. –

+0

Мой плохой. Я забыл, что «BSONDocumentWriter» принял аргумент типа. Я исправлю это в ближайшее время. – Leo

Смежные вопросы