如何获取赋予方法参数的 Scala 注释

Koo*_*sha 9 scala scala-macros scala-3

考虑以下注释:

// ok to have more meta
@field
@param
@compileTimeOnly("Only for code generation")
case class Annot(value: String) extends ConstantAnnotation
Run Code Online (Sandbox Code Playgroud)

现在三种用途:

case class A(x: Int, @Annot("z") y: String)
object A:
  def f1(x: Int, y: String @Annot("z")): A = ???
  def f2(x: Int, @Annot("z") y: String): A = ???
Run Code Online (Sandbox Code Playgroud)

我想使用 Scala 3 宏来查找每个注释。

  1. 案例类: Symbol.caseFields为我提供参数列表,并且在每个参数(类型为Symbol)上,方法annotations为我提供了我正在寻找的内容。
  2. 带注释的类型:每个参数都是一个ValDef. 如果param.tpt.tpe匹配,AnnotatedType(tpe, t)那么t就是我正在寻找的注释。
  3. 带注释的方法参数:我​​什么都没有!

知道如何获取为方法中的参数提供的注释吗?当我打印术语/符号/树/...时,在这种情况下我什至看不到“z”。

Dmy*_*tin 0

可以写在宏里

import scala.annotation.experimental
import scala.quoted.*

inline def printAnnotations[A]: Unit = ${printAnnotationsImpl[A]}

@experimental // because .typeRef is @experimental
def printAnnotationsImpl[A](using Quotes, Type[A]): Expr[Unit] = {
  import quotes.reflect.*

  val symbol = TypeTree.of[A].symbol
  println(symbol.caseFields.map(_.annotations)) // Case Class

  val companion = symbol.companionModule
  val methods = companion.declaredMethods
  // Annotated method argument
  println(methods.map(_.paramSymss.map(_.map(_.annotations)))) 

  // Annotated Type
  println(methods.collect(method => companion.typeRef.memberType(method) match {
    case lt: LambdaType => lt.paramTypes.collect {
      case at: AnnotatedType => at.annotation
    }
  }))

  '{()}
}
Run Code Online (Sandbox Code Playgroud)

那么对于

case class A(x: Int, @Annot("z1") y: String)
object A:
  def f1(x: Int, y: String @Annot("z2")): A = ???
  def f2(x: Int, @Annot("z3") y: String): A = ???
Run Code Online (Sandbox Code Playgroud)

printAnnotations[A]将打印

List(List(), List(Apply(Select(New(Ident(Annot)),<init>),List(Literal(Constant(z1))))))

List(List(List(List(), List())), List(List(List())), List(), List(List(List(), List())), List(List(List(), List(Apply(Select(New(Ident(Annot)),<init>),List(Literal(Constant(z3))))))), List(List()), List(List(List())))

List(List(), List(), List(Apply(Select(New(Ident(Annot)),<init>),List(Literal(Constant(z2))))), List(), List(), List())
Run Code Online (Sandbox Code Playgroud)

斯卡拉3.1.3