在生成的宏方法中使用`this`

时间:2013-08-30 02:12:41

标签: scala scala-macros

这是对previous question的跟进。

我想要像下面的代码一样工作。我希望能够生成宏生成的方法:

case class Cat()

test[Cat].method(1)

生成方法本身的实现使用宏("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})")
}

此代码无法编译:

[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] )

我很难破译这意味着什么,但我怀疑这与我无法在吸血鬼方法体中引用this.otherMethod这一事实有关。有没有办法做到这一点?

如果这样做,我的下一步将是otherMethod

的这种实现
def otherMethod(p: Int) = new $className { 
  override protected val aValue = p 
}

1 个答案:

答案 0 :(得分:2)

&#34; this&#34;通常以c.prefix.tree的形式提供。所以也许像是

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