@@ -16,6 +16,12 @@ object TypeLevel {
16
16
def apply (n : Int ): Any = elems.productElement(n)
17
17
}
18
18
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
+
19
25
object Mirror {
20
26
21
27
/** A mirror of case with ordinal number `ordinal` and elements as given by `Product` */
@@ -67,16 +73,30 @@ object TypeLevel {
67
73
* It informs that type `T` has shape `S` and also implements runtime reflection on `T`.
68
74
*/
69
75
abstract class Generic [T ] {
70
-
71
76
/** The shape of the `T` */
72
77
type Shape <: TypeLevel .Shape
73
78
79
+
74
80
/** The case mirror corresponding to ADT instance `x` */
75
81
def reflect (x : T ): Mirror
76
82
77
83
/** The ADT instance corresponding to given `mirror` */
78
84
def reify (mirror : Mirror ): T
79
85
}
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
+ }
80
100
}
81
101
82
102
// An algebraic datatype
@@ -101,10 +121,41 @@ object Lst {
101
121
}
102
122
}
103
123
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
+
104
137
implicit def GenericLst [T ]: GenericLst [T ] = new GenericLst [T ]
138
+ implicit def Generic2Lst [T ]: Generic2Lst [T ] = new Generic2Lst [T ]
105
139
106
140
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
+ }
108
159
109
160
// three clauses that could be generated from a `derives` clause
110
161
implicit def derived$Eq [T : Eq ]: Eq [Lst [T ]] = Eq .derived
@@ -143,7 +194,42 @@ object Eq {
143
194
false
144
195
}
145
196
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 {
147
233
def eql (x : T , y : T ): Boolean = {
148
234
val xm = ev.reflect(x)
149
235
val ym = ev.reflect(y)
0 commit comments