2014-02-04 5 views
2

Я разрабатываю аннотацию scala macro, которая обогащает объекты различными определениями (cf. play form macro). Помимо всего прочего, я хочу, чтобы объект содержал псевдоним типаКак определить псевдоним типа для более высокого типа типа с помощью аннотации scala macro (предпочтительно с использованием квазикварталов)

type WFS = FS[_, _, _, _] 

для различного количества аргументов подстановки.

Я уже пытался извлечь значение одного типа шаблонного

q"type WFS = FS[_]" match { q"type WFS = FS[$t]" => t } 

и надеялся использовать извлеченное значение в списке параметров типа (например, Q "тип WFS = FS [.. $ tplist ] "). Однако приведенное выше утверждение дает ошибку:

scala> q"type WFS = FS[_]" match { case q"type WFS = FS[$t]" => t } 
scala.MatchError: type WFS = FS[_$1] forSome { 
    <synthetic> type _$1 >: _root_.scala.Nothing <: _root_.scala.Any 
} (of class scala.reflect.internal.Trees$TypeDef) 
    at .<init>(<console>:15) 
    at .<clinit>(<console>) 
    at .<init>(<console>:7) 
    at .<clinit>(<console>) 
    at $print(<console>) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43 

Есть ли другой - возможно, проще - способ построения необходимого дерева?

ответ

0

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

scala> q"type WFS = FS[_]" match { case q"type WFS = FS[$a] forSome { $b }" => println(s"$a --- $b") } 
_$1 --- <synthetic> type _$1 >: _root_.scala.Nothing <: _root_.scala.Any 

Если вы хотите, чтобы обеспечить более параметров, а не только один, то лучше использовать "..$x", чтобы учесть, что:

scala> q"type WFS = FS[_]" match { case q"type WFS = FS[..$a] forSome { ..$b }" => println(s"$a --- $b") } 
List(_$1) --- List(<synthetic> type _$1 >: _root_.scala.Nothing <: _root_.scala.Any) 

Wildcards превращается в экзистенциалы - FS[_] означает FS[T] forSome { type T } (подробнее о экзистенциалах, есть Scala Language Sp ecification, Sec. 3.2.10, в разделе «Синтаксис заполнителя для экзистенциальных типов»). Когда вы пишете FS[$a] в своем совпадающем квазиквасоте, это означает «Я ожидаю здесь приложения конструктора типа один аргумент типа». Но FS[T] forSome { type T } является экзистенциальным типом, который содержит приложение конструктора типа к аргументу, поэтому шаблон не будет соответствовать.

Чтобы понять, что лучше, и знать, как отлаживать подобные проблемы, это проницательный смотреть с showRaw на деревьях, порожденных quasiquotes - так как эти типы, нам нужно quasiquotes типа, то есть tq"...":

scala> showRaw(tq"FS[_]") 
res15: String = ExistentialTypeTree(AppliedTypeTree(Ident(newTypeName("FS")), List(Ident(newTypeName("_$1")))), List(TypeDef(Modifiers(DEFERRED | SYNTHETIC), newTypeName("_$1"), List(), TypeBoundsTree(Select(Select(Ident(nme.ROOTPKG), newTermName("scala")), newTypeName("Nothing")), Select(Select(Ident(nme.ROOTPKG), newTermName("scala")), newTypeName("Any")))))) 

scala> showRaw(tq"FS[T]") 
res16: String = AppliedTypeTree(Ident(newTypeName("FS")), List(Ident(newTypeName("T")))) 

Насколько я понимаю, соответствие с квазиквадратами означает соответствие с соответствующим деревом. Таким образом, приведенное выше демонстрирует проблему, которую я описал.

К сожалению, квазиквадраты не скрывают таких деталей системы типа Scala. Это может быть или не быть ошибкой quasiquotes, но я не могу комментировать это - я думаю, было бы здорово, если бы не было необходимости иметь дело с

+1

Спасибо, это было хорошее наблюдение! Теперь я попытался построить тип WFS с помощью типа 'q 'WFS = FS [.. $ typeParams] forSome {.. $ typeDefs}", где каждый 'typeParam' был сконструирован' tq' $ {newTypeName (s "C $ index ")}" 'и каждый' typeDef' на 'q" type $ typeParam "'. К сожалению, это приводит к исключению компилятора: no-symbol не имеет владельца в scala.reflect.internal.SymbolTable.abort (SymbolTable.scala: 49) at scala.tools.nsc.Global.abort (Global.scala: 254) at scala.reflect.internal.Symbols $ NoSymbol.owner (Symbols.scala: 3248) – Stefan

+0

Ой, это эквивалент исключения NullPointerException для символов.Обычно компилятор заполняет символы в деревьях, чтобы сказать, к какому определению (символу) указывает имя. Я не понимаю (пока) макрокоманды, чтобы дать продуманный комментарий - я подозреваю, что вам лучше задавать следующий вопрос с исходным кодом. – Blaisorblade

 Смежные вопросы

  • Нет связанных вопросов^_^