1

假设我有“项目”的特征和这些项目的“容器”的另一个特征:

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

任何人都可以发现问题,或提出更好的解决方法吗?

谢谢!

4

0 回答 0