Skip to content

Commit 3c9f76c

Browse files
committed
Fix tuple match types
Removed all use of match types inside the implementation of the staged tuples. Pass the expansion of match types as type parameters instead.
1 parent da0c249 commit 3c9f76c

File tree

4 files changed

+130
-116
lines changed

4 files changed

+130
-116
lines changed

library/src-scala3/scala/StagedTuple.scala

Lines changed: 116 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -72,59 +72,61 @@ object StagedTuple {
7272
res.as[Res]
7373
}
7474

75-
def headStaged[Tup <: NonEmptyTuple : Type](tup: Expr[Tup], size: Option[Int]): Expr[Head[Tup]] = {
76-
if (!specialize) '(dynamicHead(~tup))
77-
else {
78-
val resVal = size match {
79-
case Some(1) =>
80-
'((~tup.as[Tuple1[_]])._1)
81-
case Some(2) =>
82-
'((~tup.as[Tuple2[_, _]])._1)
83-
case Some(3) =>
84-
'((~tup.as[Tuple3[_, _, _]])._1)
85-
case Some(4) =>
86-
'((~tup.as[Tuple4[_, _, _, _]])._1)
87-
case Some(n) if n > 4 && n <= $MaxSpecialized =>
88-
'((~tup.as[Product]).productElement(0))
89-
case Some(n) if n > $MaxSpecialized =>
90-
'((~tup.as[TupleXXL]).elems(0))
91-
case None =>
92-
'(dynamicHead(~tup))
75+
def headStaged[Head : Type](tup: Expr[NonEmptyTuple], size: Option[Int]): Expr[Head] = {
76+
val res=
77+
if (!specialize) '(dynamicHead(~tup))
78+
else {
79+
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+
}
9395
}
94-
resVal.as[Head[Tup]]
95-
}
96+
res.as[Head]
9697
}
9798

98-
def tailStaged[Tup <: NonEmptyTuple : Type](tup: Expr[Tup], size: Option[Int]): Expr[Tail[Tup]] = {
99-
if (!specialize) '(dynamicTail[Tup](~tup))
100-
else {
101-
val res = size match {
102-
case Some(1) =>
103-
'()
104-
case Some(2) =>
105-
tup.as[Tuple2[_, _]].bind(t => '(Tuple1((~t)._2)))
106-
case Some(3) =>
107-
tup.as[Tuple3[_, _, _]].bind(t => '(Tuple2((~t)._2, (~t)._3)))
108-
case Some(4) =>
109-
tup.as[Tuple4[_, _, _, _]].bind(t => '(Tuple3((~t)._2, (~t)._3, (~t)._4)))
110-
case Some(5) =>
111-
tup.as[Tuple5[_, _, _, _, _]].bind(t => '(Tuple4((~t)._2, (~t)._3, (~t)._4, (~t)._5)))
112-
case Some(n) if n > 5 =>
113-
val arr = toArrayStaged(tup, size)
114-
fromArrayStaged('((~arr).tail) , Some(n - 1))
115-
case None =>
116-
'(dynamicTail(~tup))
99+
def tailStaged[Tail <: Tuple : Type](tup: Expr[NonEmptyTuple], size: Option[Int]): Expr[Tail] = {
100+
val res =
101+
if (!specialize) '(dynamicTail(~tup))
102+
else {
103+
size match {
104+
case Some(1) =>
105+
'()
106+
case Some(2) =>
107+
tup.as[Tuple2[_, _]].bind(t => '(Tuple1((~t)._2)))
108+
case Some(3) =>
109+
tup.as[Tuple3[_, _, _]].bind(t => '(Tuple2((~t)._2, (~t)._3)))
110+
case Some(4) =>
111+
tup.as[Tuple4[_, _, _, _]].bind(t => '(Tuple3((~t)._2, (~t)._3, (~t)._4)))
112+
case Some(5) =>
113+
tup.as[Tuple5[_, _, _, _, _]].bind(t => '(Tuple4((~t)._2, (~t)._3, (~t)._4, (~t)._5)))
114+
case Some(n) if n > 5 =>
115+
val arr = toArrayStaged(tup, size)
116+
fromArrayStaged('((~arr).tail) , Some(n - 1))
117+
case None =>
118+
'(dynamicTail(~tup))
119+
}
117120
}
118-
res.as[Tail[Tup]]
119-
}
121+
res.as[Tail]
120122
}
121123

122-
def applyStaged[Tup <: NonEmptyTuple : Type, N <: Int : Type](tup: Expr[Tup], size: Option[Int], n: Expr[N], nValue: Option[Int]): Expr[Elem[Tup, N]] = {
123-
if (!specialize) '(dynamicApply(~tup, ~n))
124+
def applyStaged[Elem : Type](tup: Expr[NonEmptyTuple], size: Option[Int], n: Expr[Int], nValue: Option[Int]): Expr[Elem] = {
125+
if (!specialize) ('(dynamicApply(~tup, ~n))).as[Elem]
124126
else {
125-
def fallbackApply(): Expr[Elem[Tup, N]] = nValue match {
127+
def fallbackApply(): Expr[Elem] = nValue match {
126128
case Some(n) => quoted.QuoteError("index out of bounds: " + n)
127-
case None => '(dynamicApply(~tup, ~n))
129+
case None => ('(dynamicApply(~tup, ~n))).as[Elem]
128130
}
129131
val res = size match {
130132
case Some(1) =>
@@ -171,78 +173,81 @@ object StagedTuple {
171173
}
172174
case _ => fallbackApply()
173175
}
174-
res.as[Elem[Tup, N]]
176+
res.as[Elem]
175177
}
176178
}
177179

178-
def stagedCons[T <: Tuple & Singleton : Type, H : Type](self: Expr[T], x: Expr[H], tailSize: Option[Int]): Expr[H *: T] =
179-
if (!specialize) '(dynamic_*:[T, H](~self, ~x))
180-
else {
181-
val res = tailSize match {
182-
case Some(0) =>
183-
'(Tuple1(~x))
184-
case Some(1) =>
185-
self.as[Tuple1[_]].bind(t => '(Tuple2(~x, (~t)._1)))
186-
case Some(2) =>
187-
self.as[Tuple2[_, _]].bind(t => '(Tuple3(~x, (~t)._1, (~t)._2)))
188-
case Some(3) =>
189-
self.as[Tuple3[_, _, _]].bind(t => '(Tuple4(~x, (~t)._1, (~t)._2, (~t)._3)))
190-
case Some(4) =>
191-
self.as[Tuple4[_, _, _, _]].bind(t => '(Tuple5(~x, (~t)._1, (~t)._2, (~t)._3, (~t)._4)))
192-
case Some(n) =>
193-
fromArrayStaged('($consArray(~x, ~toArrayStaged(self, tailSize))), Some(n + 1))
194-
case _ =>
195-
'(dynamic_*:[T, H](~self, ~x))
196-
}
197-
res.as[H *: T]
180+
def stagedCons[Res <: NonEmptyTuple : Type, H : Type](self: Expr[Tuple], x: Expr[H], tailSize: Option[Int]): Expr[Res] = {
181+
val res =
182+
if (!specialize) '(dynamic_*:(~self, ~x))
183+
else {
184+
tailSize match {
185+
case Some(0) =>
186+
'(Tuple1(~x))
187+
case Some(1) =>
188+
self.as[Tuple1[_]].bind(t => '(Tuple2(~x, (~t)._1)))
189+
case Some(2) =>
190+
self.as[Tuple2[_, _]].bind(t => '(Tuple3(~x, (~t)._1, (~t)._2)))
191+
case Some(3) =>
192+
self.as[Tuple3[_, _, _]].bind(t => '(Tuple4(~x, (~t)._1, (~t)._2, (~t)._3)))
193+
case Some(4) =>
194+
self.as[Tuple4[_, _, _, _]].bind(t => '(Tuple5(~x, (~t)._1, (~t)._2, (~t)._3, (~t)._4)))
195+
case Some(n) =>
196+
fromArrayStaged('($consArray(~x, ~toArrayStaged(self, tailSize))), Some(n + 1))
197+
case _ =>
198+
'(dynamic_*:(~self, ~x))
199+
}
200+
}
201+
res.as[Res]
198202
}
199203

200-
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]] = {
201-
if (!specialize) '(dynamic_++[Self, That](~self, ~that))
202-
else {
203-
def genericConcat(xs: Expr[Tuple], ys: Expr[Tuple]): Expr[Tuple] =
204-
fromArrayStaged[Tuple]('((~toArrayStaged(xs, None)) ++ (~toArrayStaged(ys, None))), None)
205-
206-
val res = selfSize match {
207-
case Some(0) =>
208-
that
209-
case Some(1) =>
210-
if (thatSize.contains(0)) self
211-
else stagedCons(that, self.as[Tuple1[_]], thatSize)
212-
case Some(2) =>
213-
val self2 = self.as[Tuple2[_, _]]
214-
thatSize match {
215-
case Some(0) => self
216-
case Some(1) =>
217-
self2.bind { t =>
218-
that.as[Tuple1[_]].bind(u => '(Tuple3((~t)._1, (~t)._2, (~u)._1)))
219-
}
220-
case Some(2) =>
221-
self2.bind { t =>
222-
that.as[Tuple2[_, _]].bind(u => '(Tuple4((~t)._1, (~t)._2, (~u)._1, (~u)._2)))
223-
}
224-
case _ =>
225-
genericConcat(self, that)
226-
}
227-
case Some(3) =>
228-
val self2 = self.as[Tuple3[_, _, _]]
229-
thatSize match {
230-
case Some(0) => self
231-
case Some(1) =>
232-
self2.bind { t =>
233-
that.as[Tuple1[_]].bind(u => '(Tuple4((~t)._1, (~t)._2, (~t)._3, (~u)._1)))
234-
}
235-
case _ =>
236-
genericConcat(self, that)
237-
}
238-
case Some(_) =>
239-
if (thatSize.contains(0)) self
240-
else genericConcat(self, that)
241-
case None =>
242-
'(dynamic_++(~self, ~that))
204+
// FIXME: remove Concat[Self, That]
205+
def stagedConcat[Concat <: Tuple : Type](self: Expr[Tuple], selfSize: Option[Int], that: Expr[Tuple], thatSize: Option[Int]): Expr[Concat] = {
206+
val res =
207+
if (!specialize) '(dynamic_++(~self, ~that))
208+
else {
209+
def genericConcat(xs: Expr[Tuple], ys: Expr[Tuple]): Expr[Tuple] =
210+
fromArrayStaged[Tuple]('((~toArrayStaged(xs, None)) ++ (~toArrayStaged(ys, None))), None)
211+
selfSize match {
212+
case Some(0) =>
213+
that
214+
case Some(1) =>
215+
if (thatSize.contains(0)) self
216+
else stagedCons(that, self.as[Tuple1[_]], thatSize)
217+
case Some(2) =>
218+
val self2 = self.as[Tuple2[_, _]]
219+
thatSize match {
220+
case Some(0) => self
221+
case Some(1) =>
222+
self2.bind { t =>
223+
that.as[Tuple1[_]].bind(u => '(Tuple3((~t)._1, (~t)._2, (~u)._1)))
224+
}
225+
case Some(2) =>
226+
self2.bind { t =>
227+
that.as[Tuple2[_, _]].bind(u => '(Tuple4((~t)._1, (~t)._2, (~u)._1, (~u)._2)))
228+
}
229+
case _ =>
230+
genericConcat(self, that)
231+
}
232+
case Some(3) =>
233+
val self2 = self.as[Tuple3[_, _, _]]
234+
thatSize match {
235+
case Some(0) => self
236+
case Some(1) =>
237+
self2.bind { t =>
238+
that.as[Tuple1[_]].bind(u => '(Tuple4((~t)._1, (~t)._2, (~t)._3, (~u)._1)))
239+
}
240+
case _ =>
241+
genericConcat(self, that)
242+
}
243+
case Some(_) =>
244+
if (thatSize.contains(0)) self
245+
else genericConcat(self, that)
246+
case None =>
247+
'(dynamic_++(~self, ~that))
248+
}
243249
}
244-
res.as[Concat[Self, That]]
245-
}
250+
res.as[Concat]
246251
}
247252

248253
private implicit class ExprOps[U: Type](expr: Expr[U]) {

library/src-scala3/scala/Tuple.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ sealed trait Tuple extends Any {
1010
~toArrayStaged('(this), constValueOpt[BoundedSize[this.type]])
1111

1212
inline def *: [H] (x: H): H *: this.type =
13-
~stagedCons('(this), '(x), constValueOpt[BoundedSize[this.type]])
13+
~stagedCons[H *: this.type, H]('(this), '(x), constValueOpt[BoundedSize[this.type]])
1414

1515
inline def ++(that: Tuple): Concat[this.type, that.type] =
16-
~stagedConcat('(this), constValueOpt[BoundedSize[this.type]], '(that), constValueOpt[BoundedSize[that.type]])
16+
~stagedConcat[Concat[this.type, that.type]]('(this), constValueOpt[BoundedSize[this.type]], '(that), constValueOpt[BoundedSize[that.type]])
1717

1818
inline def size: Size[this.type] =
1919
~sizeStaged[Size[this.type]]('(this), constValueOpt[BoundedSize[this.type]])
@@ -182,13 +182,13 @@ abstract sealed class NonEmptyTuple extends Tuple {
182182
import StagedTuple._
183183

184184
inline def head: Head[this.type] =
185-
~headStaged[this.type]('(this), constValueOpt[BoundedSize[this.type]])
185+
~headStaged[Head[this.type]]('(this), constValueOpt[BoundedSize[this.type]])
186186

187187
inline def tail: Tail[this.type] =
188-
~tailStaged[this.type]('(this), constValueOpt[BoundedSize[this.type]])
188+
~tailStaged[Tail[this.type]]('(this), constValueOpt[BoundedSize[this.type]])
189189

190190
inline def apply(n: Int): Elem[this.type, n.type] =
191-
~applyStaged[this.type, n.type]('(this), constValueOpt[Size[this.type]], '(n), constValueOpt[n.type])
191+
~applyStaged[Elem[this.type, n.type]]('(this), constValueOpt[Size[this.type]], '(n), constValueOpt[n.type])
192192

193193
}
194194

File renamed without changes.

tests/run/tuples1a.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
object Test extends App {
2+
val t7 = '5' *: 4 *: "C" *: ()
3+
4+
val t7a = t7.tail
5+
val t7b = t7a.tail
6+
val t7c: Unit = (t7.tail: (Int, String)).tail
7+
val t7d: Unit = (t7.tail: Int *: String *: Unit).tail
8+
val t7e: Unit = t7.tail.tail
9+
}

0 commit comments

Comments
 (0)