Извлечете ClassSymbols за границите на параметрите на метода

Опитвам се да извлека ClassSymbols за всички граници на параметрите на типа на метод.

Решението, което измислих:

Внедряване на анотации на макроси:

@compileTimeOnly("Compile-time only annotation")
class classSyms extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro impl
}

object classSyms {
  def impl(c: whitebox.Context)(annottees: c.Tree*) = {
    import c.universe._
    annottees.toList foreach {
      case q"$mods def $templatename[..$typeparams](...$paramss): $tpt = $body" =>
        typeparams foreach {
          case q"$mods type $name[..$tparams] >: $low <: $high" =>
            if (!high.isEmpty) {
              //requires FQCN, does not work with imported names
              val classSymbol = c.mirror.staticClass(high.toString)
              println(classSymbol)
            }
        }
    }
    q"..$annottees"
  }
}

Пример:

package pack.age

trait Test

package another.pack.age

import pack.age._

trait Bar{
  @classSyms
  def foo[M <: pack.age.Test, T](): Unit //works ok


  @classSyms
  def baz[M <: Test, T](): Unit //throws scala.ScalaReflectionException: class Test not found.
}

Проблемът е, че такива изисквания за указване на пълно квалифицирано име на клас като обвързан параметър не правят това внедряване на макроси много полезно (никой не иска да напише този дълъг fqcn материал, особено ако името е импортирано).

Възможно ли е да се извлече ClassSymbol чрез импортирано име?


person Some Name    schedule 31.10.2020    source източник


Отговори (1)


Опитайте да използвате c.typecheck.

Сменете

val classSymbol = c.mirror.staticClass(high.toString)

с

val classSymbol = c.typecheck(tq"$high", mode = c.TYPEmode).symbol.asClass
person Dmytro Mitin    schedule 31.10.2020
comment
Готино, благодаря. Пропуснах смисъла на проверката на типа. Четене на документи Открих, че В допълнение към очертаването на структурата на програмата, дърветата съдържат и важна информация за семантиката на програмата, кодирана в символ (символ, присвоен на дървета, които въвеждат или препращат дефиниции) и tpe (вида на дървото). По подразбиране тези полета са празни, но проверката на типа ги попълва. - person Some Name; 31.10.2020
comment
@SomeName Test на различни места може да има различно значение. Test отнасящо се конкретно до pack.age.Test става известно след проверка на типа на дървото в текущия контекст c. - person Dmytro Mitin; 31.10.2020
comment
@SomeName Вижте фази на компилация: parser (тук низовете на изходния код стават нетипизирани дървета), namer (тук Test става pack.age.Test), typer (тук нетипизираното дърво q"..." става типизирано, т.е. с типове, прикачени към всички негови възли) ... typelevel.org/scala/docs/phases.html - person Dmytro Mitin; 31.10.2020
comment
@SomeName Може би във вашия конкретен случай на използване изпълнението на namer без typer би било достатъчно, но няма API за това. Но по-важното е, че в Scala обикновено имената не могат да бъдат разрешени без проверка на типа. Например имплицитните могат да окажат влияние върху разрешаването на имената, а имплицитните се разрешават по време на проверката на типа. - person Dmytro Mitin; 31.10.2020
comment
@SomeName За разлика от макросите def, манипулиращи типизирани дървета (без c.untypecheck), анотациите на макроси манипулират нетипизирани такива (без c.typecheck). Анотациите за макроси се разширяват преди проверка на типа, макросите def се разширяват по време на проверка на тип. - person Dmytro Mitin; 31.10.2020