diff --git a/core/src/main/scala-3/cats/derived/empty.scala b/core/src/main/scala-3/cats/derived/empty.scala index 0260d426..8fecdd1b 100644 --- a/core/src/main/scala-3/cats/derived/empty.scala +++ b/core/src/main/scala-3/cats/derived/empty.scala @@ -10,22 +10,47 @@ trait DerivedEmpty[A] extends Empty[A]: protected def emptyValue(): A lazy val empty: A = emptyValue() +enum EmptyOrDerived[A]: + case L(empty: Empty[A]) + case R(derived: DerivedEmpty[A]) + +object EmptyOrDerived: + inline given [A]: EmptyOrDerived[A] = summonFrom { + case e: Empty[A] => L(e) + case d: DerivedEmpty[A] => R(d) + } + object DerivedEmpty: inline given [A]: DerivedEmpty[A] = summonFrom { - case given Empty[A] => delegated - case given K0.ProductInstances[DerivedEmpty, A] => product + case given K0.ProductInstances[EmptyOrDerived, A] => product case given K0.CoproductGeneric[A] => coproduct } - - def delegated[A](using A: => Empty[A]): DerivedEmpty[A] = - () => A.empty - def product[A](using inst: K0.ProductInstances[DerivedEmpty, A]): DerivedEmpty[A] = - () => inst.construct([A] => (A: DerivedEmpty[A]) => A.empty) + def product[A](using inst: K0.ProductInstances[EmptyOrDerived, A]): DerivedEmpty[A] = + () => inst.construct([A] => (A: EmptyOrDerived[A]) => + A match { + case EmptyOrDerived.L(e) => e.empty + case EmptyOrDerived.R(d) => d.empty + }) inline def coproduct[A](using gen: K0.CoproductGeneric[A]): DerivedEmpty[A] = - K0.summonFirst[DerivedEmpty, gen.MirroredElemTypes, A] + K0.summonFirst[EmptyOrDerived, gen.MirroredElemTypes, A] match { + case EmptyOrDerived.L(e) => () => e.empty + case EmptyOrDerived.R(d) => d + } trait EmptyDerivation: extension (E: Empty.type) - def derived[A](using instance: DerivedEmpty[A]): Empty[A] = instance + def derived[A](using instance: DerivedEmpty[A]): Empty[A] = + Empty(instance.empty) + + +import empty.derived + +case class Foo(i: Int, b: IntTree) derives Empty +enum IntTree: + case Leaf + case Node(left: IntTree, value: Int, right: IntTree) + +@main def test = + println(Empty[Foo].empty)