在 2.13 中你可以实现scala.ValueOf
val instanceTree = c.inferImplicitValue(appliedType(typeOf[ValueOf[_]].typeConstructor, subSymbol.asClass.toType))
q"$instanceTree.value"
树会有所不同
sealed trait A
object A {
case object B extends A
case object C extends A
}
//scalac: Seq(new scala.ValueOf(A.this.B).value, new scala.ValueOf(A.this.C).value)
但在运行时它仍然是Seq(B, C)。
在 2.12 中可以使用shapeless.Witness 代替ValueOf
val instanceTree = c.inferImplicitValue(appliedType(typeOf[Witness.Aux[_]].typeConstructor, subSymbol.asClass.toType))
q"$instanceTree.value"
//scalac: Seq(Witness.mkWitness[App.A.B.type](A.this.B.asInstanceOf[App.A.B.type]).value, Witness.mkWitness[App.A.C.type](A.this.C.asInstanceOf[App.A.C.type]).value)
libraryDependencies += "com.chuusai" %% "shapeless" % "2.4.0-M1" // in 2.3.3 it doesn't work
在Shapeless中,他们使用一种
subSymbol.asClass.toType match {
case ref @ TypeRef(_, sym, _) if sym.isModuleClass => mkAttributedQualifier(ref)
}
https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/singletons.scala#L230
或者在我们的例子中只是
mkAttributedQualifier(subSymbol.asClass.toType)
但他们的mkAttributedQualifier 也使用向下转换到编译器内部,并且获得的树类似于Seq(A.this.B, A.this.C)。
还有
Ident(subSymbol.companionSymbol)
似乎可以工作(树是 Seq(B, C))但 .companionSymbol 已被弃用(在 scaladocs 中它被写成“可能为模块类返回意外结果”,即对象)。
以下方法类似于 @MateuszKubuszok 在他的库中使用的方法enumz 你也可以尝试
val objectName = symbol.fullName
c.typecheck(c.parse(s"$objectName"))
树是Seq(App.A.B, App.A.C)。
最后,如果您对树 Seq(B, C)(而不是更复杂的树)感兴趣,您似乎可以替换
Ident(subSymbol.asInstanceOf[scala.reflect.internal.Symbols#Symbol].sourceModule.asInstanceOf[Symbol])
更传统的
Ident(subSymbol.owner.info.decl(subSymbol.name.toTermName))