为什么编译器不考虑对象?

Ryo*_*Oka 0 macros enums scala

我试着收集一个密封班的孩子们:

import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros

object Enum {
  def values[A]: Seq[A] = macro EnumImpl.values[A]

  class EnumImpl(val c: Context) {
    import c.universe._

    implicit class SymbolOp(s: Symbol) {
      def asSealedClass = s.asClass.ensuring(_.isSealed, s"$s is not sealed")
      def asCaseClass = s.asClass.ensuring(_.isCaseClass, s"$s is not a case class")
    }

    def values[A: c.WeakTypeTag]: c.Expr[A] = {
      val enumSymbol = weakTypeOf[A].typeSymbol.asSealedClass
      val elemSymbols = enumSymbol.knownDirectSubclasses.toList
      val elemIdents = elemSymbols.map(s => Ident(s.asCaseClass))
      val elemSeqSymbol = weakTypeOf[Seq[A]].typeSymbol
      c.Expr(Apply(Ident(elemSeqSymbol.companion), elemIdents))
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我测试了这个:

sealed trait Foo
case object Moo extends Foo

println(Enum.values[Foo])
Run Code Online (Sandbox Code Playgroud)

然后编译器声称:

object Moo is not a value
Run Code Online (Sandbox Code Playgroud)

所以我尝试了它的同伴:

...
val elemIdents = elemSymbols.map(s => Ident(s.asCaseClass.companion))
...
Run Code Online (Sandbox Code Playgroud)

然后编译器声称:

not found: value <none>
Run Code Online (Sandbox Code Playgroud)

所以对象Moo不是XD对象

我究竟做错了什么?

gzm*_*zm0 5

编译器代码中的这个图描述了类模块和模块类的一般情况(内部对象称为模块):

The internal representation of classes and objects:

class Foo is "the class" or sometimes "the plain class"
object Foo is "the module"
class Foo$ is "the module class" (invisible to the user: it implements object Foo)

class Foo  <
^   ^ (2)   \
|   |  |     \
|  (5) |     (3)
|   |  |       \
(1) v  v        \
object Foo (4)-> > class Foo$

(1) companionClass
(2) companionModule
(3) linkedClassOfClass
(4) moduleClass
(5) companionSymbol
Run Code Online (Sandbox Code Playgroud)

这些东西都是内部的.但是,重要的是要看到,当您查询特征的子类时,您将获得模块类而不是模块本身.

您可以通过调用module模块类符号从模块类到模块:

val elemIdents = for {
  elemSym <- elemSymbols
  if elemSym.isModuleClass // TODO fail if not a module class? Ignore?
} yield Ident(elemSym.asClass.module)
Run Code Online (Sandbox Code Playgroud)