Я пытаюсь оценить неявный параметр типа shapeless.Witness.Aux[T]
в макросе, чтобы использовать значение одноэлементного типа 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()
}
Мне кажется, проблема в том, что в дереве без проверки типов метод value
имеет тип Boolean
, а поле value
имеет тип Boolean(true)
, и компилятору нужно, чтобы оба типа были одинаковыми.
Любые идеи, как обойти это? Поддерживается ли это даже для оценки макроса в макросе?
Кстати: этот проект https://github.com/fthomas/scala-macro содержит минимальный проект для воспроизведения этого.
refineLit[MatchesRegex[shapeless.Witness.`"[0-9]+"`.T], String]("123")
проверял во время компиляции, что строка 123 соответствует регулярному выражению [0-9]+. - person Frank S. Thomas   schedule 25.05.2015Witness
действительно предназначен для сопоставления одноэлементных типов со значениями runtime. Я думаю, вам, вероятно, было бы лучше работать напрямую с вашим аргументом типаN
и его тегом типа, а затем повторно использовать логикуWitness
внутри. Довольно простым способом сделать это было бы разложить большую часть макросаWitness
на черту, которую можно смешать с вашим собственным макросом. - person Miles Sabin   schedule 25.05.2015refineLit
(называемыйrefine
), который основан на том же механизме проверки и для которогоWitness
отлично работает. - person Frank S. Thomas   schedule 26.05.2015scala.tools.reflect.ToolBoxError: reflective toolbox has failed: cannot operate on trees that are already typed
. Явная повторная проверка дерева с помощьюc.typecheck(untypechecked)
снова дает мне дерево, в котором полеvalue
имеет типBoolean(true)
, а методvalue
имеет типBoolean
. В остальном он идентичен оригинальномуaux.tree
. - person Frank S. Thomas   schedule 27.05.2015eval
для всегоWitness
, можете ли вы перемещаться по дереву и извлекать поддерево, соответствующее правой части определения val/def? Затем вы можете использовать это как дерево или оценить его самостоятельно (что, как я ожидаю, будет работать правильно). - person Miles Sabin   schedule 27.05.2015Witness
. Например.MatchesRegex[Witness.`"[0-9]+"`.T] Or Equal[Witness.`"abc"`.T]]
был бы предикатом, который я хотел бы поддерживать. Я не уверен, как навигация и извлечение поддеревьев помогут мне здесь. Возможно, я мог бы сделать более слабую версиюWitness
, гдеvalue
имеет менее точный тип, чемT
. Может быть, что-то вродеtrait WeakWitness { type T; val value: AnyVal }
может сработать. Или, еслиvalue
будет иметь неодноэлементный типT
, это тоже должно работать. - person Frank S. Thomas   schedule 27.05.2015WeakWitness
в своей бесформенной вилке. И это работает! Я могу вычислитьWeakWitness
в макросе и использовать тамvalue
(value
имеет типBoolean
, аT
этоBoolean(true)
. Думаю, мне следует продолжить обсуждение в бесформенном PR. - person Frank S. Thomas   schedule 27.05.2015