2013-08-30 11 views
7

Questo è un follow-up sul mio previous question.Utilizzare `this` in un metodo macro generato

Vorrei qualcosa come il seguente codice per funzionare. Voglio essere in grado di generare un metodo di macro-generated:

case class Cat() 

test[Cat].method(1) 

Qualora l'attuazione del metodo generato in sé sta usando una macro (un "vampire" method):

// macro call 
def test[T] = macro testImpl[T] 

// macro implementation 
def testImpl[T : c.WeakTypeTag](c: Context): c.Expr[Any] = { 
    import c.universe._ 
    val className = newTypeName("Test") 

    // IS IT POSSIBLE TO CALL `otherMethod` HERE? 
    val bodyInstance = q"(p: Int) => otherMethod(p * 2)" 

    c.Expr { q""" 
    class $className { 
     protected val aValue = 1 

     @body($bodyInstance) 
     def method(p: Int): Int = macro methodImpl[Int] 

     def otherMethod(p: Int): Int = p 
    } 
    new $className {} 
    """} 
} 

// method implementation 
def methodImpl[F](c: Context)(p: c.Expr[F]): c.Expr[F] = { 
    import c.universe._ 

    val field = c.macroApplication.symbol 
    val bodyAnnotation = field.annotations.filter(_.tpe <:< typeOf[body]).head 
    c.Expr(q"${bodyAnnotation.scalaArgs.head}.apply(${p.tree.duplicate})") 
} 

Questo codice non riesce a compilare con :

[error] no-symbol does not have an owner 
last tree to typer: This(anonymous class $anonfun) 
[error]    symbol: anonymous class $anonfun (flags: final <synthetic>) 
[error] symbol definition: final class $anonfun extends AbstractFunction1$mcII$sp with Serializable 
[error]     tpe: examples.MacroMatcherSpec.Test.$anonfun.type 
[error]  symbol owners: anonymous class $anonfun -> value <local Test> -> class Test -> method e1 -> class MacroMatcherSpec -> package examples 
[error]  context owners: value $outer -> anonymous class $anonfun -> value <local Test> -> class Test -> method e1 -> class MacroMatcherSpec -> package examples 
[error] 
[error] == Enclosing template or block == 
[error] 
[error] DefDef(// val $outer(): Test.this.type 
[error] <method> <synthetic> <stable> <expandedname> 
[error] "examples$MacroMatcherSpec$Test$$anonfun$$$outer" 
[error] [] 
[error] List(Nil) 
[error] <tpt> // tree.tpe=Any 
[error] $anonfun.this."$outer " // private[this] val $outer: Test.this.type, tree.tpe=Test.this.type 
[error]) 

sono davvero male a decifrare ciò che questo significa, ma ho il sospetto che sia legato al fatto che non riesco a fare riferimento this.otherMethod nel corpo del il metodo dei vampiri. C'è un modo per farlo?

Se funziona, il mio prossimo passo sarà quello di avere questo tipo di implementazione per otherMethod:

def otherMethod(p: Int) = new $className { 
    override protected val aValue = p 
} 
+0

Ho appena scritto una risposta più generale a questo problema come [un post] (http://meta.plasm.us/posts/2013/08/31/feeding- i nostri vampiri /). Posso aggiungere una versione condensata come risposta qui se è ciò che stai cercando. –

risposta

2

Il "questo" è generalmente disponibile come c.prefix.tree. Quindi, forse, qualcosa di simile a

val bodyInstance = 
    q"(p: Int) => ${c.prefix.tree}.otherMethod(p * 2)" 
Problemi correlati