Skip to content

Commit b04765b

Browse files
committed
Specialize Tuple during Typer
The `stageIt` switch determines whether specialization should take place during Typer or during Staging. We should compile a test suite with both switch settings and compare - intermediate code after staging - intermesiate code after erasure - bytecode sizes - compile-time and runtime speed That would let us decide which of the two schemes is preferable.
1 parent 07beeea commit b04765b

File tree

2 files changed

+72
-44
lines changed

2 files changed

+72
-44
lines changed

library/src-scala3/scala/StagedTuple.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ object StagedTuple {
66
import Tuple._
77
import NonEmptyTuple._
88

9+
private final val specialize = true
10+
911
def toArrayStaged(tup: Expr[Tuple], size: Option[Int]): Expr[Array[Object]] = {
1012
if (!specialize) '(dynamicToArray(~tup))
1113
else size match {

library/src-scala3/scala/Tuple.scala

Lines changed: 70 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package scala
22
import annotation.showAsInfix
33
import typelevel._
4+
import scala.StagedTuple
45

56
sealed trait Tuple extends Any {
67
import Tuple._
78

89
inline def toArray: Array[Object] =
9-
if (specialize)
10-
inline constValueOpt[BoundedSize[this.type]] match {
10+
if (stageIt) stagedToArray
11+
else inline constValueOpt[BoundedSize[this.type]] match {
1112
case Some(0) =>
1213
$emptyArray
1314
case Some(1) =>
@@ -29,10 +30,13 @@ sealed trait Tuple extends Any {
2930
case None =>
3031
dynamicToArray(this)
3132
}
32-
else dynamicToArray(this)
33+
34+
inline def stagedToArray: Array[Object] =
35+
~StagedTuple.toArrayStaged('(this), constValueOpt[BoundedSize[this.type]])
3336

3437
inline def *: [H] (x: H): H *: this.type =
35-
if (specialize) {
38+
if (stageIt) stagedCons[H](x)
39+
else {
3640
type Result = H *: this.type
3741
inline constValueOpt[BoundedSize[this.type]] match {
3842
case Some(0) =>
@@ -54,10 +58,13 @@ sealed trait Tuple extends Any {
5458
dynamic_*:[this.type, H](this, x)
5559
}
5660
}
57-
else dynamic_*:[this.type, H](this, x)
61+
62+
inline def stagedCons[H] (x: H): H *: this.type =
63+
~StagedTuple.stagedCons('(this), '(x), constValueOpt[BoundedSize[this.type]])
5864

5965
inline def ++(that: Tuple): Concat[this.type, that.type] =
60-
if (specialize) {
66+
if (stageIt) stagedConcat(that)
67+
else {
6168
type Result = Concat[this.type, that.type]
6269
inline constValueOpt[BoundedSize[this.type]] match {
6370
case Some(0) =>
@@ -95,27 +102,33 @@ sealed trait Tuple extends Any {
95102
dynamic_++[this.type, that.type](this, that)
96103
}
97104
}
98-
else dynamic_++[this.type, that.type](this, that)
105+
106+
inline def stagedConcat(that: Tuple): Concat[this.type, that.type] =
107+
~StagedTuple.stagedConcat('(this), constValueOpt[BoundedSize[this.type]],
108+
'(that), constValueOpt[BoundedSize[that.type]])
99109

100110
inline def genericConcat[T <: Tuple](xs: Tuple, ys: Tuple): Tuple =
101111
fromArray[T](xs.toArray ++ ys.toArray)
102112

103113
inline def size: Size[this.type] =
104-
if (specialize) {
114+
if (stageIt) stagedSize
115+
else {
105116
type Result = Size[this.type]
106117
inline constValueOpt[BoundedSize[this.type]] match {
107118
case Some(n) => n.asInstanceOf[Result]
108119
case _ => dynamicSize(this)
109120
}
110121
}
111-
else dynamicSize(this)
122+
123+
inline def stagedSize: Size[this.type] =
124+
~StagedTuple.sizeStaged[Size[this.type]]('(this), constValueOpt[BoundedSize[this.type]])
112125
}
113126

114127
object Tuple {
115128
inline val $MaxSpecialized = 22
116129
inline private val XXL = $MaxSpecialized + 1
117130

118-
final val specialize = true
131+
final val stageIt = false
119132

120133
type Head[+X <: NonEmptyTuple] = X match {
121134
case x *: _ => x
@@ -175,34 +188,36 @@ object Tuple {
175188
}
176189

177190
inline def fromArray[T <: Tuple](xs: Array[Object]): T =
178-
if (specialize)
179-
inline constValue[BoundedSize[T]] match {
180-
case 0 => ().asInstanceOf[T]
181-
case 1 => Tuple1(xs(0)).asInstanceOf[T]
182-
case 2 => Tuple2(xs(0), xs(1)).asInstanceOf[T]
183-
case 3 => Tuple3(xs(0), xs(1), xs(2)).asInstanceOf[T]
184-
case 4 => Tuple4(xs(0), xs(1), xs(2), xs(3)).asInstanceOf[T]
185-
case 5 => Tuple5(xs(0), xs(1), xs(2), xs(3), xs(4)).asInstanceOf[T]
186-
case 6 => Tuple6(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5)).asInstanceOf[T]
187-
case 7 => Tuple7(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6)).asInstanceOf[T]
188-
case 8 => Tuple8(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7)).asInstanceOf[T]
189-
case 9 => Tuple9(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8)).asInstanceOf[T]
190-
case 10 => Tuple10(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9)).asInstanceOf[T]
191-
case 11 => Tuple11(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10)).asInstanceOf[T]
192-
case 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)).asInstanceOf[T]
193-
case 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)).asInstanceOf[T]
194-
case 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)).asInstanceOf[T]
195-
case 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)).asInstanceOf[T]
196-
case 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)).asInstanceOf[T]
197-
case 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)).asInstanceOf[T]
198-
case 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)).asInstanceOf[T]
199-
case 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)).asInstanceOf[T]
200-
case 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)).asInstanceOf[T]
201-
case 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)).asInstanceOf[T]
202-
case 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)).asInstanceOf[T]
203-
case _ => TupleXXL(xs).asInstanceOf[T]
204-
}
205-
else dynamicFromArray[T](xs)
191+
if (stageIt) stagedFromArray[T](xs)
192+
else inline constValue[BoundedSize[T]] match {
193+
case 0 => ().asInstanceOf[T]
194+
case 1 => Tuple1(xs(0)).asInstanceOf[T]
195+
case 2 => Tuple2(xs(0), xs(1)).asInstanceOf[T]
196+
case 3 => Tuple3(xs(0), xs(1), xs(2)).asInstanceOf[T]
197+
case 4 => Tuple4(xs(0), xs(1), xs(2), xs(3)).asInstanceOf[T]
198+
case 5 => Tuple5(xs(0), xs(1), xs(2), xs(3), xs(4)).asInstanceOf[T]
199+
case 6 => Tuple6(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5)).asInstanceOf[T]
200+
case 7 => Tuple7(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6)).asInstanceOf[T]
201+
case 8 => Tuple8(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7)).asInstanceOf[T]
202+
case 9 => Tuple9(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8)).asInstanceOf[T]
203+
case 10 => Tuple10(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9)).asInstanceOf[T]
204+
case 11 => Tuple11(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10)).asInstanceOf[T]
205+
case 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)).asInstanceOf[T]
206+
case 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)).asInstanceOf[T]
207+
case 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)).asInstanceOf[T]
208+
case 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)).asInstanceOf[T]
209+
case 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)).asInstanceOf[T]
210+
case 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)).asInstanceOf[T]
211+
case 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)).asInstanceOf[T]
212+
case 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)).asInstanceOf[T]
213+
case 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)).asInstanceOf[T]
214+
case 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)).asInstanceOf[T]
215+
case 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)).asInstanceOf[T]
216+
case _ => TupleXXL(xs).asInstanceOf[T]
217+
}
218+
219+
inline def stagedFromArray[T <: Tuple](xs: Array[Object]): T =
220+
~StagedTuple.fromArrayStaged[T]('(xs), constValueOpt[BoundedSize[this.type]])
206221

207222
def dynamicFromArray[T <: Tuple](xs: Array[Object]): T = xs.length match {
208223
case 0 => ().asInstanceOf[T]
@@ -297,7 +312,8 @@ abstract sealed class NonEmptyTuple extends Tuple {
297312
import NonEmptyTuple._
298313

299314
inline def head: Head[this.type] =
300-
if (specialize) {
315+
if (stageIt) stagedHead
316+
else {
301317
type Result = Head[this.type]
302318
val resVal = inline constValueOpt[BoundedSize[this.type]] match {
303319
case Some(1) =>
@@ -322,10 +338,13 @@ abstract sealed class NonEmptyTuple extends Tuple {
322338
}
323339
resVal.asInstanceOf[Result]
324340
}
325-
else dynamicHead[this.type](this)
341+
342+
inline def stagedHead: Head[this.type] =
343+
~StagedTuple.headStaged[this.type]('(this), constValueOpt[BoundedSize[this.type]])
326344

327345
inline def tail: Tail[this.type] =
328-
if (specialize) {
346+
if (stageIt) stagedTail
347+
else {
329348
type Result = Tail[this.type]
330349
inline constValueOpt[BoundedSize[this.type]] match {
331350
case Some(1) =>
@@ -348,7 +367,9 @@ abstract sealed class NonEmptyTuple extends Tuple {
348367
dynamicTail[this.type](this)
349368
}
350369
}
351-
else dynamicTail[this.type](this)
370+
371+
inline def stagedTail: Tail[this.type] =
372+
~StagedTuple.tailStaged[this.type]('(this), constValueOpt[BoundedSize[this.type]])
352373

353374
inline def fallbackApply(n: Int) =
354375
inline constValueOpt[n.type] match {
@@ -357,7 +378,8 @@ abstract sealed class NonEmptyTuple extends Tuple {
357378
}
358379

359380
inline def apply(n: Int): Elem[this.type, n.type] =
360-
if (specialize) {
381+
if (stageIt) stagedApply(n)
382+
else {
361383
type Result = Elem[this.type, n.type]
362384
inline constValueOpt[Size[this.type]] match {
363385
case Some(1) =>
@@ -405,7 +427,11 @@ abstract sealed class NonEmptyTuple extends Tuple {
405427
case _ => fallbackApply(n).asInstanceOf[Result]
406428
}
407429
}
408-
else dynamicApply[this.type](this, n)
430+
431+
inline def stagedApply(n: Int): Elem[this.type, n.type] =
432+
~StagedTuple.applyStaged[this.type, n.type](
433+
'(this), constValueOpt[Size[this.type]],
434+
'(n), constValueOpt[n.type])
409435
}
410436

411437
object NonEmptyTuple {

0 commit comments

Comments
 (0)