Обработка параметров по имени в макросе Scala
У меня есть макрос, который выполняет анализ вложенных функций приложений. Он сопоставляет приложения и извлекает типы параметров следующим образом:
case q"$f[..$targs](..$args)(...$otherArgs)" =>
// retrieve the list of all parameter types
val paramTpes = f.tpe match {
case pmt: PolyType if pmt.paramLists.size == 0 =>
Seq()
case pmt: PolyType =>
pmt.paramLists(0) map {_.typeSignature
.substituteTypes(pmt.typeParams, targs map (_.tpe))}
case pmt: MethodType if pmt.paramLists.size == 0 =>
Seq()
case pmt: MethodType =>
pmt.paramLists(0) map (_.typeSignature)
}
Теперь, если есть параметры по имени, я получаю странный тип, который печатает => T
но ни с чем не может сравниться. Кажется, в API отражений нет средств для их правильной обработки. Что я хотел бы сделать, это получить T
в случае, если это => T
, так как => T
вызывает дальнейшие проблемы в сгенерированном коде.
1 ответ
Обычно используют экстракторы. Иногда мне нужно посмотреть, что такое класс времени выполнения, чтобы вспомнить, какой экстрактор использовать. Я не использую API каждый день.
scala> import reflect.runtime._, universe._
import reflect.runtime._
import universe._
scala> class X { def x(i: => Int) = i * 2 }
defined class X
scala> typeOf[X].member(TermName("x"))
res0: reflect.runtime.universe.Symbol = method x
scala> .typeSignature
res1: reflect.runtime.universe.Type = (i: => scala.Int)scala.Int
scala> res1 match { case MethodType(ps, res) => ps }
res2: List[reflect.runtime.universe.Symbol] = List(value i)
scala> .head
res3: reflect.runtime.universe.Symbol = value i
scala> .typeSignature
res4: reflect.runtime.universe.Type = => scala.Int
scala> res4.getClass
res5: Class[_ <: reflect.runtime.universe.Type] = class scala.reflect.internal.Types$ClassArgsTypeRef
scala> res4 match { case TypeRef(pre, sym, args) => sym }
res6: reflect.runtime.universe.Symbol = class <byname>
scala> res4 match { case TypeRef(pre, sym, args) => args }
res7: List[reflect.runtime.universe.Type] = List(scala.Int)
scala> definitions
res8: reflect.runtime.universe.DefinitionsApi = scala.reflect.internal.Definitions$definitions$@4e80a001
scala> definitions.By
ByNameParamClass ByteClass ByteTpe
scala> definitions.ByNameParamClass
res9: reflect.runtime.universe.ClassSymbol = class <byname>
Я смутно помню специальное имя, но могу ли я получить стабильный префикс для сопоставления с образцом? Я думаю, нет.
scala> res4 match { case TypeRef(pre, definitions.ByNameParamClass, args) => args }
<console>:20: error: stable identifier required, but scala.reflect.runtime.`package`.universe.definitions.ByNameParamClass found.
Note that method ByNameParamClass is not stable because its type, => reflect.runtime.universe.ClassSymbol, is volatile.
res4 match { case TypeRef(pre, definitions.ByNameParamClass, args) => args }
^
scala> val k = definitions.ByNameParamClass
k: reflect.runtime.universe.ClassSymbol = class <byname>
scala> res4 match { case TypeRef(pre, k, args) => args }
res11: List[reflect.runtime.universe.Type] = List(scala.Int)
scala>