Skip to content

Redefine Tuple operations #19185

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/test/dotc/pos-test-pickling.blacklist
Original file line number Diff line number Diff line change
@@ -63,6 +63,7 @@ i17149.scala
tuple-fold.scala
mt-redux-norm.perspective.scala
i18211.scala
i15743.scala

# Opaque type
i5720.scala
442 changes: 442 additions & 0 deletions library/src-bootstrapped/scala/Tuple.scala

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// non-bootstrapped version of Tuple.scala

package scala

import annotation.{experimental, showAsInfix}
12 changes: 8 additions & 4 deletions library/src/scala/runtime/Tuples.scala
Original file line number Diff line number Diff line change
@@ -288,6 +288,8 @@ object Tuples {
// Tail for Tuple1 to Tuple22
private def specialCaseTail(self: Tuple): Tuple = {
(self: Any) match {
case self: EmptyTuple =>
throw new NoSuchElementException("tail of empty tuple")
case self: Tuple1[?] =>
EmptyTuple
case self: Tuple2[?, ?] =>
@@ -352,7 +354,7 @@ object Tuples {
}
}

def tail(self: NonEmptyTuple): Tuple = (self: Any) match {
def tail(self: Tuple): Tuple = (self: Any) match {
case xxl: TupleXXL => xxlTail(xxl)
case _ => specialCaseTail(self)
}
@@ -514,6 +516,8 @@ object Tuples {
// Init for Tuple1 to Tuple22
private def specialCaseInit(self: Tuple): Tuple = {
(self: Any) match {
case self: EmptyTuple =>
throw new NoSuchElementException("init of empty tuple")
case _: Tuple1[?] =>
EmptyTuple
case self: Tuple2[?, ?] =>
@@ -561,16 +565,16 @@ object Tuples {
}
}

def init(self: NonEmptyTuple): Tuple = (self: Any) match {
def init(self: Tuple): Tuple = (self: Any) match {
case xxl: TupleXXL => xxlInit(xxl)
case _ => specialCaseInit(self)
}

def last(self: NonEmptyTuple): Any = (self: Any) match {
def last(self: Tuple): Any = (self: Any) match {
case self: Product => self.productElement(self.productArity - 1)
}

def apply(self: NonEmptyTuple, n: Int): Any =
def apply(self: Tuple, n: Int): Any =
self.productElement(n)

// Benchmarks showed that this is faster than doing (it1 zip it2).copyToArray(...)
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ package transformers

class InheritanceInformationTransformer(using DocContext) extends (Module => Module):
override def apply(original: Module): Module =
val subtypes = getSupertypes(original.rootPackage).groupMap(_(0))(_(1)).view.mapValues(_.distinct).toMap
val subtypes = getSupertypes(original.rootPackage).groupMap(_._1)(_._2).view.mapValues(_.distinct).toMap
original.updateMembers { m =>
val edges = getEdges(m.asLink.copy(kind = bareClasslikeKind(m.kind)), subtypes)
val st: Seq[LinkToType] = edges.map(_._1).distinct
4 changes: 2 additions & 2 deletions tests/neg/i13780-1.check
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-- [E007] Type Mismatch Error: tests/neg/i13780-1.scala:38:24 ----------------------------------------------------------
-- [E007] Type Mismatch Error: tests/neg/i13780-1.scala:38:26 ----------------------------------------------------------
38 | case x: (h *: t) => x.head // error
| ^^^^^^
| Found: Tuple.Head[VS & h *: t]
| Found: Tuple.Head[VS & h *: t] & Tuple.Head[(x : VS & h *: t)]
| Required: h
|
| where: VS is a type in method foo with bounds <: Tuple
4 changes: 4 additions & 0 deletions tests/pos/Tuple_apply.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
def testTuple(tup: Tuple) = tup(0)
def testNonEmptyTuple(tup: NonEmptyTuple) = tup(0)
def testConsUnbound(tup: Any *: Tuple) = tup(0)
def testCons(tup: Any *: EmptyTuple) = tup(0)
3 changes: 3 additions & 0 deletions tests/pos/i12721.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def bar(t: Any): Int = 1
def foo(t: AnyRef): Unit =
t.asInstanceOf[NonEmptyTuple].toList.map(bar)
8 changes: 8 additions & 0 deletions tests/pos/i16207.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import scala.compiletime.constValueTuple
import scala.deriving.Mirror.ProductOf

case class C(date: Int, time: Int)

inline def labelsOf[A](using p: ProductOf[A]): Tuple = constValueTuple[p.MirroredElemLabels]

val headers: List[String] = labelsOf[C].toList.map(_.toString)
18 changes: 9 additions & 9 deletions tests/run-staging/liftables.check
Original file line number Diff line number Diff line change
@@ -69,22 +69,22 @@ scala.Tuple21.apply[scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala
scala.Tuple22.apply[scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int](1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22)
{
val x$1: scala.Int = 1
scala.Tuple22.apply[scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int](2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23).*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.Tuple$package.EmptyTuple]]]]]]]]]]]]]]]]]]]]]]](x$1)
scala.Tuple.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.Tuple$package.EmptyTuple]]]]]]]]]]]]]]]]]]]]]]](scala.Tuple22.apply[scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int](2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23))(x$1)
}
{
val x$1: scala.Int = 1
{
scala.Tuple.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.Tuple$package.EmptyTuple]]]]]]]]]]]]]]]]]]]]]]]]({
val `x$1₂`: scala.Int = 2
scala.Tuple22.apply[scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int](3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24).*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.Tuple$package.EmptyTuple]]]]]]]]]]]]]]]]]]]]]]](`x$1₂`)
}.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.Tuple$package.EmptyTuple]]]]]]]]]]]]]]]]]]]]]]]](x$1)
scala.Tuple.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.Tuple$package.EmptyTuple]]]]]]]]]]]]]]]]]]]]]]](scala.Tuple22.apply[scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int](3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24))(`x$1₂`)
})(x$1)
}
{
val x$1: scala.Int = 1
{
scala.Tuple.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.Tuple$package.EmptyTuple]]]]]]]]]]]]]]]]]]]]]]]]]({
val `x$1₂`: scala.Int = 2
{
scala.Tuple.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.Tuple$package.EmptyTuple]]]]]]]]]]]]]]]]]]]]]]]]({
val `x$1₃`: scala.Int = 3
scala.Tuple22.apply[scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int](4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25).*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.Tuple$package.EmptyTuple]]]]]]]]]]]]]]]]]]]]]]](`x$1₃`)
}.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.Tuple$package.EmptyTuple]]]]]]]]]]]]]]]]]]]]]]]](`x$1₂`)
}.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.Tuple$package.EmptyTuple]]]]]]]]]]]]]]]]]]]]]]]]](x$1)
scala.Tuple.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.*:[scala.Int, scala.Tuple$package.EmptyTuple]]]]]]]]]]]]]]]]]]]]]]](scala.Tuple22.apply[scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int, scala.Int](4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25))(`x$1₃`)
})(`x$1₂`)
})(x$1)
}
8 changes: 4 additions & 4 deletions tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala
Original file line number Diff line number Diff line change
@@ -92,10 +92,10 @@ val experimentalDefinitionInLibrary = Set(
"scala.quoted.Quotes.reflectModule.TermParamClauseMethods.hasErasedArgs",

// New feature: reverse method on Tuple
"scala.Tuple.reverse", // can be stabilized in 3.5
"scala.Tuple$.Reverse", // can be stabilized in 3.5
"scala.Tuple$.ReverseOnto", // can be stabilized in 3.5
"scala.runtime.Tuples$.reverse", // can be stabilized in 3.5
"scala.Tuple$.reverse",
"scala.Tuple$.Reverse",
"scala.Tuple$.ReverseOnto",
"scala.runtime.Tuples$.reverse",
)


