Как проверить, является ли тип каким-то конкретным типом generi c в макросе Scala? - PullRequest
0 голосов
/ 23 февраля 2020

Я хотел бы выполнить обход AST с помощью макросов для типов AST, таких как:

  trait Node

  case class Root(children: Seq[Node]) extends Node {
    override def toString = s"Root(${children.size})"
  }
  case class Bi(left: Node, var right: Node) extends Node
  case class Leaf(id: String) extends Node

В следующем коде я могу обнаружить элементы T, которые имеют тип B, и создать функцию называя их. Я также хотел бы обнаружить члены с типом Seq[B] (и, возможно, другие контейнеры, содержащие B). Я попытался создать тип TypeApply(Ident(TermName("Seq")), List(tq"$B")), который, кажется, работает, однако вызов .tpe для этого возвращает null, поэтому я не могу вызвать <:< для результата.

Как я могу сделать f.asMethod.returnType <:< Seq[B]?

  def walker[B, T <: B]: (T, B => Unit) => Unit = macro walker_impl[B, T]

  def walker_impl[B: c.WeakTypeTag, T: c.WeakTypeTag](c: blackbox.Context): c.Expr[(T, B => Unit) => Unit] = {
    import c.universe._
    val T = weakTypeOf[T]
    val B = weakTypeOf[B]

    val seqType = TypeApply(Ident(TermName("Seq")), List(tq"$B"))
    val dive = T.decls.collect {
      case f if f.isMethod && f.asMethod.paramLists.isEmpty && f.asMethod.isGetter && f.asMethod.returnType <:< B =>
        q"t.$f"
      case f if f.isMethod && f.asMethod.paramLists.isEmpty &&
        f.asMethod.isGetter && f.asMethod.returnType <:< seqType.tpe
      =>
        q"t.$f" // TODO: decompose the seq

    }

    c.Expr[(T, B => Unit) => Unit](
      q"(t: $T, f: $B => Unit) => Seq(..$dive).map(f)"
    )
  }

Полный проект можно посмотреть на https://github.com/OndrejSpanel/ScalaMacroMembers

1 Ответ

0 голосов
/ 23 февраля 2020

Я нашел библиотеку, которая делает подобные вещи, AVSystem / scala -commons . Вдохновленный этими источниками, я реализовал то, что хочу, таким образом:

  val iterable = typeOf[Iterable[Any]]
  val iterableClass = iterable.typeSymbol
  def isSeqB(returnType: Type) = {
    returnType <:< iterable &&
    returnType.baseType(iterableClass).typeArgs.headOption.exists(_ <:< B)
  }

    case f if f.isMethod && f.asMethod.paramLists.isEmpty && f.asMethod.isGetter &&
      isSeqB(f.asMethod.returnType) =>

или просто

val iterableB = weakTypeOf[Iterable[B]]

case f if f.isMethod && f.asMethod.paramLists.isEmpty &&
  f.asMethod.isGetter && f.asMethod.returnType <:< iterableB =>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...