scala: Как получить имя класса через сложный полиморфизм с макросами времени компиляции? - PullRequest
0 голосов
/ 21 апреля 2019

При попытке получить имя класса с помощью ссылки WeakTypeTag при определении реализации макроса, я не могу получить правильную информацию, если применяется несколько слоев полиморфизма.

Например, если у меня есть следующие настройки:

object MacroSupport {
  def get_name_impl[A: c.WeakTypeTag](c: blackbox.Context): c.Expr[String] = {
    val nameOfA: String = weakTypeOf[A].toString
    ...
  }

  def getName[A] = macro get_name_impl[A]
}

abstract class GenericInterface[T] {
  def getName: String = MacroSupport.getName[T]
}

case class ContainerA(
  someValue: String
)

class FunctionalClass extends GenericInterface[ContainerA] {
  val containerName: String = getName
}

Я надеюсь достичь любого количества FunctionalClass, каждый со своим собственным классом Container, и они могут сообщить имя своего контейнера, который используется для некоторой мета-конфигурации. В основном MacroSupport и GenericInterface будут существовать в библиотеке, которую я пишу, в то время как уровни FunctionalClass и Container будут написаны другими, использующими библиотеку.

Проблема, возникшая у меня из-за сквозного типа в GenericInterface, FunctionalClass.containerName == "t" и попыток доступа к объявлениям типа, ничего не дает. Как получить информацию о типе из объявления FunctionalClass до уровня MacroSupport?

1 Ответ

1 голос
/ 21 апреля 2019

Попробуйте выполнить материализацию класса типа

https://docs.scala -lang.org / Overviews / macros / implicits.html # implicit-materializers

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

object MacroSupport {
  def getName[A](implicit gn: GetName[A]): String = gn()

  trait GetName[A] {
    def apply(): String
  }

  object GetName {
    implicit def materializeGetName[A]: GetName[A] = macro materializeGetNameImpl[A]

    def materializeGetNameImpl[A: c.WeakTypeTag](c: blackbox.Context): c.Expr[GetName[A]] = {
      import c.universe._

      c.Expr[GetName[A]] {
        q"""
          new MacroSupport.GetName[${weakTypeOf[A]}] {
             override def apply(): _root_.java.lang.String = ${weakTypeOf[A].toString}
          }
         """
      }
    }
  }
}

import MacroSupport.GetName

abstract class GenericInterface[T: GetName] {
  def getName: String = MacroSupport.getName[T]
}

case class ContainerA(
                      someValue: String
                     )

class FunctionalClass extends GenericInterface[ContainerA] {
  val containerName: String = getName
}

(new FunctionalClass).containerName // ContainerA

ПоКстати, shapeless.Typeable делает свою работу.Typeable[A].describe как наш MacroSupport.getName[A].

...