【问题标题】:Type Parameters on Scala Macro AnnotationsScala 宏注解上的类型参数
【发布时间】:2013-11-16 11:40:06
【问题描述】:

我正在尝试在 scala 中使用宏注释,其中我的宏注释将采用另一种类型的参数。然后它会使用 scala 反射来查看传入的类型,并根据需要添加一些方法。例如。

trait MyTrait {
  def x: Int
  def y: Float
}

@MyAnnotation class MyClass //<-- somehow, this annotation should reference MyTrait

class MyAnnotation(val target: Any) extends StaticAnnotation {
  def macroTransform(annottees: Any*) = macro MyAnnotationImpl.impl
}
object MyAnnotationImpl {
  def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    // if I can get a handle on the type MyTrait in here
    // then I can call .members on it, etc.
    ...
  }
}

基本上和Using Scala reflection in Scala macros一样,除了使用宏注解。但是,当我尝试使用 TypeTag 模板化我的宏注释时

class MyAnnotation[T](val target: Any) extends StaticAnnotation {
  def macroTransform[T](annottees: Any*) = macro MyAnnotationImpl.impl[T]
}
object MyAnnotationImpl {
  def impl[T: c.WeakTypeTag](c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    ...
  }
}

我明白了

[error] /Users/imran/other_projs/learn_macros/macros/src/main/scala/com/imranrashid/oleander/macros/MacrosWithReflection.scala:7: macro annotation has wrong shape:
[error]   required: def macroTransform(annottees: Any*) = macro ...
[error]   found   : def macroTransform[T](annottees: Any*) = macro ...
[error] class MyAnnotation[T](val target: Any) extends StaticAnnotation {
[error]       ^

我还尝试将类型作为注释的参数,所以我会像@MyAnnotation(MyTrait) class Foo ... 一样使用它。我可以将名称​​提取为字符串,例如

val targetTrait = c.prefix.tree match {
  case Apply(Select(New(Ident(_)), nme.CONSTRUCTOR), List(Ident(termName))) => termName
}

但是,我不确定我能用那个字符串做什么来取回完整的类型。我也尝试过像@MyAnnotation(typeOf[MyTrait]) class Foo ... 这样的变体,然后在我的宏中的typeOf 上使用c.eval,但这也无法编译。

【问题讨论】:

    标签: reflection scala-macros


    【解决方案1】:

    在宏天堂 2.0.0-SNAPSHOT 中,我们有一种非常棘手的方式来访问宏注释的类型参数(当我们有专门的 API 时情况会有所改善,但现在很难引入新功能宏天堂里的scala-reflect.jar,所以现在的API有点粗糙)。

    现在需要在注解类上指定类型参数,而不是在macroTransform方法上声明任何类型参数。然后,在宏展开中,访问c.macroApplication,提取传入的类型参数对应的无类型树。然后,按照Can't access Parent's Members while dealing with Macro Annotations 中的说明执行c.typeCheck

    【讨论】:

    • 已经有一段时间了,现在有更好的方法吗?
    【解决方案2】:

    正如 Eugene 在他的回答中指出的那样,可以在整个宏应用程序的树上进行匹配。与每个 Scala 方法一样,注释宏应用程序可以采用多个类型参数列表以及多个值参数列表。

    考虑一个名为test的注解宏的宏应用:

        @test[A, B][C, D](a, b)(c, d) trait Foo
    

    test的实现中,我们可以检查宏应用程序

        println(show(c.macroApplication))
    

    这将导致:

        new test[A, B][C, D](a, b)(c, d).macroTransform(abstract trait Foo extends scala.AnyRef)
    

    要从树中提取(类型/值)参数,您必须在树上进行模式匹配。可以找到任意数量参数列表的解析器in this project

    使用此解析器检索宏应用程序的第一个值参数非常简单

        val List(List(arg)) = MacroApp(c.macroApplication).termArgs
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-19
      相关资源
      最近更新 更多