Очень простая макрокоманда макросов, поддерживаемая макросом.Макросы Scala: подпись типа типа от ValDef
def impl(c: blackbox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
annottees.map(_.tree) match {
case (classDef @ q"$mods class $tpname[..$tparams] $ctorMods(...$params) extends { ..$earlydefns } with ..$parents { $self => ..$stats }")
:: Nil if mods.hasFlag(Flag.CASE) =>
val name = tpname.toTermName
val typeName = tpname.toTypeName
val res = q"""
$classDef
object $name {
..${doStuff(c)(typeName, name, params.head)}
}
"""
c.Expr[Any](res)
case _ => c.abort(c.enclosingPosition, "Invalid annotation target, this must be a case class")
}
}
Так что все очень простое прямое удовольствие. Бит, вызывающий проблемы, возникает из $params
выше, которые являются только List[List[ValDef]]
, а именно так, что подпись типа теряется.
def accessors(c: blackbox.Context)(
params: Seq[c.universe.ValDef]
): Iterable[(c.universe.TermName, c.universe.TypeName)] = {
import c.universe._
params.map {
case ValDef(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree) => {
// tpt.tpe = kaboom, null pointer
name -> TypeName(tpt.tpe.typeSymbol.fullName)
}
}
}
tpe
на ValDef
возвращается как null
, поэтому DEFS не наберется, но мне нужен тип подписи Params, чтобы достичь того, чего я хочу. Как я могу получить подпись типа params без его взрыва?
Как ни странно, showCode(tpt)
действительно производит строку правильного типа, так что это можно обойти с TypeName(tpt.toString)
, но я не знаю, почему tpe
не доступен.
Вы можете взглянуть на ответ и комментарии Евгения Burmako в этом вопросе: http://stackoverflow.com/questions/23671379/proper-way-to-pattern-match-the- Valu е-оф-а-typetree-с-а-valdef-в-макро-лестницы –