@@ -5,95 +5,32 @@ import scala.annotation.tailrec
5
5
// The real typeclass derivation is tested in typeclass-derivation3.scala.
6
6
object TypeLevel {
7
7
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
-
19
8
object EmptyProduct extends Product {
20
9
def canEqual (that : Any ): Boolean = true
21
10
def productElement (n : Int ) = throw new IndexOutOfBoundsException
22
11
def productArity = 0
23
12
}
24
13
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 ]
70
21
}
71
22
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
- */
75
23
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 ] {
88
24
type Shape <: Tuple
89
25
}
90
26
91
- abstract class GenericSum [S ] extends Generic2 [S ] {
27
+ abstract class GenericSum [S ] extends Generic [S ] {
92
28
def ordinal (x : S ): Int
93
29
def alternative (n : Int ): GenericProduct [_ <: S ] = ???
94
30
}
95
31
96
- abstract class GenericProduct [P ] extends Generic2 [P ] {
32
+ abstract class GenericProduct [P ] extends Generic [P ] {
33
+ type Prod = P
97
34
def toProduct (x : P ): Product
98
35
def fromProduct (p : Product ): P
99
36
}
@@ -106,22 +43,7 @@ object Lst {
106
43
// common compiler-generated infrastructure
107
44
import TypeLevel ._
108
45
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 ]] {
125
47
override type Shape = (Cons [T ], Nil .type )
126
48
def ordinal (x : Lst [T ]) = x match {
127
49
case x : Cons [_] => 0
@@ -135,7 +57,6 @@ object Lst {
135
57
}
136
58
137
59
implicit def GenericLst [T ]: GenericLst [T ] = new GenericLst [T ]
138
- implicit def Generic2Lst [T ]: Generic2Lst [T ] = new Generic2Lst [T ]
139
60
140
61
case class Cons [T ](hd : T , tl : Lst [T ]) extends Lst [T ]
141
62
@@ -144,7 +65,8 @@ object Lst {
144
65
type Shape = (T , Lst [T ])
145
66
def toProduct (x : Cons [T ]): Product = x
146
67
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 ]])
148
70
}
149
71
implicit def GenericCons [T ]: GenericCons [T ] = new GenericCons [T ]
150
72
}
@@ -176,69 +98,41 @@ object Eq {
176
98
case eq : Eq [T ] => eq.eql(x, y)
177
99
}
178
100
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 =
180
102
inline erasedValue[Elems ] match {
181
103
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 )
184
108
case _ : Unit =>
185
109
true
186
110
}
187
111
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 =
207
113
inline erasedValue[Alts ] match {
208
114
case _ : (alt *: alts1) =>
209
115
if (ord == n)
210
116
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 )
214
122
}
215
- else eqlAlts [T , alts1](x, y, genSum, ord, n + 1 )
123
+ else eqlCases [T , alts1](x, y, genSum, ord, n + 1 )
216
124
case _ : Unit =>
217
125
false
218
126
}
219
127
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 ] {
221
129
def eql (x : T , y : T ): Boolean = {
222
130
inline ev match {
223
131
case evv : GenericSum [T ] =>
224
132
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 )
226
134
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 )
242
136
}
243
137
}
244
138
}
0 commit comments