Scala макрос, как преобразовать MethodSymbol в DefDef со значениями параметров по умолчанию? - PullRequest
0 голосов
/ 23 марта 2020

Макросы, которые я писал, обычно должны обрабатывать все определения из других объектов / модулей, которые живут в библиотеках и т. Д. c, поэтому деревья недоступны. Внутри макроса мне часто нужно преобразовать MethodSymbol, полученный из другого объекта, в новый вызов API в моей целевой функции, который копирует сигнатуру функции, включая параметры по умолчанию.

Однако я не понял способ получения значений параметров по умолчанию для параметров в MethodSymbol, поэтому при построении результата я не могу «реплицировать» некоторые сигнатуры метода так, как мне бы хотелось.

Есть ли способ получить параметры по умолчанию Скажем, для параметров, полученных из свойства «members» символа «type», для параметров в MethodSymbol?

1 Ответ

1 голос
/ 09 апреля 2020

Вы можете использовать следующую технику

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

def foo[A]: Unit = macro impl[A]

def impl[A: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
  import c.universe._

  // just for testing, in actual use case methodSymbol is obtained from somewhere 
  val methodSymbol = weakTypeOf[A].decl(TermName("smth")).asMethod

  val traverser = new Traverser {
    override def traverse(tree: Tree): Unit = {
      tree match {
        case t @ q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" if t.symbol == methodSymbol =>
          paramss.flatten.foreach {
            case q"$mods1 val $tname1: $tpt1 = $expr1" =>
              println(s"method $tname: default value of $tname1 is $expr1")
            case _ =>
          }
        case _ =>
      }
      super.traverse(tree)
    }
  }

  c.enclosingRun.units.foreach(unit =>
    traverser.traverse(unit.body)
  )

  q"()"
}

object App {

  class MyClass {
    def smth(x: Int = 1): Unit = ()
  }

  foo[MyClass] //Warning:scalac: method smth: default value of x is 1
}
...