Я пытаюсь оценить неявный параметр типа shapeless.Witness.Aux[T]
в макросе, чтобы использовать значение одноэлементного типа T. Это минимальный пример:Оценка выражения типа shapeless.Witness.Aux [T] в макросе не удается
import shapeless.Witness
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
object Macro {
def foo[N](implicit aux: Witness.Aux[N]): Unit = macro fooImpl[N]
def fooImpl[N: c.WeakTypeTag](c: Context)
(aux: c.Expr[Witness.Aux[N]]): c.Expr[Unit] = {
import c.universe._
val typechecked = aux.tree
println("Typechecked tree:")
println(show(typechecked))
val untypechecked = c.untypecheck(typechecked)
println("Untypechecked tree:")
println(show(untypechecked))
def eval = c.eval(c.Expr(untypechecked))
val w = scala.util.Try(eval).getOrElse(eval)
// now use w.value
c.Expr[Unit](q"()")
}
}
Но составление этого
val w = shapeless.Witness(true)
Macro.foo[w.T]
выдает следующее сообщение об ошибке:
[error] overriding value value in trait Witness of type fresh$macro$2.this.T;
[error] value value has incompatible type
Выход println(show(typechecked))
является:
{
final class fresh$macro$2 extends AnyRef with shapeless.Witness {
def <init>(): fresh$macro$2 = {
fresh$macro$2.super.<init>();
()
};
type T = Boolean(true);
private[this] val value: Boolean(true) = true;
<stable> <accessor> def value: Boolean(true) = true
};
new fresh$macro$2()
}
Выход println(show(untypechecked))
является:
{
final class fresh$macro$2 extends AnyRef with _root_.shapeless.Witness {
def <init>() = {
super.<init>();
()
};
type T = Boolean(true);
private[this] val value: Boolean(true) = true;
<stable> <accessor> def value: Boolean = true
};
new fresh$macro$2()
}
я, мне кажется, что проблема заключается в том, что в untypechecked дерева метод value
имеет тип Boolean
в то время как value
поле имеет тип Boolean(true)
, и для компилятора оба типа должны быть одинаковыми.
Любые идеи, как обойти это? Поддерживается ли это даже при оценке макроса в макросе?
BTW: Этот проект https://github.com/fthomas/scala-macro содержит минимальный проект для воспроизведения этого.
Могу ли я предположить, что то, что вы пытаетесь сделать здесь, заключается в контрабанде времени компиляции _value_ в реализацию макроса, чтобы его можно было использовать при вычислении времени компиляции? –
@MilesSabin Это звучит о праве. Это появилось в контексте библиотеки [уточненного] (https://github.com/fthomas/refined), где мне нужен этот 'уточнениеLit [MatchesRegex [shapeless.Witness. \' "[0-9] +" \ '.T], String] (" 123 ")', чтобы проверить во время компиляции, что строка "123" соответствует регулярному выражению "[0-9] +". –
Gotcha.'Witness' действительно предназначен для отображения одноэлементных типов в значения _runtime_. Я думаю, вам, вероятно, будет лучше работать непосредственно с вашим аргументом типа N и его тегом типа, а затем повторно использовать логику 'Witness' внутри. Довольно простой способ сделать это будет факторизация основной части макроса 'Witness' в черту, которая может быть смешана вашим собственным макросом. –