Can I use the Mirror of a type parameter in a generic class?

Using deriving.Mirror in a generic method allows you to retrieve the names of members for any case class.

//> using scala 3.3.1
import scala.compiletime.*
import scala.deriving.Mirror

inline def labels[T](using m: Mirror.Of[T]) =
    constValueTuple[m.MirroredElemLabels].toList.asInstanceOf[List[Any]]

case class Bbb(id: Int, name: String, value: Double)

println(labels[Bbb]) // => List(id, name, value)

However, attempting the same in a generic class does not seem to work.
For example, the following code results in a compilation error.

//> using scala 3.3.1
import scala.compiletime.*
import scala.deriving.Mirror

class Aaa[T](a: Int)(using m: Mirror.Of[T]):
    inline def labels =
        constValueTuple[m.MirroredElemLabels].toList.asInstanceOf[List[Any]]
        
case class Bbb(id: Int, name: String, value: Double)

println(Aaa[Bbb](1).labels)
cannot reduce inline match with
 scrutinee:  compiletime.erasedValue[deriving.Mirror.Of[Bbb]#MirroredElemLabels] : deriving.Mirror.Of[Bbb]#MirroredElemLabels
 patterns :  case _:EmptyTuple
             case _:*:[t @ _, ts @ _]

How should this difference be understood?

Is it correct to understand that MirroredElemLabels is not obtained as a constant type at compile-time?

Trying the following code results in “Tuple”, causing me some confusion.

//> using scala 3.3.1
import scala.compiletime.*
import scala.deriving.Mirror

class Aaa[T](a: Int)(using m: Mirror.Of[T]):
    inline def whatis =
        inline erasedValue[m.MirroredElemLabels] match
          case _: EmptyTuple => "Empty"
          case _: (t *: ts)  => "Cons"   // pass
          case _: Tuple      => "Tuple"  // match
          case _             => "Unknown"
1 Like