@@ -16,6 +16,12 @@ object TypeLevel {
1616 def apply (n : Int ): Any = elems.productElement(n)
1717 }
1818
19+ object EmptyProduct extends Product {
20+ def canEqual (that : Any ): Boolean = true
21+ def productElement (n : Int ) = throw new IndexOutOfBoundsException
22+ def productArity = 0
23+ }
24+
1925 object Mirror {
2026
2127 /** A mirror of case with ordinal number `ordinal` and elements as given by `Product` */
@@ -67,16 +73,30 @@ object TypeLevel {
6773 * It informs that type `T` has shape `S` and also implements runtime reflection on `T`.
6874 */
6975 abstract class Generic [T ] {
70-
7176 /** The shape of the `T` */
7277 type Shape <: TypeLevel .Shape
7378
79+
7480 /** The case mirror corresponding to ADT instance `x` */
7581 def reflect (x : T ): Mirror
7682
7783 /** The ADT instance corresponding to given `mirror` */
7884 def reify (mirror : Mirror ): T
7985 }
86+
87+ abstract class Generic2 [T ] {
88+ type Shape <: Tuple
89+ }
90+
91+ abstract class GenericSum [S ] extends Generic2 [S ] {
92+ def ordinal (x : S ): Int
93+ def alternative (n : Int ): GenericProduct [_ <: S ] = ???
94+ }
95+
96+ abstract class GenericProduct [P ] extends Generic2 [P ] {
97+ def toProduct (x : P ): Product
98+ def fromProduct (p : Product ): P
99+ }
80100}
81101
82102// An algebraic datatype
@@ -101,10 +121,41 @@ object Lst {
101121 }
102122 }
103123
124+ class Generic2Lst [T ] extends GenericSum [Lst [T ]] {
125+ override type Shape = (Cons [T ], Nil .type )
126+ def ordinal (x : Lst [T ]) = x match {
127+ case x : Cons [_] => 0
128+ case Nil => 1
129+ }
130+ inline override def alternative (inline n : Int ) <: GenericProduct [_ <: Lst [T ]] =
131+ inline n match {
132+ case 0 => Cons .GenericCons [T ]
133+ case 1 => Nil .GenericNil
134+ }
135+ }
136+
104137 implicit def GenericLst [T ]: GenericLst [T ] = new GenericLst [T ]
138+ implicit def Generic2Lst [T ]: Generic2Lst [T ] = new Generic2Lst [T ]
105139
106140 case class Cons [T ](hd : T , tl : Lst [T ]) extends Lst [T ]
107- case object Nil extends Lst [Nothing ]
141+
142+ object Cons {
143+ class GenericCons [T ] extends GenericProduct [Cons [T ]] {
144+ type Shape = (T , Lst [T ])
145+ def toProduct (x : Cons [T ]): Product = x
146+ def fromProduct (p : Product ): Cons [T ] =
147+ Cons (p.productElement(0 ).asInstanceOf , p.productElement(1 ).asInstanceOf )
148+ }
149+ implicit def GenericCons [T ]: GenericCons [T ] = new GenericCons [T ]
150+ }
151+ case object Nil extends Lst [Nothing ] {
152+ class GenericNil extends GenericProduct [Nil .type ] {
153+ type Shape = Unit
154+ def toProduct (x : Nil .type ): Product = EmptyProduct
155+ def fromProduct (p : Product ): Nil .type = Nil
156+ }
157+ implicit def GenericNil : GenericNil = new GenericNil
158+ }
108159
109160 // three clauses that could be generated from a `derives` clause
110161 implicit def derived$Eq [T : Eq ]: Eq [Lst [T ]] = Eq .derived
@@ -143,7 +194,42 @@ object Eq {
143194 false
144195 }
145196
146- inline def derived [T , S <: Shape ](implicit ev : Generic [T ]): Eq [T ] = new {
197+ inline def eqlProducts [Elems <: Tuple ](x : Product , y : Product , n : Int ): Boolean =
198+ inline erasedValue[Elems ] match {
199+ case _ : (elem *: elems1) =>
200+ tryEql[elem](x.productElement(n).asInstanceOf , y.productElement(n).asInstanceOf ) &&
201+ eqlProducts[elems1](x, y, n + 1 )
202+ case _ : Unit =>
203+ true
204+ }
205+
206+ inline def eqlAlts [T , Alts <: Tuple ](x : T , y : T , genSum : GenericSum [T ], ord : Int , inline n : Int ): Boolean =
207+ inline erasedValue[Alts ] match {
208+ case _ : (alt *: alts1) =>
209+ if (ord == n)
210+ inline genSum.alternative(n) match {
211+ case genProd => eqlProducts[genProd.Shape ](
212+ genProd.toProduct(x.asInstanceOf ),
213+ genProd.toProduct(y.asInstanceOf ), 0 )
214+ }
215+ else eqlAlts[T , alts1](x, y, genSum, ord, n + 1 )
216+ case _ : Unit =>
217+ false
218+ }
219+
220+ inline def derived [T ](implicit ev : Generic2 [T ]): Eq [T ] = new Eq [T ] {
221+ def eql (x : T , y : T ): Boolean = {
222+ inline ev match {
223+ case evv : GenericSum [T ] =>
224+ val ord = evv.ordinal(x)
225+ ord == evv.ordinal(y) && eqlAlts[T , evv.Shape ](x, y, evv, ord, 0 )
226+ case evv : GenericProduct [T ] =>
227+ eqlProducts[evv.Shape ](evv.toProduct(x), evv.toProduct(y), 0 )
228+ }
229+ }
230+ }
231+
232+ inline def derived2 [T , S <: Shape ](implicit ev : Generic [T ]): Eq [T ] = new {
147233 def eql (x : T , y : T ): Boolean = {
148234 val xm = ev.reflect(x)
149235 val ym = ev.reflect(y)
0 commit comments