Когда выполняются аннотации макросов Scala? (макро рай) - PullRequest
3 голосов
/ 03 апреля 2019

Я попытался реализовать пример макроаннотаций Scala, как описано в документации .Мне удалось скомпилировать аннотации макросов до того, как реальный проект, который их использует, т. Е. @compileTimeOnly("enable macro paradise to expand macro annotations") не запускается, что означает, что аннотация макроса компилируется перед его использованием.Пока все хорошо.

Однако, когда я аннотирую определенные значения в моем реальном проекте следующим образом:

@identity val foo: Double = 1.1
@identity val bar: String = "bar"

, тогда я ожидаю, что следующая печать произойдет при запуске основного проекта (пример аннотации макроса, связанный ранее):

(<empty>,List(val foo: Double = 1.1))
(<empty>,List(val bar: String = "bar"))

Это то, где я запутался, печать не происходит, когда я запускаю основной проект.Однако он появляется на долю секунды при компиляции основного проекта как предупреждение?

(я использую IntelliJ IDEA и Scala 2.12.8)

1 Ответ

3 голосов
/ 03 апреля 2019

Мне удалось скомпилировать аннотации макросов до того, как фактический проект, который их использует, т. Е. @CompileTimeOnly ("разрешить макро-райзам расширять аннотации макросов") не получает срабатывания, что означает, что аннотации макросов компилируются перед использованием

Нет, запуск @compileTimeOnly будет означать, что аннотация присутствует после компиляции кода с его использованием. Таким образом, отсутствие запуска означает, что макрос был выполнен во время компиляции. А поскольку println находится в теле макроса, а не в преобразованном коде, то вы видите вывод.

Если вы хотите, чтобы печать выполнялась при запуске проекта, вам нужно изменить возвращаемое значение, которое содержит преобразованный код, то есть две последние строки в примере:

val outputs = expandees
c.Expr[Any](Block(outputs, Literal(Constant(()))))

с использованием квазиквот или , непосредственно манипулирующих AST .

Не проверено, но с использованием квазицитатов что-то вроде этого должно работать

object identityMacro {
  def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._
    val inputs = annottees.map(_.tree).toList
    val (annottee, expandees) = inputs match {
      case (param: ValDef) :: (rest @ (_ :: _)) => (param, rest)
      case (param: TypeDef) :: (rest @ (_ :: _)) => (param, rest)
      case _ => (EmptyTree, inputs)
    }
    val stringToPrint = (annottee, expandees).toString
    c.Expr[Any](q"""
    println($stringToPrint)
    $expandees
    ()
    """)
  }
}
...