@@ -5,95 +5,32 @@ import scala.annotation.tailrec
55// The real typeclass derivation is tested in typeclass-derivation3.scala.
66object TypeLevel {
77
8- /** A generic representation of a case in an ADT
9- * @param deriving The companion object of the ADT
10- * @param ordinal The ordinal value of the case in the list of the ADT's cases
11- * @param elems The elements of the case
12- */
13- class Mirror (val ordinal : Int , val elems : Product ) {
14-
15- /** The `n`'th element of this generic case */
16- def apply (n : Int ): Any = elems.productElement(n)
17- }
18-
198 object EmptyProduct extends Product {
209 def canEqual (that : Any ): Boolean = true
2110 def productElement (n : Int ) = throw new IndexOutOfBoundsException
2211 def productArity = 0
2312 }
2413
25- object Mirror {
26-
27- /** A mirror of case with ordinal number `ordinal` and elements as given by `Product` */
28- def apply (ordinal : Int , product : Product ): Mirror =
29- new Mirror (ordinal, product)
30-
31- /** A mirror with elements given as an array */
32- def apply (ordinal : Int , elems : Array [AnyRef ]): Mirror =
33- apply(ordinal, new ArrayProduct (elems))
34-
35- /** A mirror with an initial empty array of `numElems` elements, to be filled in. */
36- def apply (ordinal : Int , numElems : Int ): Mirror =
37- apply(ordinal, new Array [AnyRef ](numElems))
38-
39- /** A mirror of a case with no elements */
40- def apply (ordinal : Int ): Mirror =
41- apply(ordinal, EmptyProduct )
42-
43- /** Helper class to turn arrays into products */
44- private class ArrayProduct (val elems : Array [AnyRef ]) extends Product {
45- def canEqual (that : Any ): Boolean = true
46- def productElement (n : Int ) = elems(n)
47- def productArity = elems.length
48- override def productIterator : Iterator [Any ] = elems.iterator
49- def update (n : Int , x : Any ) = elems(n) = x.asInstanceOf [AnyRef ]
50- }
51-
52- /** Helper object */
53- private object EmptyProduct extends Product {
54- def canEqual (that : Any ): Boolean = true
55- def productElement (n : Int ) = throw new IndexOutOfBoundsException
56- def productArity = 0
57- }
58- }
59-
60- /** The shape of an ADT.
61- * This is eithe a product (`Case`) or a sum (`Cases`) of products.
62- */
63- enum Shape {
64-
65- /** A sum with alternative types `Alts` */
66- case Cases [Alts <: Tuple ]
67-
68- /** A product type `T` with element types `Elems` */
69- case Case [T , Elems <: Tuple ]
14+ /** Helper class to turn arrays into products */
15+ class ArrayProduct (val elems : Array [AnyRef ]) extends Product {
16+ def canEqual (that : Any ): Boolean = true
17+ def productElement (n : Int ) = elems(n)
18+ def productArity = elems.length
19+ override def productIterator : Iterator [Any ] = elems.iterator
20+ def update (n : Int , x : Any ) = elems(n) = x.asInstanceOf [AnyRef ]
7021 }
7122
72- /** Every generic derivation starts with a typeclass instance of this type.
73- * It informs that type `T` has shape `S` and also implements runtime reflection on `T`.
74- */
7523 abstract class Generic [T ] {
76- /** The shape of the `T` */
77- type Shape <: TypeLevel .Shape
78-
79-
80- /** The case mirror corresponding to ADT instance `x` */
81- def reflect (x : T ): Mirror
82-
83- /** The ADT instance corresponding to given `mirror` */
84- def reify (mirror : Mirror ): T
85- }
86-
87- abstract class Generic2 [T ] {
8824 type Shape <: Tuple
8925 }
9026
91- abstract class GenericSum [S ] extends Generic2 [S ] {
27+ abstract class GenericSum [S ] extends Generic [S ] {
9228 def ordinal (x : S ): Int
9329 def alternative (n : Int ): GenericProduct [_ <: S ] = ???
9430 }
9531
96- abstract class GenericProduct [P ] extends Generic2 [P ] {
32+ abstract class GenericProduct [P ] extends Generic [P ] {
33+ type Prod = P
9734 def toProduct (x : P ): Product
9835 def fromProduct (p : Product ): P
9936 }
@@ -106,22 +43,7 @@ object Lst {
10643 // common compiler-generated infrastructure
10744 import TypeLevel ._
10845
109- class GenericLst [T ] extends Generic [Lst [T ]] {
110- type Shape = Shape .Cases [(
111- Shape .Case [Cons [T ], (T , Lst [T ])],
112- Shape .Case [Nil .type , Unit ]
113- )]
114- def reflect (xs : Lst [T ]): Mirror = xs match {
115- case xs : Cons [T ] => Mirror (0 , xs)
116- case Nil => Mirror (1 )
117- }
118- def reify (c : Mirror ): Lst [T ] = c.ordinal match {
119- case 0 => Cons [T ](c(0 ).asInstanceOf , c(1 ).asInstanceOf )
120- case 1 => Nil
121- }
122- }
123-
124- class Generic2Lst [T ] extends GenericSum [Lst [T ]] {
46+ class GenericLst [T ] extends GenericSum [Lst [T ]] {
12547 override type Shape = (Cons [T ], Nil .type )
12648 def ordinal (x : Lst [T ]) = x match {
12749 case x : Cons [_] => 0
@@ -135,7 +57,6 @@ object Lst {
13557 }
13658
13759 implicit def GenericLst [T ]: GenericLst [T ] = new GenericLst [T ]
138- implicit def Generic2Lst [T ]: Generic2Lst [T ] = new Generic2Lst [T ]
13960
14061 case class Cons [T ](hd : T , tl : Lst [T ]) extends Lst [T ]
14162
@@ -144,7 +65,8 @@ object Lst {
14465 type Shape = (T , Lst [T ])
14566 def toProduct (x : Cons [T ]): Product = x
14667 def fromProduct (p : Product ): Cons [T ] =
147- Cons (p.productElement(0 ).asInstanceOf , p.productElement(1 ).asInstanceOf )
68+ Cons (p.productElement(0 ).asInstanceOf [T ],
69+ p.productElement(1 ).asInstanceOf [Cons [T ]])
14870 }
14971 implicit def GenericCons [T ]: GenericCons [T ] = new GenericCons [T ]
15072 }
@@ -176,69 +98,41 @@ object Eq {
17698 case eq : Eq [T ] => eq.eql(x, y)
17799 }
178100
179- inline def eqlElems [Elems <: Tuple ](xm : Mirror , ym : Mirror , n : Int ): Boolean =
101+ inline def eqlElems [Elems <: Tuple ](x : Product , y : Product , n : Int ): Boolean =
180102 inline erasedValue[Elems ] match {
181103 case _ : (elem *: elems1) =>
182- tryEql[elem](xm(n).asInstanceOf , ym(n).asInstanceOf ) &&
183- eqlElems[elems1](xm, ym, n + 1 )
104+ tryEql[elem](
105+ x.productElement(n).asInstanceOf [elem],
106+ y.productElement(n).asInstanceOf [elem]) &&
107+ eqlElems[elems1](x, y, n + 1 )
184108 case _ : Unit =>
185109 true
186110 }
187111
188- inline def eqlCases [Alts <: Tuple ](xm : Mirror , ym : Mirror , n : Int ): Boolean =
189- inline erasedValue[Alts ] match {
190- case _ : (Shape .Case [alt, elems] *: alts1) =>
191- if (xm.ordinal == n) eqlElems[elems](xm, ym, 0 )
192- else eqlCases[alts1](xm, ym, n + 1 )
193- case _ : Unit =>
194- false
195- }
196-
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 =
112+ inline def eqlCases [T , Alts <: Tuple ](x : T , y : T , genSum : GenericSum [T ], ord : Int , inline n : Int ): Boolean =
207113 inline erasedValue[Alts ] match {
208114 case _ : (alt *: alts1) =>
209115 if (ord == n)
210116 inline genSum.alternative(n) match {
211- case genProd => eqlProducts[genProd.Shape ](
212- genProd.toProduct(x.asInstanceOf ),
213- genProd.toProduct(y.asInstanceOf ), 0 )
117+ case cas =>
118+ eqlElems[cas.Shape ](
119+ cas.toProduct(x.asInstanceOf [cas.Prod ]),
120+ cas.toProduct(y.asInstanceOf [cas.Prod ]),
121+ 0 )
214122 }
215- else eqlAlts [T , alts1](x, y, genSum, ord, n + 1 )
123+ else eqlCases [T , alts1](x, y, genSum, ord, n + 1 )
216124 case _ : Unit =>
217125 false
218126 }
219127
220- inline def derived [T ](implicit ev : Generic2 [T ]): Eq [T ] = new Eq [T ] {
128+ inline def derived [T ](implicit ev : Generic [T ]): Eq [T ] = new Eq [T ] {
221129 def eql (x : T , y : T ): Boolean = {
222130 inline ev match {
223131 case evv : GenericSum [T ] =>
224132 val ord = evv.ordinal(x)
225- ord == evv.ordinal(y) && eqlAlts [T , evv.Shape ](x, y, evv, ord, 0 )
133+ ord == evv.ordinal(y) && eqlCases [T , evv.Shape ](x, y, evv, ord, 0 )
226134 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 {
233- def eql (x : T , y : T ): Boolean = {
234- val xm = ev.reflect(x)
235- val ym = ev.reflect(y)
236- inline erasedValue[ev.Shape ] match {
237- case _ : Shape .Cases [alts] =>
238- xm.ordinal == ym.ordinal &&
239- eqlCases[alts](xm, ym, 0 )
240- case _ : Shape .Case [_, elems] =>
241- eqlElems[elems](xm, ym, 0 )
135+ eqlElems[evv.Shape ](evv.toProduct(x), evv.toProduct(y), 0 )
242136 }
243137 }
244138 }
0 commit comments