From d8dfef6f68559882b18209aa319d3640602bf153 Mon Sep 17 00:00:00 2001 From: danicheg Date: Fri, 15 Oct 2021 16:00:31 +0300 Subject: [PATCH 1/6] Add reverse method to NonEmptyTuple --- library/src/scala/Tuple.scala | 14 ++++ library/src/scala/runtime/Tuples.scala | 73 +++++++++++++++++++++ project/MiMaFilters.scala | 5 +- tests/run-deep-subtype/Tuple-reverse.check | 76 ++++++++++++++++++++++ tests/run-deep-subtype/Tuple-reverse.scala | 66 +++++++++++++++++++ 5 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 tests/run-deep-subtype/Tuple-reverse.check create mode 100644 tests/run-deep-subtype/Tuple-reverse.scala diff --git a/library/src/scala/Tuple.scala b/library/src/scala/Tuple.scala index fb08a0afe2b5..3aac6974021b 100644 --- a/library/src/scala/Tuple.scala +++ b/library/src/scala/Tuple.scala @@ -185,6 +185,14 @@ object Tuple { */ type IsMappedBy[F[_]] = [X <: Tuple] =>> X =:= Map[InverseMap[X, F], F] + /** Type of the reversed tuple */ + @experimental + type Reverse[X <: Tuple] <: Tuple = X match { + case EmptyTuple => EmptyTuple + case x *: xs => + Concat[Reverse[xs], x *: EmptyTuple] + } + /** Transforms a tuple `(T1, ..., Tn)` into `(T1, ..., Ti)`. */ type Take[T <: Tuple, N <: Int] <: Tuple = N match { case 0 => EmptyTuple @@ -301,6 +309,12 @@ sealed trait NonEmptyTuple extends Tuple { inline def tail[This >: this.type <: NonEmptyTuple]: Tail[This] = runtime.Tuples.tail(this).asInstanceOf[Tail[This]] + /** Given a tuple `(a1, ..., am)`, returns the reversed tuple `(am, ..., a1)` + * consisting all its elements. + */ + @experimental + inline def reverse[This >: this.type <: NonEmptyTuple]: Reverse[This] = + runtime.Tuples.reverse(this).asInstanceOf[Reverse[This]] } @showAsInfix diff --git a/library/src/scala/runtime/Tuples.scala b/library/src/scala/runtime/Tuples.scala index e5018cce47a6..fa19c4245964 100644 --- a/library/src/scala/runtime/Tuples.scala +++ b/library/src/scala/runtime/Tuples.scala @@ -1,5 +1,7 @@ package scala.runtime +import scala.annotation.experimental + object Tuples { inline val MaxSpecialized = 22 @@ -372,6 +374,77 @@ object Tuples { } } + // Reverse for TupleXXL + private def xxlReverse(xxl: TupleXXL): Tuple = { + if (xxl.productArity == 22) { + val elems = xxl.elems + Tuple22( + elems(21), elems(20), elems(19), elems(18), elems(17), elems(16), + elems(15), elems(14), elems(13), elems(12), elems(11), elems(10), + elems(9), elems(8), elems(7), elems(6), elems(5), elems(4), + elems(3), elems(2), elems(1), elems(0) + ) + } else { + TupleXXL.fromIArray(xxl.elems.reverse.asInstanceOf[IArray[Object]]).asInstanceOf[Tuple] + } + } + + // Reverse for Tuple1 to Tuple22 + private def specialCaseReverse(self: Tuple): Tuple = { + (self: Any) match { + case self: Tuple1[_] => + self + case self: Tuple2[_, _] => + Tuple2(self._2, self._1) + case self: Tuple3[_, _, _] => + Tuple3(self._3, self._2, self._1) + case self: Tuple4[_, _, _, _] => + Tuple4(self._4, self._3, self._2, self._1) + case self: Tuple5[_, _, _, _, _] => + Tuple5(self._5, self._4, self._3, self._2, self._1) + case self: Tuple6[_, _, _, _, _, _] => + Tuple6(self._6, self._5, self._4, self._3, self._2, self._1) + case self: Tuple7[_, _, _, _, _, _, _] => + Tuple7(self._7, self._6, self._5, self._4, self._3, self._2, self._1) + case self: Tuple8[_, _, _, _, _, _, _, _] => + Tuple8(self._8, self._7, self._6, self._5, self._4, self._3, self._2, self._1) + case self: Tuple9[_, _, _, _, _, _, _, _, _] => + Tuple9(self._9, self._8, self._7, self._6, self._5, self._4, self._3, self._2, self._1) + case self: Tuple10[_, _, _, _, _, _, _, _, _, _] => + Tuple10(self._10, self._9, self._8, self._7, self._6, self._5, self._4, self._3, self._2, self._1) + case self: Tuple11[_, _, _, _, _, _, _, _, _, _, _] => + Tuple11(self._11, self._10, self._9, self._8, self._7, self._6, self._5, self._4, self._3, self._2, self._1) + case self: Tuple12[_, _, _, _, _, _, _, _, _, _, _, _] => + Tuple12(self._12, self._11, self._10, self._9, self._8, self._7, self._6, self._5, self._4, self._3, self._2, self._1) + case self: Tuple13[_, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple13(self._13, self._12, self._11, self._10, self._9, self._8, self._7, self._6, self._5, self._4, self._3, self._2, self._1) + case self: Tuple14[_, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple14(self._14, self._13, self._12, self._11, self._10, self._9, self._8, self._7, self._6, self._5, self._4, self._3, self._2, self._1) + case self: Tuple15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple15(self._15, self._14, self._13, self._12, self._11, self._10, self._9, self._8, self._7, self._6, self._5, self._4, self._3, self._2, self._1) + case self: Tuple16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple16(self._16, self._15, self._14, self._13, self._12, self._11, self._10, self._9, self._8, self._7, self._6, self._5, self._4, self._3, self._2, self._1) + case self: Tuple17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple17(self._17, self._16, self._15, self._14, self._13, self._12, self._11, self._10, self._9, self._8, self._7, self._6, self._5, self._4, self._3, self._2, self._1) + case self: Tuple18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple18(self._18, self._17, self._16, self._15, self._14, self._13, self._12, self._11, self._10, self._9, self._8, self._7, self._6, self._5, self._4, self._3, self._2, self._1) + case self: Tuple19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple19(self._19, self._18, self._17, self._16, self._15, self._14, self._13, self._12, self._11, self._10, self._9, self._8, self._7, self._6, self._5, self._4, self._3, self._2, self._1) + case self: Tuple20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple20(self._20, self._19, self._18, self._17, self._16, self._15, self._14, self._13, self._12, self._11, self._10, self._9, self._8, self._7, self._6, self._5, self._4, self._3, self._2, self._1) + case self: Tuple21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple21(self._21, self._20, self._19, self._18, self._17, self._16, self._15, self._14, self._13, self._12, self._11, self._10, self._9, self._8, self._7, self._6, self._5, self._4, self._3, self._2, self._1) + case self: Tuple22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Tuple22(self._22, self._21, self._20, self._19, self._18, self._17, self._16, self._15, self._14, self._13, self._12, self._11, self._10, self._9, self._8, self._7, self._6, self._5, self._4, self._3, self._2, self._1) + } + } + + @experimental + def reverse(self: NonEmptyTuple): Tuple = (self: Any) match { + case xxl: TupleXXL => xxlReverse(xxl) + case _ => specialCaseReverse(self) + } + // Init for Tuple1 to Tuple22 private def specialCaseInit(self: Tuple): Tuple = { (self: Any) match { diff --git a/project/MiMaFilters.scala b/project/MiMaFilters.scala index 0f8dbfa896c0..7bd827b0cacd 100644 --- a/project/MiMaFilters.scala +++ b/project/MiMaFilters.scala @@ -5,6 +5,9 @@ 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") + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.last"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.append"), + ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#TypeReprMethods.substituteTypes"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.quoted.Quotes#reflectModule#TypeReprMethods.substituteTypes"), ) } diff --git a/tests/run-deep-subtype/Tuple-reverse.check b/tests/run-deep-subtype/Tuple-reverse.check new file mode 100644 index 000000000000..ec64f86e3530 --- /dev/null +++ b/tests/run-deep-subtype/Tuple-reverse.check @@ -0,0 +1,76 @@ +(0) +(0,0) +(1,0,0) +(2,1,0,0) +(3,2,1,0,0) +(4,3,2,1,0,0) +(5,4,3,2,1,0,0) +(6,5,4,3,2,1,0,0) +(7,6,5,4,3,2,1,0,0) +(8,7,6,5,4,3,2,1,0,0) +(9,8,7,6,5,4,3,2,1,0,0) +(10,9,8,7,6,5,4,3,2,1,0,0) +(11,10,9,8,7,6,5,4,3,2,1,0,0) +(12,11,10,9,8,7,6,5,4,3,2,1,0,0) +(13,12,11,10,9,8,7,6,5,4,3,2,1,0,0) +(14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0) +(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0) +(16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0) +(17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0) +(18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0) +(19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0) +(20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0) +(21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0) +(22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0) +(23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0) +(24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0) +(1) +(2,1) +(3,2,1) +(4,3,2,1) +(5,4,3,2,1) +(6,5,4,3,2,1) +(7,6,5,4,3,2,1) +(8,7,6,5,4,3,2,1) +(9,8,7,6,5,4,3,2,1) +(10,9,8,7,6,5,4,3,2,1) +(11,10,9,8,7,6,5,4,3,2,1) +(12,11,10,9,8,7,6,5,4,3,2,1) +(13,12,11,10,9,8,7,6,5,4,3,2,1) +(14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(1) +(2,1) +(3,2,1) +(4,3,2,1) +(5,4,3,2,1) +(6,5,4,3,2,1) +(7,6,5,4,3,2,1) +(8,7,6,5,4,3,2,1) +(9,8,7,6,5,4,3,2,1) +(10,9,8,7,6,5,4,3,2,1) +(11,10,9,8,7,6,5,4,3,2,1) +(12,11,10,9,8,7,6,5,4,3,2,1) +(13,12,11,10,9,8,7,6,5,4,3,2,1) +(14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +(25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) diff --git a/tests/run-deep-subtype/Tuple-reverse.scala b/tests/run-deep-subtype/Tuple-reverse.scala new file mode 100644 index 000000000000..cfcdb7dd627a --- /dev/null +++ b/tests/run-deep-subtype/Tuple-reverse.scala @@ -0,0 +1,66 @@ +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.reverse) + } + + for (i <- 0 to 25) + testArray(i, j => j) + + println(Tuple1(1).reverse) + println((1, 2).reverse) + println((1, 2, 3).reverse) + println((1, 2, 3, 4).reverse) + println((1, 2, 3, 4, 5).reverse) + println((1, 2, 3, 4, 5, 6).reverse) + println((1, 2, 3, 4, 5, 6, 7).reverse) + println((1, 2, 3, 4, 5, 6, 7, 8).reverse) + println((1, 2, 3, 4, 5, 6, 7, 8, 9).reverse) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10).reverse) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11).reverse) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12).reverse) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13).reverse) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14).reverse) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15).reverse) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16).reverse) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17).reverse) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18).reverse) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19).reverse) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20).reverse) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21).reverse) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22).reverse) + println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23).reverse) + 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).reverse) + 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).reverse) + + println((1 *: Tuple()).reverse) + println((1 *: 2 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: Tuple()).reverse) + println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: Tuple()).reverse) + 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()).reverse) + 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()).reverse) + 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()).reverse) + } +} From ab1a19fa90353e65b8e5ffd0f4115065484c4434 Mon Sep 17 00:00:00 2001 From: danicheg Date: Fri, 22 Oct 2021 20:48:27 +0300 Subject: [PATCH 2/6] Update MiMa filters --- project/MiMaFilters.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/project/MiMaFilters.scala b/project/MiMaFilters.scala index 4ef5e4d69c57..ecaee7fef71e 100644 --- a/project/MiMaFilters.scala +++ b/project/MiMaFilters.scala @@ -9,5 +9,6 @@ object MiMaFilters { ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.append"), ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#TypeReprMethods.substituteTypes"), ProblemFilters.exclude[DirectMissingMethodProblem]("scala.quoted.Quotes#reflectModule#TypeReprMethods.substituteTypes"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.reverse"), ) } From a1d8b663b12c04eac4b6844950f42e682a17af80 Mon Sep 17 00:00:00 2001 From: danicheg Date: Sun, 14 May 2023 17:16:44 +0400 Subject: [PATCH 3/6] Address review comments --- library/src/scala/Tuple.scala | 19 ++++++++++++------- library/src/scala/runtime/Tuples.scala | 8 ++++++-- project/MiMaFilters.scala | 1 + .../stdlibExperimentalDefinitions.scala | 10 +++++++++- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/library/src/scala/Tuple.scala b/library/src/scala/Tuple.scala index 8f83a4acd40f..3fb347d078e6 100644 --- a/library/src/scala/Tuple.scala +++ b/library/src/scala/Tuple.scala @@ -1,6 +1,6 @@ package scala -import annotation.showAsInfix +import annotation.{experimental, showAsInfix} import compiletime._ import compiletime.ops.int._ @@ -195,11 +195,16 @@ object Tuple { /** Type of the reversed tuple */ @experimental - type Reverse[X <: Tuple] <: Tuple = X match { - case EmptyTuple => EmptyTuple - case x *: xs => - Concat[Reverse[xs], x *: EmptyTuple] - } + type Reverse[X <: Tuple] = Helpers.ReverseImpl[EmptyTuple, X] + + @experimental + object Helpers: + + /** Type of the reversed tuple */ + @experimental + type ReverseImpl[Acc <: Tuple, X <: Tuple] <: Tuple = X match + case x *: xs => ReverseImpl[x *: Acc, xs] + case EmptyTuple => Acc /** Transforms a tuple `(T1, ..., Tn)` into `(T1, ..., Ti)`. */ type Take[T <: Tuple, N <: Int] <: Tuple = N match { @@ -310,7 +315,7 @@ sealed trait NonEmptyTuple extends Tuple { * consisting all its elements. */ @experimental - inline def reverse[This >: this.type <: NonEmptyTuple]: Reverse[This] = + inline def reverse[This >: this.type <: Tuple]: Reverse[This] = runtime.Tuples.reverse(this).asInstanceOf[Reverse[This]] } diff --git a/library/src/scala/runtime/Tuples.scala b/library/src/scala/runtime/Tuples.scala index 3f939603861c..6420c884570a 100644 --- a/library/src/scala/runtime/Tuples.scala +++ b/library/src/scala/runtime/Tuples.scala @@ -1,5 +1,7 @@ package scala.runtime +import scala.annotation.experimental + object Tuples { inline val MaxSpecialized = 22 @@ -462,9 +464,11 @@ object Tuples { } } - // Reverse for Tuple1 to Tuple22 + // Reverse for Tuple0 to Tuple22 private def specialCaseReverse(self: Tuple): Tuple = { (self: Any) match { + case EmptyTuple => + EmptyTuple case self: Tuple1[_] => self case self: Tuple2[_, _] => @@ -513,7 +517,7 @@ object Tuples { } @experimental - def reverse(self: NonEmptyTuple): Tuple = (self: Any) match { + def reverse(self: Tuple): Tuple = (self: Any) match { case xxl: TupleXXL => xxlReverse(xxl) case _ => specialCaseReverse(self) } diff --git a/project/MiMaFilters.scala b/project/MiMaFilters.scala index 2027c779e5ba..e8328a5e1a20 100644 --- a/project/MiMaFilters.scala +++ b/project/MiMaFilters.scala @@ -32,6 +32,7 @@ object MiMaFilters { ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.stdLibPatches.language#experimental.relaxedExtensionImports"), ProblemFilters.exclude[MissingClassProblem]("scala.runtime.stdLibPatches.language$experimental$relaxedExtensionImports$"), ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.reverse"), + ProblemFilters.exclude[MissingFieldProblem]("scala.Tuple.Helpers"), // end of New experimental features in 3.3.X // Added java.io.Serializable as LazyValControlState supertype diff --git a/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala b/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala index 644efb54c32e..b55c63b0e9bd 100644 --- a/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala +++ b/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala @@ -92,7 +92,15 @@ val experimentalDefinitionInLibrary = Set( "scala.quoted.Quotes.reflectModule.MethodTypeMethods.hasErasedParams", "scala.quoted.Quotes.reflectModule.TermParamClauseMethods.erasedArgs", "scala.quoted.Quotes.reflectModule.TermParamClauseMethods.hasErasedArgs", - "scala.quoted.Quotes.reflectModule.defnModule.ErasedFunctionClass" + "scala.quoted.Quotes.reflectModule.defnModule.ErasedFunctionClass", + + // New feature: reverse method on Tuple + "scala.NonEmptyTuple.reverse", + "scala.Tuple$.Helpers", + "scala.Tuple$.Helpers$", + "scala.Tuple$.Helpers$.ReverseImpl", + "scala.Tuple$.Reverse", + "scala.runtime.Tuples$.reverse" ) From 5006b2f9e4ca818d32ce0b988e3787f8d27558b1 Mon Sep 17 00:00:00 2001 From: danicheg Date: Wed, 17 May 2023 13:29:59 +0400 Subject: [PATCH 4/6] Remove wrong branch in Tuples#xxlReverse --- library/src/scala/runtime/Tuples.scala | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/library/src/scala/runtime/Tuples.scala b/library/src/scala/runtime/Tuples.scala index 6420c884570a..87682ed86ce5 100644 --- a/library/src/scala/runtime/Tuples.scala +++ b/library/src/scala/runtime/Tuples.scala @@ -450,19 +450,8 @@ object Tuples { } // Reverse for TupleXXL - private def xxlReverse(xxl: TupleXXL): Tuple = { - if (xxl.productArity == 22) { - val elems = xxl.elems - Tuple22( - elems(21), elems(20), elems(19), elems(18), elems(17), elems(16), - elems(15), elems(14), elems(13), elems(12), elems(11), elems(10), - elems(9), elems(8), elems(7), elems(6), elems(5), elems(4), - elems(3), elems(2), elems(1), elems(0) - ) - } else { - TupleXXL.fromIArray(xxl.elems.reverse.asInstanceOf[IArray[Object]]).asInstanceOf[Tuple] - } - } + private def xxlReverse(xxl: TupleXXL): Tuple = + TupleXXL.fromIArray(xxl.elems.reverse.asInstanceOf[IArray[Object]]).asInstanceOf[Tuple] // Reverse for Tuple0 to Tuple22 private def specialCaseReverse(self: Tuple): Tuple = { From 6aef25a7425c7317029fa89a88c1525fa4b6205e Mon Sep 17 00:00:00 2001 From: danicheg Date: Sun, 2 Jul 2023 16:02:47 +0400 Subject: [PATCH 5/6] Move reverse method to Tuple --- library/src/scala/Tuple.scala | 14 +++++++------- .../stdlibExperimentalDefinitions.scala | 2 +- tests/run-deep-subtype/Tuple-reverse.check | 2 ++ tests/run-deep-subtype/Tuple-reverse.scala | 2 ++ 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/library/src/scala/Tuple.scala b/library/src/scala/Tuple.scala index 3fb347d078e6..2d9aaea2be08 100644 --- a/library/src/scala/Tuple.scala +++ b/library/src/scala/Tuple.scala @@ -78,6 +78,13 @@ sealed trait Tuple extends Product { */ inline def splitAt[This >: this.type <: Tuple](n: Int): Split[This, n.type] = runtime.Tuples.splitAt(this, n).asInstanceOf[Split[This, n.type]] + + /** Given a tuple `(a1, ..., am)`, returns the reversed tuple `(am, ..., a1)` + * consisting all its elements. + */ + @experimental + inline def reverse[This >: this.type <: Tuple]: Reverse[This] = + runtime.Tuples.reverse(this).asInstanceOf[Reverse[This]] } object Tuple { @@ -310,13 +317,6 @@ sealed trait NonEmptyTuple extends Tuple { */ inline def tail[This >: this.type <: NonEmptyTuple]: Tail[This] = runtime.Tuples.tail(this).asInstanceOf[Tail[This]] - - /** Given a tuple `(a1, ..., am)`, returns the reversed tuple `(am, ..., a1)` - * consisting all its elements. - */ - @experimental - inline def reverse[This >: this.type <: Tuple]: Reverse[This] = - runtime.Tuples.reverse(this).asInstanceOf[Reverse[This]] } @showAsInfix diff --git a/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala b/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala index 69becd2cf7cb..e2499ef48883 100644 --- a/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala +++ b/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala @@ -102,7 +102,7 @@ val experimentalDefinitionInLibrary = Set( "scala.quoted.Quotes.reflectModule.defnModule.ErasedFunctionClass", // New feature: reverse method on Tuple - "scala.NonEmptyTuple.reverse", + "scala.Tuple.reverse", "scala.Tuple$.Helpers", "scala.Tuple$.Helpers$", "scala.Tuple$.Helpers$.ReverseImpl", diff --git a/tests/run-deep-subtype/Tuple-reverse.check b/tests/run-deep-subtype/Tuple-reverse.check index ec64f86e3530..e889132e88a5 100644 --- a/tests/run-deep-subtype/Tuple-reverse.check +++ b/tests/run-deep-subtype/Tuple-reverse.check @@ -24,6 +24,7 @@ (22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0) (23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0) (24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0) +() (1) (2,1) (3,2,1) @@ -49,6 +50,7 @@ (23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) (24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) (25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +() (1) (2,1) (3,2,1) diff --git a/tests/run-deep-subtype/Tuple-reverse.scala b/tests/run-deep-subtype/Tuple-reverse.scala index cfcdb7dd627a..9c08c5cf2706 100644 --- a/tests/run-deep-subtype/Tuple-reverse.scala +++ b/tests/run-deep-subtype/Tuple-reverse.scala @@ -11,6 +11,7 @@ object Test { for (i <- 0 to 25) testArray(i, j => j) + println(EmptyTuple.reverse) println(Tuple1(1).reverse) println((1, 2).reverse) println((1, 2, 3).reverse) @@ -37,6 +38,7 @@ object Test { 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).reverse) 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).reverse) + println(Tuple().reverse) println((1 *: Tuple()).reverse) println((1 *: 2 *: Tuple()).reverse) println((1 *: 2 *: 3 *: Tuple()).reverse) From ae14dab639e0fe155d0da25a97e84994cc3d5111 Mon Sep 17 00:00:00 2001 From: danicheg Date: Sun, 2 Jul 2023 18:23:28 +0400 Subject: [PATCH 6/6] Add one more test --- tests/run-deep-subtype/Tuple-reverse.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/run-deep-subtype/Tuple-reverse.scala b/tests/run-deep-subtype/Tuple-reverse.scala index 9c08c5cf2706..b0461d167fab 100644 --- a/tests/run-deep-subtype/Tuple-reverse.scala +++ b/tests/run-deep-subtype/Tuple-reverse.scala @@ -11,6 +11,11 @@ object Test { for (i <- 0 to 25) testArray(i, j => j) + val tuple: Tuple3[Int, Boolean, String] = (1, true, "hello") + val reversedTuple: Tuple3[String, Boolean, Int] = tuple.reverse + + assert(reversedTuple == ("hello", true, 1)) + println(EmptyTuple.reverse) println(Tuple1(1).reverse) println((1, 2).reverse)