【问题标题】:Scala macros: Get type arguments of root type of object members inside class definitionScala宏:获取类定义中对象成员的根类型的类型参数
【发布时间】:2016-12-04 23:55:32
【问题描述】:

有点时髦的场景,最好在下面概述。

假设我有sealed trait Painting[T],然后是一堆更专业的变体,比如trait ImpressionistPainting[T] extends Painting[T]等等,构建一个简单的密封类型族。

然后我有一个具有 f 有界多态类型的类:

class Gallery[T <: Gallery[T]]()(implicit helper: GalleryHelper[T])

还有一个:

trait GalleryHelper[T <: Gallery[T]] {
  def paintings: Set[Painting[_]]
}
object GalleryHelper {
  implicit def materialize[T <: Gallery[T]]: GalleyHelper[T] = {
    macro MyMacro.materialize[T]
  }

  def apply[T <: Gallery[T]]()(
   implicit ev: GalleryHelper[T]
  ): GalleryHelper[T] = ev 
}

到目前为止,这是非常基本且简单的 foo 条形码。

此设置的全部目标是宏实现我需要描述画廊的项目的帮助列表,或者在这种情况下任意键入“用户内容”,如下所示:

class MyGallery extends Gallery[MyGallery] {
  object `le-reve` extends CubistPainting[Picasso]
  object starry_night extends PostImpressionistPainting[VanGogh]
  // ..
}

现在有了一些宏兼容的乐趣,我想对有问题的助手进行宏具体化并过滤 T &lt;: Gallery[T] 的成员以提取 MemberType &lt;:&lt; Painting[_] 的成员。

一切都非常简单,下面的代码比简单的type.decls.filter(_.typeSignature &lt;:&lt; typeOf[Filter] 更复杂,因为它还需要按照写入顺序返回所有继承成员的列表,例如,给定画廊扩展其他画廊。

  def findMembersWithBound[T : WeakTypeTag, Filter : TypeTag](
    exclusions: Symbol => Option[Symbol] = { s: Symbol => Some(s) }
  ): Set[Symbol] = {
    val tpe = weakTypeOf[T].typeSymbol.typeSignature

    (
      for {
        baseClass <- tpe.baseClasses.reverse.flatMap(exclusions(_))
        symbol <- baseClass.typeSignature.members.sorted
        if symbol.typeSignature <:< typeOf[Filter]
      } yield symbol
    )(collection.breakOut)
  }

因此,在隐式宏中,类型 T 的模块成员的基本遍历需要按子类型过滤,在本例中为 Painting[_],然后查看用户在扩展时提供了哪些特定类型参数Painting 的变体。类型族是密封的,因此用户使用object 扩展Painting 的子类,而不是直接使用Painting[_],如果这与任何方式相关。

@macrocompat.bundle
class MyMacro(val c: blackbox.Context) {
  import c.universe._
  def materialize[T <: Gallery[T]]: Tree = {
    val galleryTpe = weakTypeOf[T]
    val fields = findMembersWithBound[T, Painting[_]](exclusions)

    val colMembers = sourceMembers.map { member =>
      val memberType = member.typeSignatureIn(galleryTpe)

      memberType.baseClasses.find(colSymbol ==) match {
        case Some(root) => {
          // Herein lies the problem, typeArgs is Nil.
          root.typeSignatureIn(memberType).typeArgs.headOption match {
            case Some(colSignature) => colSignature
            case None => c.abort(
              c.enclosingPosition,
              s"Could not find the artist for ${member.asModule.name}"
          )
        }
      }
      case None => c.abort(c.enclosingPosition, s"Could not find root painting type for ${member.asModule.name}")
    }
  }
}

问题是传递给Painting 的原始类型参数都不再可见,即使typeSignature 会在范围内进行评估等等,我只是想确保 Van梵高并没有成为众所周知的沃尔多。

dealias 的正确 API 是什么,或者让那些 typeArgs 再次可见?当前为空列表。

【问题讨论】:

    标签: scala scala-macros


    【解决方案1】:

    好吧,原来有一种“隐藏得很好”的方法可以使用asSeenFrom 来做到这一点。相关部分是:

    root.typeSignature.typeParams match {
      case head :: Nil => head.asType.toType.asSeenFrom(memberType, colSymbol)
      case _ => c.abort(
        c.enclosingPosition,
       "Expected exactly one type parameter provided for painting type"
      )
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-14
      • 1970-01-01
      • 1970-01-01
      • 2013-05-05
      • 1970-01-01
      • 2012-02-07
      • 1970-01-01
      • 2016-12-05
      相关资源
      最近更新 更多