2015-05-25 20 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方法具有类型Booleanvalue字段键入Boolean(true)并且编译器需要两种类型相同。

任何想法如何解决这个问题?这甚至支持评估宏中的宏吗?

顺便说一句:这个项目https://github.com/fthomas/scala-macro包含是一个最小的项目来重现这一点。

+0

我是否正确地猜测你在这里试图做的是将一个编译时间_value_走私到一个宏实现中,以便它可以在编译时计算中使用? –

+0

@MilesSabin这听起来是正确的。这出现在[精致](https://github.com/fthomas/refined)库中,我希望这个'refineLit [MatchesRegex [shapeless.Witness。\'“[0-9] +”\ '.T],String](“123”)'在编译时检查字符串“123”是否匹配正则表达式“[0-9] +”。 –

+1

Gotcha.'Witness'实际上是用于将singleton类型映射到_runtime_值。我认为你最好直接用你的类型参数'N'和它的类型标记,然后在内部重用'Witness'的逻辑。一个相当直接的做法是将大量的“见证”宏分解成可以由你自己的宏混入的特性。 –

回答