假设我有“项目”的特征和这些项目的“容器”的另一个特征:
sealed trait Item
case class Marble() extends Item
case class Book() extends Item
sealed trait Container[Item]
case object Pouch extends Container[Marble]
case object Shelf extends Container[Book]
使用上面的类型信息,我想通过宏和一些运行时反射来构造一个这样的映射:
// Map(classOf[Marble] -> Pouch, classOf[Book] -> Shelf)
val itemToContainer = typeParamMap[Container[_], Item](Pouch, Shelf)
这是我的尝试,它编译得很好,并且以只返回 TypeTags 列表的中间形式工作:
object Macros {
def getTag[T](implicit ttag: ru.TypeTag[T]) = ttag
def getBaseParam(child: ru.Type, base: ru.Symbol, paramBase: ru.Symbol) =
child.baseType(base)
.find(_.baseClasses.contains(paramBase))
.get
.typeSymbol
.asClass // TODO how to get java.lang.Class from here?
def typeParamMapImpl[B, P](c: Context)(children: c.Expr[B]*)(baseTag: c.Expr[ru.WeakTypeTag[B]], paramTag: c.Expr[ru.WeakTypeTag[P]]) = {
import c.universe._
val getTagTree = Select(Ident(newTermName("Macros")), "getTag")
val typeTags = c.Expr[List[ru.TypeTag[_]]](Apply(reify(List).tree, children.map( t =>
c.Expr(TypeApply(getTagTree, List(t.tree))).tree
).toList))
reify {
typeTags.splice.map { child =>
getBaseParam(child.tpe, baseTag.splice.tpe.typeSymbol, paramTag.splice.tpe.typeSymbol) -> child.tpe
}.toMap
}
}
def typeParamMap[B, P](children: B*)(implicit baseTag: ru.WeakTypeTag[B], paramTag: ru.WeakTypeTag[P]) = macro Macros.typeParamMapImpl[B, P]
}
但是,当我尝试通过调用它进行编译时,我得到一个巨大的编译器错误:https ://gist.github.com/4647812
任何人都可以发现问题,或提出更好的解决方法吗?
谢谢!