From 429b634f9053e5f816fec04390c3ae4e14163b9f Mon Sep 17 00:00:00 2001 From: danicheg Date: Mon, 11 Oct 2021 22:51:47 +0300 Subject: [PATCH 1/8] Add last method to NonEmptyTuple --- library/src/scala/Tuple.scala | 10 ++++++++++ library/src/scala/runtime/Tuples.scala | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/library/src/scala/Tuple.scala b/library/src/scala/Tuple.scala index c5c2115811cb..730a00e7cc84 100644 --- a/library/src/scala/Tuple.scala +++ b/library/src/scala/Tuple.scala @@ -87,6 +87,12 @@ object Tuple { case _ *: xs => xs } + /** Type of the last of a tuple */ + type Last[X <: NonEmptyTuple] = X match { + case x *: EmptyTuple => x + case _ *: xs => Last[xs] + } + /** Type of the concatenation of two tuples */ type Concat[X <: Tuple, +Y <: Tuple] <: Tuple = X match { case EmptyTuple => Y @@ -269,6 +275,10 @@ sealed trait NonEmptyTuple extends Tuple { inline def head[This >: this.type <: NonEmptyTuple]: Head[This] = runtime.Tuples.apply(this, 0).asInstanceOf[Head[This]] + /** Get the last of this tuple */ + inline def last[This >: this.type <: NonEmptyTuple]: Last[This] = + runtime.Tuples.last(this).asInstanceOf[Last[This]] + /** Get the tail of this tuple. * This operation is O(this.size) */ diff --git a/library/src/scala/runtime/Tuples.scala b/library/src/scala/runtime/Tuples.scala index 267e04f65aed..19334c62da72 100644 --- a/library/src/scala/runtime/Tuples.scala +++ b/library/src/scala/runtime/Tuples.scala @@ -355,6 +355,10 @@ object Tuples { case _ => specialCaseTail(self) } + def last(self: NonEmptyTuple): Any = (self: Any) match { + case self: Product => self.productElement(self.productArity) + } + def apply(self: NonEmptyTuple, n: Int): Any = self.productElement(n) From 75359c05d856da9e3f1d1bab65d78932ff273970 Mon Sep 17 00:00:00 2001 From: danicheg Date: Tue, 12 Oct 2021 00:10:51 +0300 Subject: [PATCH 2/8] Add init method to NonEmptyTuple --- library/src/scala/Tuple.scala | 11 ++++ library/src/scala/runtime/Tuples.scala | 74 +++++++++++++++++++++++++- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/library/src/scala/Tuple.scala b/library/src/scala/Tuple.scala index 730a00e7cc84..279a1342be52 100644 --- a/library/src/scala/Tuple.scala +++ b/library/src/scala/Tuple.scala @@ -82,6 +82,13 @@ object Tuple { case x *: _ => x } + /** Type of the initial part of the tuple without its last element */ + type Init[X <: NonEmptyTuple] <: Tuple = X match { + case x *: EmptyTuple => x *: EmptyTuple + case (x *: _) *: EmptyTuple => x *: EmptyTuple + case x *: xs => x *: Init[xs] + } + /** Type of the tail of a tuple */ type Tail[X <: NonEmptyTuple] <: Tuple = X match { case _ *: xs => xs @@ -275,6 +282,10 @@ sealed trait NonEmptyTuple extends Tuple { inline def head[This >: this.type <: NonEmptyTuple]: Head[This] = runtime.Tuples.apply(this, 0).asInstanceOf[Head[This]] + /** Get the initial part of the tuple without its last element */ + inline def init[This >: this.type <: NonEmptyTuple]: Init[This] = + runtime.Tuples.init(this).asInstanceOf[Init[This]] + /** Get the last of this tuple */ inline def last[This >: this.type <: NonEmptyTuple]: Last[This] = runtime.Tuples.last(this).asInstanceOf[Last[This]] diff --git a/library/src/scala/runtime/Tuples.scala b/library/src/scala/runtime/Tuples.scala index 19334c62da72..e806c8683d6e 100644 --- a/library/src/scala/runtime/Tuples.scala +++ b/library/src/scala/runtime/Tuples.scala @@ -355,8 +355,80 @@ object Tuples { case _ => specialCaseTail(self) } + // Init for TupleXXL + private def xxlInit(xxl: TupleXXL): Tuple = { + if (xxl.productArity == 23) { + val elems = xxl.elems + Tuple22( + elems(0), elems(1), elems(2), elems(3), elems(4), elems(5), + elems(6), elems(7), elems(8), elems(9), elems(10), elems(11), + elems(12), elems(13), elems(14), elems(15), elems(16), elems(17), + elems(18), elems(19), elems(20), elems(21) + ) + } else { + val arr = new Array[Object](xxl.elems.length - 1) + System.arraycopy(xxl.elems, 0, arr, 0, xxl.elems.length - 1) + TupleXXL.fromIArray(arr.asInstanceOf[IArray[Object]]).asInstanceOf[Tuple] + } + } + + // Init for Tuple1 to Tuple22 + private def specialCaseInit(self: Tuple): Tuple = { + (self: Any) match { + case self: Tuple1[_] => + self + case self: Tuple2[_, _] => + Tuple1(self._1) + case self: Tuple3[_, _, _] => + Tuple2(self._1, self._2) + case self: Tuple4[_, _, _, _] => + Tuple3(self._1, self._2, self._3) + case self: Tuple5[_, _, _, _, _] => + Tuple4(self._1,self._2, self._3, self._4) + case self: Tuple6[_, _, _, _, _, _] => + Tuple5(self._1, self._2, self._3, self._4, self._5) + case self: Tuple7[_, _, _, _, _, _, _] => + Tuple6(self._1, self._2, self._3, self._4, self._5, self._6) + case self: Tuple8[_, _, _, _, _, _, _, _] => + Tuple7(self._1, self._2, self._3, self._4, self._5, self._6, self._7) + case self: Tuple9[_, _, _, _, _, _, _, _, _] => + Tuple8(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8) + case self: Tuple10[_, _, _, _, _, _, _, _, _, _] => + Tuple9(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9) + case self: Tuple11[_, _, _, _, _, _, _, _, _, _, _] => + Tuple10(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10) + case self: Tuple12[_, _, _, _, _, _, _, _, _, _, _, _] => + Tuple11(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11) + case self: Tuple13[_, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple12(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12) + case self: Tuple14[_, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple13(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13) + case self: Tuple15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple14(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14) + case self: Tuple16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple15(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15) + case self: Tuple17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple16(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16) + case self: Tuple18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple17(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, self._17) + case self: Tuple19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple18(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, self._17, self._18) + case self: Tuple20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple19(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, self._17, self._18, self._19) + case self: Tuple21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple20(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, self._17, self._18, self._19, self._20) + case self: Tuple22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple21(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, self._17, self._18, self._19, self._20, self._21) + } + } + + def init(self: NonEmptyTuple): Tuple = (self: Any) match { + case xxl: TupleXXL => xxlInit(xxl) + case _ => specialCaseInit(self) + } + def last(self: NonEmptyTuple): Any = (self: Any) match { - case self: Product => self.productElement(self.productArity) + case self: Product => self.productElement(self.productArity - 1) } def apply(self: NonEmptyTuple, n: Int): Any = From 545251c2f937a27519aea5719a6f1a45d1bd1976 Mon Sep 17 00:00:00 2001 From: danicheg Date: Tue, 12 Oct 2021 19:12:29 +0300 Subject: [PATCH 3/8] Add regression tests for NonEmptyTuple.last --- library/src/scala/Tuple.scala | 28 ++++++++--- tests/run-deep-subtype/Tuple-last.check | 26 ++++++++++ tests/run-deep-subtype/Tuple-last.scala | 65 +++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 tests/run-deep-subtype/Tuple-last.check create mode 100644 tests/run-deep-subtype/Tuple-last.scala diff --git a/library/src/scala/Tuple.scala b/library/src/scala/Tuple.scala index 279a1342be52..49b776bc1e50 100644 --- a/library/src/scala/Tuple.scala +++ b/library/src/scala/Tuple.scala @@ -84,9 +84,14 @@ object Tuple { /** Type of the initial part of the tuple without its last element */ type Init[X <: NonEmptyTuple] <: Tuple = X match { - case x *: EmptyTuple => x *: EmptyTuple - case (x *: _) *: EmptyTuple => x *: EmptyTuple - case x *: xs => x *: Init[xs] + case _ *: EmptyTuple => X + case x *: xs => + xs match { + case _ *: EmptyTuple => + x *: EmptyTuple + case _ => + x *: Init[xs] + } } /** Type of the tail of a tuple */ @@ -95,9 +100,20 @@ object Tuple { } /** Type of the last of a tuple */ - type Last[X <: NonEmptyTuple] = X match { - case x *: EmptyTuple => x - case _ *: xs => Last[xs] + type Last[X <: NonEmptyTuple] = Reduce[X, EmptyTuple] match { + case x *: xs => xs match { + case EmptyTuple => x + } + } + + /** Type of the reduce of the first tuple to a tuple of arity 1 or provide the second tuple as a result */ + type Reduce[X <: Tuple, Y <: Tuple] <: Tuple = X match { + case EmptyTuple => Y + case x *: xs => xs match { + case EmptyTuple => x *: EmptyTuple + case y *: ys => + Reduce[ys, y *: EmptyTuple] + } } /** Type of the concatenation of two tuples */ diff --git a/tests/run-deep-subtype/Tuple-last.check b/tests/run-deep-subtype/Tuple-last.check new file mode 100644 index 000000000000..cc750f5e721c --- /dev/null +++ b/tests/run-deep-subtype/Tuple-last.check @@ -0,0 +1,26 @@ +0 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 \ No newline at end of file diff --git a/tests/run-deep-subtype/Tuple-last.scala b/tests/run-deep-subtype/Tuple-last.scala new file mode 100644 index 000000000000..d4bad1719b64 --- /dev/null +++ b/tests/run-deep-subtype/Tuple-last.scala @@ -0,0 +1,65 @@ +import scala.reflect.ClassTag + +object Test { + def main(args: Array[String]): Unit = { + def printArray[T: ClassTag](n: Int, elem: Int => T): Unit = { + val t: Int *: Tuple = 0 *: Tuple.fromArray(Array.tabulate(n)(elem)) + println(t.last) + } + + for (i <- 0 to 25) + printArray(i, j => j) + + assert(1 == Tuple1(1).last) + assert(2 == (1, 2).last) + assert(3 == (1, 2, 3).last) + assert(4 == (1, 2, 3, 4).last) + assert(5 == (1, 2, 3, 4, 5).last) + assert(6 == (1, 2, 3, 4, 5, 6).last) + assert(7 == (1, 2, 3, 4, 5, 6, 7).last) + assert(8 == (1, 2, 3, 4, 5, 6, 7, 8).last) + assert(9 == (1, 2, 3, 4, 5, 6, 7, 8, 9).last) + assert(10 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10).last) + assert(11 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11).last) + assert(12 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12).last) + assert(13 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13).last) + assert(14 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14).last) + assert(15 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15).last) + assert(16 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16).last) + assert(17 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17).last) + assert(18 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18).last) + assert(19 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19).last) + assert(20 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20).last) + assert(21 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21).last) + assert(22 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22).last) + assert(23 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23).last) + assert(24 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24).last) + assert(25 == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25).last) + + assert(1 == (1 *: Tuple()).last) + assert(2 == (1 *: 2 *: Tuple()).last) + assert(3 == (1 *: 2 *: 3 *: Tuple()).last) + assert(4 == (1 *: 2 *: 3 *: 4 *: Tuple()).last) + assert(5 == (1 *: 2 *: 3 *: 4 *: 5 *: Tuple()).last) + assert(6 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: Tuple()).last) + assert(7 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: Tuple()).last) + assert(8 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: Tuple()).last) + assert(9 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: Tuple()).last) + assert(10 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: Tuple()).last) + assert(11 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: Tuple()).last) + assert(12 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: Tuple()).last) + assert(13 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: Tuple()).last) + assert(14 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: Tuple()).last) + assert(15 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: Tuple()).last) + assert(16 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: Tuple()).last) + assert(17 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: Tuple()).last) + assert(18 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: Tuple()).last) + assert(19 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: Tuple()).last) + assert(20 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: Tuple()).last) + assert(21 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: Tuple()).last) + assert(22 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: Tuple()).last) + assert(23 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: 23 *: Tuple()).last) + assert(24 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: 23 *: 24 *: Tuple()).last) + assert(25 == (1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: 23 *: 24 *: 25 *: Tuple()).last) + } +} From 9f8ca946b52dbc2fa09893e2d86998f6c49423c4 Mon Sep 17 00:00:00 2001 From: danicheg Date: Tue, 12 Oct 2021 19:18:41 +0300 Subject: [PATCH 4/8] Add regression tests for NonEmptyTuple.init --- tests/run-deep-subtype/Tuple-init.check | 76 +++++++++++++++++++++++++ tests/run-deep-subtype/Tuple-init.scala | 65 +++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 tests/run-deep-subtype/Tuple-init.check create mode 100644 tests/run-deep-subtype/Tuple-init.scala diff --git a/tests/run-deep-subtype/Tuple-init.check b/tests/run-deep-subtype/Tuple-init.check new file mode 100644 index 000000000000..47e4d16f5263 --- /dev/null +++ b/tests/run-deep-subtype/Tuple-init.check @@ -0,0 +1,76 @@ +(0) +(0) +(0,0) +(0,0,1) +(0,0,1,2) +(0,0,1,2,3) +(0,0,1,2,3,4) +(0,0,1,2,3,4,5) +(0,0,1,2,3,4,5,6) +(0,0,1,2,3,4,5,6,7) +(0,0,1,2,3,4,5,6,7,8) +(0,0,1,2,3,4,5,6,7,8,9) +(0,0,1,2,3,4,5,6,7,8,9,10) +(0,0,1,2,3,4,5,6,7,8,9,10,11) +(0,0,1,2,3,4,5,6,7,8,9,10,11,12) +(0,0,1,2,3,4,5,6,7,8,9,10,11,12,13) +(0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14) +(0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) +(0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) +(0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17) +(0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18) +(0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19) +(0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20) +(0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21) +(0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) +(0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23) +(1) +(1) +(1,2) +(1,2,3) +(1,2,3,4) +(1,2,3,4,5) +(1,2,3,4,5,6) +(1,2,3,4,5,6,7) +(1,2,3,4,5,6,7,8) +(1,2,3,4,5,6,7,8,9) +(1,2,3,4,5,6,7,8,9,10) +(1,2,3,4,5,6,7,8,9,10,11) +(1,2,3,4,5,6,7,8,9,10,11,12) +(1,2,3,4,5,6,7,8,9,10,11,12,13) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24) +(1) +(1) +(1,2) +(1,2,3) +(1,2,3,4) +(1,2,3,4,5) +(1,2,3,4,5,6) +(1,2,3,4,5,6,7) +(1,2,3,4,5,6,7,8) +(1,2,3,4,5,6,7,8,9) +(1,2,3,4,5,6,7,8,9,10) +(1,2,3,4,5,6,7,8,9,10,11) +(1,2,3,4,5,6,7,8,9,10,11,12) +(1,2,3,4,5,6,7,8,9,10,11,12,13) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23) +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24) diff --git a/tests/run-deep-subtype/Tuple-init.scala b/tests/run-deep-subtype/Tuple-init.scala new file mode 100644 index 000000000000..286c84a17cf7 --- /dev/null +++ b/tests/run-deep-subtype/Tuple-init.scala @@ -0,0 +1,65 @@ +import scala.reflect.ClassTag + +object Test { + def main(args: Array[String]): Unit = { + def testArray[T: ClassTag](n: Int, elem: Int => T): Unit = { + val t: Int *: Tuple = 0 *: Tuple.fromArray(Array.tabulate(n)(elem)) + println(t.init) + } + + for (i <- 0 to 25) + testArray(i, j => j) + + println(Tuple1(1).init) + println((1, 2).init) + println((1, 2, 3).init) + println((1, 2, 3, 4).init) + println((1, 2, 3, 4, 5).init) + println((1, 2, 3, 4, 5, 6).init) + println((1, 2, 3, 4, 5, 6, 7).init) + println((1, 2, 3, 4, 5, 6, 7, 8).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24).init) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25).init) + + println((1 *: Tuple()).init) + println((1 *: 2 *: Tuple()).init) + println((1 *: 2 *: 3 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: 23 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: 23 *: 24 *: Tuple()).init) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: 23 *: 24 *: 25 *: Tuple()).init) + } +} From 235a716fddfa5ccd5a9fd70577d3517199d1b13e Mon Sep 17 00:00:00 2001 From: danicheg Date: Wed, 13 Oct 2021 13:08:49 +0300 Subject: [PATCH 5/8] Fix init for Tuple1 case --- library/src/scala/Tuple.scala | 2 +- library/src/scala/runtime/Tuples.scala | 4 ++-- tests/run-deep-subtype/Tuple-init.check | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/src/scala/Tuple.scala b/library/src/scala/Tuple.scala index 49b776bc1e50..87ea2363f736 100644 --- a/library/src/scala/Tuple.scala +++ b/library/src/scala/Tuple.scala @@ -84,7 +84,7 @@ object Tuple { /** Type of the initial part of the tuple without its last element */ type Init[X <: NonEmptyTuple] <: Tuple = X match { - case _ *: EmptyTuple => X + case _ *: EmptyTuple => EmptyTuple case x *: xs => xs match { case _ *: EmptyTuple => diff --git a/library/src/scala/runtime/Tuples.scala b/library/src/scala/runtime/Tuples.scala index e806c8683d6e..e5018cce47a6 100644 --- a/library/src/scala/runtime/Tuples.scala +++ b/library/src/scala/runtime/Tuples.scala @@ -375,8 +375,8 @@ object Tuples { // Init for Tuple1 to Tuple22 private def specialCaseInit(self: Tuple): Tuple = { (self: Any) match { - case self: Tuple1[_] => - self + case _: Tuple1[_] => + EmptyTuple case self: Tuple2[_, _] => Tuple1(self._1) case self: Tuple3[_, _, _] => diff --git a/tests/run-deep-subtype/Tuple-init.check b/tests/run-deep-subtype/Tuple-init.check index 47e4d16f5263..31c15bbd4e76 100644 --- a/tests/run-deep-subtype/Tuple-init.check +++ b/tests/run-deep-subtype/Tuple-init.check @@ -1,4 +1,4 @@ -(0) +() (0) (0,0) (0,0,1) @@ -24,7 +24,7 @@ (0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21) (0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) (0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23) -(1) +() (1) (1,2) (1,2,3) @@ -49,7 +49,7 @@ (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23) (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24) -(1) +() (1) (1,2) (1,2,3) From 809d7b769a4700d79093b454ced0bf9cb15cb276 Mon Sep 17 00:00:00 2001 From: danicheg Date: Wed, 13 Oct 2021 13:28:13 +0300 Subject: [PATCH 6/8] Mark NonEmptyTuple.{init|last} as experimental --- library/src/scala/Tuple.scala | 5 ++++- project/Build.scala | 13 ++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/library/src/scala/Tuple.scala b/library/src/scala/Tuple.scala index 87ea2363f736..ff3825b00583 100644 --- a/library/src/scala/Tuple.scala +++ b/library/src/scala/Tuple.scala @@ -1,5 +1,6 @@ package scala -import annotation.showAsInfix + +import annotation.{experimental, showAsInfix} import compiletime._ import compiletime.ops.int._ @@ -299,10 +300,12 @@ sealed trait NonEmptyTuple extends Tuple { runtime.Tuples.apply(this, 0).asInstanceOf[Head[This]] /** Get the initial part of the tuple without its last element */ + @experimental inline def init[This >: this.type <: NonEmptyTuple]: Init[This] = runtime.Tuples.init(this).asInstanceOf[Init[This]] /** Get the last of this tuple */ + @experimental inline def last[This >: this.type <: NonEmptyTuple]: Last[This] = runtime.Tuples.last(this).asInstanceOf[Last[This]] diff --git a/project/Build.scala b/project/Build.scala index c21fb71609fa..f4ae7a79c1ae 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -3,6 +3,7 @@ import java.nio.file._ import Modes._ import com.jsuereth.sbtpgp.PgpKeys +import com.typesafe.tools.mima.core.{DirectMissingMethodProblem, ProblemFilters} import sbt.Keys._ import sbt._ import complete.DefaultParsers._ @@ -14,20 +15,15 @@ import sbt.ScriptedPlugin.autoImport._ import xerial.sbt.pack.PackPlugin import xerial.sbt.pack.PackPlugin.autoImport._ import xerial.sbt.Sonatype.autoImport._ - import com.typesafe.tools.mima.plugin.MimaPlugin.autoImport._ - -import dotty.tools.sbtplugin.DottyIDEPlugin.{ installCodeExtension, prepareCommand, runProcess } +import dotty.tools.sbtplugin.DottyIDEPlugin.{installCodeExtension, prepareCommand, runProcess} import dotty.tools.sbtplugin.DottyIDEPlugin.autoImport._ - import org.scalajs.sbtplugin.ScalaJSPlugin import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._ - import sbtbuildinfo.BuildInfoPlugin import sbtbuildinfo.BuildInfoPlugin.autoImport._ import scala.util.Properties.isJavaAtLeast - import org.portablescala.sbtplatformdeps.PlatformDepsPlugin.autoImport._ object DottyJSPlugin extends AutoPlugin { @@ -1781,7 +1777,10 @@ object Build { (Compile/doc/target).value }, commonMiMaSettings, - mimaBinaryIssueFilters ++= MiMaFilters.Library, + mimaBinaryIssueFilters ++= MiMaFilters.Library ++ Seq( + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.init"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.last") + ) ) } else base } From 156a500bcbe2079e54d80b076ff51080ea6258b7 Mon Sep 17 00:00:00 2001 From: danicheg Date: Wed, 13 Oct 2021 18:52:45 +0300 Subject: [PATCH 7/8] Use X <: Tuple bound for Tuple.{Init|Last} --- library/src/scala/Tuple.scala | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/library/src/scala/Tuple.scala b/library/src/scala/Tuple.scala index ff3825b00583..fb08a0afe2b5 100644 --- a/library/src/scala/Tuple.scala +++ b/library/src/scala/Tuple.scala @@ -84,15 +84,11 @@ object Tuple { } /** Type of the initial part of the tuple without its last element */ - type Init[X <: NonEmptyTuple] <: Tuple = X match { + @experimental + type Init[X <: Tuple] <: Tuple = X match { case _ *: EmptyTuple => EmptyTuple case x *: xs => - xs match { - case _ *: EmptyTuple => - x *: EmptyTuple - case _ => - x *: Init[xs] - } + x *: Init[xs] } /** Type of the tail of a tuple */ @@ -100,21 +96,11 @@ object Tuple { case _ *: xs => xs } - /** Type of the last of a tuple */ - type Last[X <: NonEmptyTuple] = Reduce[X, EmptyTuple] match { - case x *: xs => xs match { - case EmptyTuple => x - } - } - - /** Type of the reduce of the first tuple to a tuple of arity 1 or provide the second tuple as a result */ - type Reduce[X <: Tuple, Y <: Tuple] <: Tuple = X match { - case EmptyTuple => Y - case x *: xs => xs match { - case EmptyTuple => x *: EmptyTuple - case y *: ys => - Reduce[ys, y *: EmptyTuple] - } + /** Type of the last element of a tuple */ + @experimental + type Last[X <: Tuple] = X match { + case x *: EmptyTuple => x + case _ *: xs => Last[xs] } /** Type of the concatenation of two tuples */ From 12fccf387546c8527f3a4bdddb9706f6b946ef72 Mon Sep 17 00:00:00 2001 From: danicheg Date: Wed, 13 Oct 2021 18:57:20 +0300 Subject: [PATCH 8/8] Move MiMa settings to MiMaFilters --- project/Build.scala | 6 +----- project/MiMaFilters.scala | 2 ++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index f4ae7a79c1ae..8520a5de6839 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -3,7 +3,6 @@ import java.nio.file._ import Modes._ import com.jsuereth.sbtpgp.PgpKeys -import com.typesafe.tools.mima.core.{DirectMissingMethodProblem, ProblemFilters} import sbt.Keys._ import sbt._ import complete.DefaultParsers._ @@ -1777,10 +1776,7 @@ object Build { (Compile/doc/target).value }, commonMiMaSettings, - mimaBinaryIssueFilters ++= MiMaFilters.Library ++ Seq( - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.init"), - ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.last") - ) + mimaBinaryIssueFilters ++= MiMaFilters.Library ) } else base } diff --git a/project/MiMaFilters.scala b/project/MiMaFilters.scala index c7a71a2dd8dc..0f8dbfa896c0 100644 --- a/project/MiMaFilters.scala +++ b/project/MiMaFilters.scala @@ -4,5 +4,7 @@ import com.typesafe.tools.mima.core.ProblemFilters._ object MiMaFilters { val Library: Seq[ProblemFilter] = Seq( + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.init"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.last") ) }