Closed
Description
Compiler version
3.1.0
Minimized code
import scala.deriving.Mirror
import scala.util.NotGiven
import scala.compiletime.constValue
trait GetConstValue[T] {
type Out
def get : Out
}
object GetConstValue {
type Aux[T, O] = GetConstValue[T] { type Out = O }
inline given value[T <: Singleton](
using
ev : NotGiven[T <:< Tuple],
) : GetConstValue.Aux[T, T] = {
val out = constValue[T]
new GetConstValue[T] {
type Out = T
def get : Out = out
}
}
given empty : GetConstValue[EmptyTuple] with {
type Out = EmptyTuple
def get : Out = EmptyTuple
}
given nonEmpty[H, HRes, Tail <: Tuple, TRes <: Tuple](
using
head : GetConstValue.Aux[H, HRes],
tail : GetConstValue.Aux[Tail, TRes],
) : GetConstValue[H *: Tail] with {
type Out = HRes *: TRes
def get : Out = head.get *: tail.get
}
}
trait MirrorNamesDeriver[T] {
type Derived <: Tuple
def derive : Derived
}
object MirrorNamesDeriver {
given mirDeriver[T, ElemLabels <: NonEmptyTuple](
using
mir: Mirror.SumOf[T] { type MirroredElemLabels = ElemLabels },
ev : GetConstValue.Aux[ElemLabels, ElemLabels],
): MirrorNamesDeriver[T] with {
type Derived = ElemLabels
def derive: ElemLabels = ev.get
}
def derive[T](using d : MirrorNamesDeriver[T]) : d.Derived = d.derive
}
sealed trait SuperT
final case class SubT1(int: Int) extends SuperT
final case class SubT2(str: String, dbl : Double, bool : Boolean) extends SuperT
// Works when type parameters are set explicitly
val successfulLabels = MirrorNamesDeriver.mirDeriver[SuperT, ("SubT1", "SubT2")].derive
println(successfulLabels)
// Fails when type parameters are inferred
val failedLabels = MirrorNamesDeriver.derive[SuperT]
println(failedLabels)
Output
(SubT1,SubT2)
(())
Expectation
(SubT1, SubT2)
(SubT1, SubT2)
Note that if you change mir: Mirror.SumOf[T]
to mir: Mirror.ProductOf[T]
in mirDeriver
, and you change failedLabels
to MirrorNamesDeriver.derive[SubT2]
, the output is:
(str,dbl,bool)
This means that for Mirror.Product
, the compiler is able to infer the type parameter correctly but not for Mirror.Sum