Как динамически сгенерировать приложение типа с помощью scala квазиквот - PullRequest
0 голосов
/ 02 апреля 2020

Я хочу сгенерировать приложение типа, чтобы я мог вызвать функцию типа foo.bar[com.a.b.SomeType](baz), где com.a.b.SomeType может быть любым из широкого диапазона типов. Я использовал отражение во время выполнения макроса, чтобы получить ссылку на фактический класс, представленный SomeType, чтобы я мог делать такие вещи, как получение имени пакета, простого имени и полного имени.

Когда я пишу tq"com.a.b.SomeType" Я получаю желаемые результаты и могу использовать интерполяцию в своем выражении, например,

val someType = tq"com.a.b.SomeType"
q"""
  foo.bar[$someType](baz)
"""

Мне нужно динамически создать это tq выражение, используя информацию о классе, которую я могу получить из среды выполнения макроса из строка. Я посмотрел на дерево, сгенерированное tq"com.example.SomeType", и для каждого из пакетов com, a, b, c есть ряд вложенных Select узлов, который кажется неудобным для генерации вручную.

Select(Select(Select(Ident(TermName("com")), TermName("a")), TermName("b")), TypeName("SomeType"))

Я полагаю, что есть более простой способ, которого я просто не вижу.

С этой целью я попробовал что-то вроде:

tq"${someType.getPackage.getName}.${someType.getSimpleName}"

, но я вижу, что это неправильно и получить такие ошибки, как:

Compilation error[MyMacro.this.c.universe.Name expected but MyMacro.this.c.universe.Tree found]

Итак, каков краткий способ добиться того, что я пытаюсь сделать, когда имя типа доступно только через отражение, например, как экземпляр Class?

1 Ответ

0 голосов
/ 02 апреля 2020

Вы не можете получить тип из отражения во время выполнения, потому что этот тип будет использоваться в сгенерированном коде и получаться в двоичном виде. Однако вы можете получить тип во время компиляции с сайта вызова, используя TypeTag или WeakTypeTag

def myMethod[T] = macro macroImplementation

def macroImplementation[T: c.WeakTypeTag](c: Context) = {
  val typeT = weakTypeOf[T].tpe
  val body = q"""
    foo.bar[$typeT](baz)
  """
  ...
}

, что позволит вам создавать макросы для методов с параметрами типа, которые вы могли бы безопасно заполнить время выполнения (тогда typeT будет следить не за тем, что вы используете известный тип, а за тем, что вы используете что-то из параметра типа, а не из ничего).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...