Использование ClassSymbol в квазицитатах

У меня есть ClassSymbol и я хочу сгенерировать метод без аргументов, выдающий ???. Вот мои попытки:

Предположим, что object Test — это тип, которого у нас есть ClassSymbol.

Я.

val sym = //the ClassSymbol
val tpe = tq"$sym.type"
q"def foo(): $tpe = ???"

Результат:

[error]  stable identifier required, but Test.type found.

II.

val sym = //the ClassSymbol
val tpe = tq"${sym.name}.type"
q"def foo(): $tpe = ???"

Результат:

[error]  found   : c.universe.TypeName
[error]  required: c.universe.TermName
[error]         val tpe = tq"${sym.name}.type"

III.

val sym = //the ClassSymbol
val tpe = tq"${TermName(sym.name.toString)}.type"
q"def foo(): $tpe = ???"

Результат:

Compiles successfully

Так что я остановился на методе III, который выглядит довольно пугающе.

Есть ли собственный способ использовать ClassSymbol в квазицитатах?


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


Ответы (1)


Мы можем сохранить ваш подход II

val tpe = tq"${sym.name.toTermName}.type"

Это похоже на III, но без ручной обработки строк.

Так же не забывайте, что кроме квазикавычек всегда можно строить деревья с ручным разбором

val tree = tb.parse(s"def foo(): ${sym.name}.type = ???") // for macros c.parse instead of tb.parse 

Что касается нативного способа, то сейчас лучше использовать ModuleSymbol

val sym = rm.moduleSymbol(Test.getClass)

or

val sym = typeOf[Test.type].termSymbol.asModule 

а не ClassSymbol

val sym0 = rm.classSymbol(Test.getClass)

or

val sym0 = typeOf[Test.type].typeSymbol.asClass 

Тестирование:

val tpe = tq"$sym.type"
val tree = q"def foo(): $tpe = ???"
tb.typecheck(tree) // no exception

Я использовал отражение во время выполнения, но для макросов это похоже.

Если у вас уже есть ClassSymbol, его можно преобразовать в ModuleSymbol.

val sym = sym0.companionSymbol // not sym0.companion but .companionSymbol is deprecated

or

val sym = sym0.asInstanceOf[scala.reflect.internal.Symbols#ClassSymbol].sourceModule.asInstanceOf[ModuleSymbol]

or

val sym = sym0.owner.info.decl(sym0.name.toTermName)

Получите символ модуля, учитывая, что у меня есть класс модуля, макрос scala

person Dmytro Mitin    schedule 31.10.2020
comment
Спасибо. Я предполагаю, что при использовании произвольного типа класса его следует проверить на наличие Module (isModule) перед вставкой суффикса .type. - person Some Name; 01.11.2020