Skip to content

Commit 0c28594

Browse files
committed
Use staged macros to implement parts of Tuple
1 parent 8ce3ea2 commit 0c28594

File tree

2 files changed

+277
-234
lines changed

2 files changed

+277
-234
lines changed
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
package scala
2+
3+
import scala.quoted._
4+
5+
object StagedTuple {
6+
import Tuple._
7+
import NonEmptyTuple._
8+
9+
def toArrayStaged(tup: Expr[Tuple], size: Option[Int]): Expr[Array[Object]] = {
10+
if (!specialize) '(dynamicToArray(~tup))
11+
else size match {
12+
case Some(0) =>
13+
'($emptyArray)
14+
case Some(1) =>
15+
tup.as[Tuple1[Object]].bind(t => '(Array((~t)._1)))
16+
case Some(2) =>
17+
tup.as[Tuple2[Object, Object]].bind(t => '(Array((~t)._1, (~t)._2)))
18+
case Some(3) =>
19+
tup.as[Tuple3[Object, Object, Object]].bind(t => '(Array((~t)._1, (~t)._2, (~t)._3)))
20+
case Some(4) =>
21+
tup.as[Tuple4[Object, Object, Object, Object]].bind(t => '(Array((~t)._1, (~t)._2, (~t)._3, (~t)._4)))
22+
case Some(n) if n <= $MaxSpecialized =>
23+
'($toArray(~tup, ~n.toExpr))
24+
case Some(n) =>
25+
'((~tup.as[TupleXXL]).elems)
26+
case None =>
27+
'(dynamicToArray(~tup))
28+
}
29+
}
30+
31+
def fromArrayStaged[T <: Tuple : Type](xs: Expr[Array[Object]], size: Option[Int]): Expr[T] = {
32+
if (!specialize) '(dynamicFromArray[T](~xs))
33+
else {
34+
val tup = size match {
35+
case Some(0) => '()
36+
case Some(1) => '(Tuple1( (~xs)(0)))
37+
case Some(2) => '(Tuple2( (~xs)(0), (~xs)(1)))
38+
case Some(3) => '(Tuple3( (~xs)(0), (~xs)(1), (~xs)(2)))
39+
case Some(4) => '(Tuple4( (~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3)))
40+
case Some(5) => '(Tuple5( (~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4)))
41+
case Some(6) => '(Tuple6( (~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5)))
42+
case Some(7) => '(Tuple7( (~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6)))
43+
case Some(8) => '(Tuple8( (~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7)))
44+
case Some(9) => '(Tuple9( (~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8)))
45+
case Some(10) => '(Tuple10((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9)))
46+
case Some(11) => '(Tuple11((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10)))
47+
case Some(12) => '(Tuple12((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11)))
48+
case Some(13) => '(Tuple13((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12)))
49+
case Some(14) => '(Tuple14((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13)))
50+
case Some(15) => '(Tuple15((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13), (~xs)(14)))
51+
case Some(16) => '(Tuple16((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13), (~xs)(14), (~xs)(15)))
52+
case Some(17) => '(Tuple17((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13), (~xs)(14), (~xs)(15), (~xs)(16)))
53+
case Some(18) => '(Tuple18((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13), (~xs)(14), (~xs)(15), (~xs)(16), (~xs)(17)))
54+
// FIXME: some kind of limit is reached while testing CompilationTests.tastyBootstrap
55+
// case Some(19) => '(Tuple19((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13), (~xs)(14), (~xs)(15), (~xs)(16), (~xs)(17), (~xs)(18)))
56+
// case Some(20) => '(Tuple20((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13), (~xs)(14), (~xs)(15), (~xs)(16), (~xs)(17), (~xs)(18), (~xs)(19)))
57+
// case Some(21) => '(Tuple21((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13), (~xs)(14), (~xs)(15), (~xs)(16), (~xs)(17), (~xs)(18), (~xs)(19), (~xs)(20)))
58+
// case Some(22) => '(Tuple22((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13), (~xs)(14), (~xs)(15), (~xs)(16), (~xs)(17), (~xs)(18), (~xs)(19), (~xs)(20), (~xs)(21)))
59+
case Some(_) => '(TupleXXL(~xs))
60+
case None => '(dynamicFromArray[T](~xs))
61+
}
62+
tup.as[T]
63+
}
64+
}
65+
66+
def sizeStaged[Res <: Int : Type](tup: Expr[Tuple], size: Option[Int]): Expr[Res] = {
67+
val res =
68+
if (!specialize) '(dynamicSize(~tup))
69+
else size match {
70+
case Some(n) => n.toExpr
71+
case None => '(dynamicSize(~tup))
72+
}
73+
res.as[Res]
74+
}
75+
76+
def headStaged[Tup <: NonEmptyTuple : Type](tup: Expr[Tup], size: Option[Int]): Expr[Head[Tup]] = {
77+
if (!specialize) '(dynamicHead(~tup))
78+
else {
79+
val resVal = size match {
80+
case Some(1) =>
81+
'((~tup.as[Tuple1[_]])._1)
82+
case Some(2) =>
83+
'((~tup.as[Tuple2[_, _]])._1)
84+
case Some(3) =>
85+
'((~tup.as[Tuple3[_, _, _]])._1)
86+
case Some(4) =>
87+
'((~tup.as[Tuple4[_, _, _, _]])._1)
88+
case Some(n) if n > 4 && n <= $MaxSpecialized =>
89+
'((~tup.as[Product]).productElement(0))
90+
case Some(n) if n > $MaxSpecialized =>
91+
'((~tup.as[TupleXXL]).elems(0))
92+
case None =>
93+
'(dynamicHead(~tup))
94+
}
95+
resVal.as[Head[Tup]]
96+
}
97+
}
98+
99+
def tailStaged[Tup <: NonEmptyTuple : Type](tup: Expr[Tup], size: Option[Int]): Expr[Tail[Tup]] = {
100+
if (!specialize) '(dynamicTail[Tup](~tup))
101+
else {
102+
val res = size match {
103+
case Some(1) =>
104+
'()
105+
case Some(2) =>
106+
tup.as[Tuple2[_, _]].bind(t => '(Tuple1((~t)._2)))
107+
case Some(3) =>
108+
tup.as[Tuple3[_, _, _]].bind(t => '(Tuple2((~t)._2, (~t)._3)))
109+
case Some(4) =>
110+
tup.as[Tuple4[_, _, _, _]].bind(t => '(Tuple3((~t)._2, (~t)._3, (~t)._4)))
111+
case Some(5) =>
112+
tup.as[Tuple5[_, _, _, _, _]].bind(t => '(Tuple4((~t)._2, (~t)._3, (~t)._4, (~t)._5)))
113+
case Some(n) if n > 5 =>
114+
val arr = toArrayStaged(tup, size)
115+
fromArrayStaged('((~arr).tail) , Some(n - 1))
116+
case None =>
117+
'(dynamicTail(~tup))
118+
}
119+
res.as[Tail[Tup]]
120+
}
121+
}
122+
123+
def applyStaged[Tup <: NonEmptyTuple : Type, N <: Int : Type](tup: Expr[Tup], size: Option[Int], n: Expr[N], nValue: Option[Int]): Expr[Elem[Tup, N]] = {
124+
if (!specialize) '(dynamicApply(~tup, ~n))
125+
else {
126+
def fallbackApply(): Expr[Elem[Tup, N]] = nValue match {
127+
case Some(n) => quoted.QuoteError("index out of bounds: " + n)
128+
case None => '(dynamicApply(~tup, ~n))
129+
}
130+
val res = size match {
131+
case Some(1) =>
132+
val t = tup.as[Tuple1[_]]
133+
nValue match {
134+
case Some(0) => '((~t)._1)
135+
case _ => fallbackApply()
136+
}
137+
case Some(2) =>
138+
val t = tup.as[Tuple2[_, _]]
139+
nValue match {
140+
case Some(0) => '((~t)._1)
141+
case Some(1) => '((~t)._2)
142+
case _ => fallbackApply()
143+
}
144+
case Some(3) =>
145+
val t = tup.as[Tuple3[_, _, _]]
146+
nValue match {
147+
case Some(0) => '((~t)._1)
148+
case Some(1) => '((~t)._2)
149+
case Some(2) => '((~t)._3)
150+
case _ => fallbackApply()
151+
}
152+
case Some(4) =>
153+
val t = tup.as[Tuple4[_, _, _, _]]
154+
nValue match {
155+
case Some(0) => '((~t)._1)
156+
case Some(1) => '((~t)._2)
157+
case Some(2) => '((~t)._3)
158+
case Some(3) => '((~t)._4)
159+
case _ => fallbackApply()
160+
}
161+
case Some(s) if s > 4 && s <= $MaxSpecialized =>
162+
val t = tup.as[Product]
163+
nValue match {
164+
case Some(n) if n >= 0 && n < s => '((~t).productElement(~n.toExpr))
165+
case _ => fallbackApply()
166+
}
167+
case Some(s) if s > $MaxSpecialized =>
168+
val t = tup.as[TupleXXL]
169+
nValue match {
170+
case Some(n) if n >= 0 && n < s => '((~t).elems(~n.toExpr))
171+
case _ => fallbackApply()
172+
}
173+
case _ => fallbackApply()
174+
}
175+
res.as[Elem[Tup, N]]
176+
}
177+
}
178+
179+
def stagedCons[T <: Tuple & Singleton : Type, H : Type](self: Expr[T], x: Expr[H], tailSize: Option[Int]): Expr[H *: T] =
180+
if (!specialize) '(dynamic_*:[T, H](~self, ~x))
181+
else {
182+
val res = tailSize match {
183+
case Some(0) =>
184+
'(Tuple1(~x))
185+
case Some(1) =>
186+
self.as[Tuple1[_]].bind(t => '(Tuple2(~x, (~t)._1)))
187+
case Some(2) =>
188+
self.as[Tuple2[_, _]].bind(t => '(Tuple3(~x, (~t)._1, (~t)._2)))
189+
case Some(3) =>
190+
self.as[Tuple3[_, _, _]].bind(t => '(Tuple4(~x, (~t)._1, (~t)._2, (~t)._3)))
191+
case Some(4) =>
192+
self.as[Tuple4[_, _, _, _]].bind(t => '(Tuple5(~x, (~t)._1, (~t)._2, (~t)._3, (~t)._4)))
193+
case Some(n) =>
194+
fromArrayStaged('($consArray(~x, ~toArrayStaged(self, tailSize))), Some(n + 1))
195+
case _ =>
196+
'(dynamic_*:[T, H](~self, ~x))
197+
}
198+
res.as[H *: T]
199+
}
200+
201+
def stagedConcat[Self <: Tuple & Singleton : Type, That <: Tuple & Singleton : Type](self: Expr[Self], selfSize: Option[Int], that: Expr[That], thatSize: Option[Int]): Expr[Concat[Self, That]] = {
202+
if (!specialize) '(dynamic_++[Self, That](~self, ~that))
203+
else {
204+
def genericConcat(xs: Expr[Tuple], ys: Expr[Tuple]): Expr[Tuple] =
205+
fromArrayStaged[Tuple]('((~toArrayStaged(xs, None)) ++ (~toArrayStaged(ys, None))), None)
206+
207+
val res = selfSize match {
208+
case Some(0) =>
209+
that
210+
case Some(1) =>
211+
if (thatSize.contains(0)) self
212+
else stagedCons(that, self.as[Tuple1[_]], thatSize)
213+
case Some(2) =>
214+
val self2 = self.as[Tuple2[_, _]]
215+
thatSize match {
216+
case Some(0) => self
217+
case Some(1) =>
218+
self2.bind { t =>
219+
that.as[Tuple1[_]].bind(u => '(Tuple3((~t)._1, (~t)._2, (~u)._1)))
220+
}
221+
case Some(2) =>
222+
self2.bind { t =>
223+
that.as[Tuple2[_, _]].bind(u => '(Tuple4((~t)._1, (~t)._2, (~u)._1, (~u)._2)))
224+
}
225+
case _ =>
226+
genericConcat(self, that)
227+
}
228+
case Some(3) =>
229+
val self2 = self.as[Tuple3[_, _, _]]
230+
thatSize match {
231+
case Some(0) => self
232+
case Some(1) =>
233+
self2.bind { t =>
234+
that.as[Tuple1[_]].bind(u => '(Tuple4((~t)._1, (~t)._2, (~t)._3, (~u)._1)))
235+
}
236+
case _ =>
237+
genericConcat(self, that)
238+
}
239+
case Some(_) =>
240+
if (thatSize.contains(0)) self
241+
else genericConcat(self, that)
242+
case None =>
243+
'(dynamic_++(~self, ~that))
244+
}
245+
res.as[Concat[Self, That]]
246+
}
247+
}
248+
249+
private implicit class ExprOps[U: Type](expr: Expr[U]) {
250+
251+
def as[T: Type]: Expr[T] = '{ (~expr).asInstanceOf[T] }
252+
253+
def bind[T](in: Expr[U] => Expr[T]): Expr[T] = '{
254+
val t: U = (~expr)
255+
~(in('(t)))
256+
}
257+
258+
}
259+
260+
}

0 commit comments

Comments
 (0)