Skip to content

MirroredElemLabels of Mirror.Sum inferred to be EmptyTuple #14150

Closed
@johnhungerford

Description

@johnhungerford

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions