Scala 3 Macro: Get a list of all direct child objects of a sealed trait

I am trying to migrate a piece of scala.reflect code to Scala 3.

Given


sealed trait MyReader
object ReaderA extends MyReader
object ReaderB extends MyReader

How do I write a macro (or inline def?)

inline def findSubclassModulesOfSealedTrait[T]: List[T] = ???

// caller code
val mods = findSubclassModulesOfSealedTrait[MyReader]
// mods = List(ReaderA, ReaderB)

I get to the point where I have a List of all the Symbols and am completely at a loss here:

import scala.quoted.*

object FindClassesMacro {
  def findDirectSubModulesImpl[T](using
      quotes: Quotes,
      t: Type[T]
  ): Expr[Set[T]] = {
    import quotes.reflect.*

    val tpeSym                 = TypeTree.of[T].symbol
    val children: List[Symbol] = tpeSym.children
    val nonModules             = children.filterNot(_.flags.is(Flags.Module))
    val modules                = children.filter(_.flags.is(Flags.Module))

    // TODO
    '{Set.empty}

I have the feeling that this is super simple and that I am missing something trivial, any hints or examples to get me started are highly appreciated.

I think you should be able to reuse the Mirror infrastructure. Type Class Derivation | Scala 3 Language Reference | Scala Documentation

Thanks a lot for driving me off the macro path, this simplifies everything a lot!

It still took me some time to figure out how I get from the type t to the value (object instance) - all the examples summon a given of the type.

This is what I’ve got now:


inline def findSubclassModulesOfSealedTrait[T](using
        m: scala.deriving.Mirror.SumOf[T]
    ): Set[T] = 
      allInstances[m.MirroredElemTypes, m.MirroredType].toSet
    
inline def allInstances[ET <: Tuple, T]: List[T] =
      import scala.compiletime.*

      inline erasedValue[ET] match
        case _: EmptyTuple => Nil
        case _: (t *: ts)  => summonInline[ValueOf[t]].value.asInstanceOf[T] :: allInstances[ts, T]

It seems to work in this test-scastie but is it “safe” or are there loopholes leading to runtime exceptions?

3 Likes