2015-05-25 3 views
1

Я пытаюсь оценить неявный параметр типа 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 содержит минимальный проект для воспроизведения этого.

+0

Могу ли я предположить, что то, что вы пытаетесь сделать здесь, заключается в контрабанде времени компиляции _value_ в реализацию макроса, чтобы его можно было использовать при вычислении времени компиляции? –

+0

@MilesSabin Это звучит о праве. Это появилось в контексте библиотеки [уточненного] (https://github.com/fthomas/refined), где мне нужен этот 'уточнениеLit [MatchesRegex [shapeless.Witness. \' "[0-9] +" \ '.T], String] (" 123 ")', чтобы проверить во время компиляции, что строка "123" соответствует регулярному выражению "[0-9] +". –

+1

Gotcha.'Witness' действительно предназначен для отображения одноэлементных типов в значения _runtime_. Я думаю, вам, вероятно, будет лучше работать непосредственно с вашим аргументом типа N и его тегом типа, а затем повторно использовать логику 'Witness' внутри. Довольно простой способ сделать это будет факторизация основной части макроса 'Witness' в черту, которая может быть смешана вашим собственным макросом. –

ответ