Skip to content

Commit 456f075

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 456f075

File tree

5 files changed

+136
-119
lines changed

5 files changed

+136
-119
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
# Closure type miss match
22
eff-dependent.scala
3+
4+
# FIXME Macros are not expanded
5+
tuples1.scala
6+
tuples1a.scala

library/src-scala3/scala/StagedTuple.scala

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

248-
private implicit class ExprOps[U: Type](expr: Expr[U]) {
249-
252+
private implicit class ExprOps[U](expr: Expr[U]) {
250253
def as[T: Type]: Expr[T] = '{ (~expr).asInstanceOf[T] }
254+
}
251255

256+
private implicit class ExprTypedOps[U: Type](expr: Expr[U]) {
252257
def bind[T](in: Expr[U] => Expr[T]): Expr[T] = '{
253258
val t: U = (~expr)
254259
~(in('(t)))
255260
}
256-
257261
}
258262

259263
}

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)