0

下面的代码片段是一个来自 thinkworks 项目的简短 scala 宏包定义:

  private[SelfType] final class Macros(val c: whitebox.Context) {
    import c.universe._

    def apply[A: WeakTypeTag]: Tree = {
      val a = weakTypeOf[A]
      val selfTypes: List[Type] = {
        val selfTypeBuilder = List.newBuilder[Type]
        def buildSelfTypes(t: Type): Unit = {
          val dealiased = t.dealias
          dealiased match {
            case RefinedType(superTypes, refinedScope) =>
              superTypes.foreach(buildSelfTypes)
            case typeRef: TypeRef =>
              val symbol = dealiased.typeSymbol
              if (symbol.isClass) {
                selfTypeBuilder += symbol.asClass.selfType.asSeenFrom(dealiased, symbol)
              }
            case _ =>
          }
        }
        buildSelfTypes(a)
        selfTypeBuilder.result()
      }
      val out = selfTypes match {
        case Nil =>
          definitions.AnyTpe
        case _ =>
          internal.refinedType(selfTypes, c.internal.enclosingOwner)
      }
      q"_root_.com.thoughtworks.feature.SelfType.make[$a, $out]"

    }

  }

(由https://github.com/ThoughtWorksInc/feature.scala/blob/4d19cc19016d85f26925895f43f618e1b7552d09/SelfType/src/main/scala/com/thoughtworks/feature/SelfType.scala提供)

最后一行作为 quasiquote 似乎包含很多样板文本:

q"_root_.com.thoughtworks.feature.SelfType.make[$a, $out]"

假设这个宏包被定义在一个特征中作为家族多态性设计模式的一部分:没有确定性q"_root_.com.thoughtworks.feature.SelfType.make[$a, $out]",它必须vvv在编译时从宏包的对象变量派生。如何使用此变量使准引用更短且更具适应性?

可能有多种方法可以实现这一点(例如,对于每个实现,为SelfType对象定义一个 Liftable)。但这更是样板。我正在寻找最短的解决方案。理想情况下,是这样的:

val sym = Term(vvv)
q"$sym.make[$a, $out]"
4

2 回答 2

1

如果你有一个静态引用(例如类型/伴侣被导入),你可以这样做:

q"${symbolOf[SelfType.type]}.make[$a, $out]"

symbolOf[A].companion如果您有A: WeakTypeTag但没有关于其伴侣的信息,您也可以使用。如果编译器不考虑object Aclass A

于 2021-04-07T08:39:03.220 回答
-1

找到了我的第一个解决方案:

val name = SelfTypes.getClass.getCanonicalName.stripSuffix("$")
val tree = c.parse(name)
q"$tree.make[$a, $out]"

不确定这是否是最有效或最惯用的解决方案,我会让问题悬在那里一段时间

于 2021-04-06T23:23:01.567 回答