4 changes: 2 additions & 2 deletions tests/run/tuple-ops.scala
Original file line number Diff line number Diff line change
@@ -13,13 +13,13 @@ val r5: Unit = a.zip(d)
// Map
case class Foo[X](x: X)

val r6: (Int, Int, Int) = a.map[[t] =>> Int]([t] => (x: t) => x match {
val r6: (Int, Int, Int) = a.map[(1, 2, 3), [t] =>> Int]([t] => (x: t) => x match {
case x: Int => x * x
case _ => ???
})

val r7: ((1, Foo[1]), (2, Foo[2]), (3, Foo[3])) =
a.map[[t] =>> (t, Foo[t])]( [t] => (x: t) => (x, Foo(x)) )
a.map[(1, 2, 3), [t] =>> (t, Foo[t])]( [t] => (x: t) => (x, Foo(x)) )

// More Zip
val t1: Int *: Long *: Tuple = (1, 2l, 100, 200)
2 changes: 1 addition & 1 deletion tests/run/tuples1.scala
Original file line number Diff line number Diff line change
@@ -62,7 +62,7 @@ object Test extends App {
def head2[X <: NonEmptyTuple](x: X): Tuple.Head[X] = x.head

val hd1: Int = head1(x3)
// Without an explicit type parameter type inferance infers Nothing here.
// Without an explicit type parameter type inference infers Nothing here.
val hd2: Int = head2[x3.type](x3)

def tail1(x: NonEmptyTuple): Tuple.Tail[x.type] = x.tail