给定我具有模块类的Scala宏,获取模块符号

问题描述

我正在尝试使用宏来构建简单的类型类IsEnum[T]

如果kNownDirectSubclasses,我使用T获取所有直接子类,确保T是密封特征,并且所有子类都是case对象(使用subSymbol.asClass.isModuleClass && subSymbol.asClass.isCaseClass

现在,我正在尝试使用子类引用的case对象构建一个Seq

正在使用一种解决方法

  Ident(subSymbol.asInstanceOf[scala.reflect.internal.Symbols#Symbol].sourceModule.asInstanceOf[Symbol])

但是我从其他question那里复制了它,但看起来似乎很错误。为什么行得通?有没有更清洁的方法来实现这一目标?

解决方法

在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))

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...