Skip to content

Commit eee615d

Browse files
committed
Rename scala.runtime.{Tuple => Tuples}
To avoid confusion with scala.Tuple. Part of #10602.
1 parent 1405778 commit eee615d

File tree

8 files changed

+848
-45
lines changed

8 files changed

+848
-45
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -867,20 +867,20 @@ class Definitions {
867867

868868
def TupleXXL_fromIterator(using Context): Symbol = TupleXXLModule.requiredMethod("fromIterator")
869869

870-
@tu lazy val RuntimeTupleModule: Symbol = requiredModule("scala.runtime.Tuple")
871-
@tu lazy val RuntimeTupleModuleClass: Symbol = RuntimeTupleModule.moduleClass
872-
lazy val RuntimeTuple_consIterator: Symbol = RuntimeTupleModule.requiredMethod("consIterator")
873-
lazy val RuntimeTuple_concatIterator: Symbol = RuntimeTupleModule.requiredMethod("concatIterator")
874-
lazy val RuntimeTuple_apply: Symbol = RuntimeTupleModule.requiredMethod("apply")
875-
lazy val RuntimeTuple_cons: Symbol = RuntimeTupleModule.requiredMethod("cons")
876-
lazy val RuntimeTuple_size: Symbol = RuntimeTupleModule.requiredMethod("size")
877-
lazy val RuntimeTuple_tail: Symbol = RuntimeTupleModule.requiredMethod("tail")
878-
lazy val RuntimeTuple_concat: Symbol = RuntimeTupleModule.requiredMethod("concat")
879-
lazy val RuntimeTuple_toArray: Symbol = RuntimeTupleModule.requiredMethod("toArray")
880-
lazy val RuntimeTuple_productToArray: Symbol = RuntimeTupleModule.requiredMethod("productToArray")
881-
lazy val RuntimeTuple_isInstanceOfTuple: Symbol = RuntimeTupleModule.requiredMethod("isInstanceOfTuple")
882-
lazy val RuntimeTuple_isInstanceOfEmptyTuple: Symbol = RuntimeTupleModule.requiredMethod("isInstanceOfEmptyTuple")
883-
lazy val RuntimeTuple_isInstanceOfNonEmptyTuple: Symbol = RuntimeTupleModule.requiredMethod("isInstanceOfNonEmptyTuple")
870+
@tu lazy val RuntimeTuplesModule: Symbol = requiredModule("scala.runtime.Tuples")
871+
@tu lazy val RuntimeTuplesModuleClass: Symbol = RuntimeTuplesModule.moduleClass
872+
lazy val RuntimeTuples_consIterator: Symbol = RuntimeTuplesModule.requiredMethod("consIterator")
873+
lazy val RuntimeTuples_concatIterator: Symbol = RuntimeTuplesModule.requiredMethod("concatIterator")
874+
lazy val RuntimeTuples_apply: Symbol = RuntimeTuplesModule.requiredMethod("apply")
875+
lazy val RuntimeTuples_cons: Symbol = RuntimeTuplesModule.requiredMethod("cons")
876+
lazy val RuntimeTuples_size: Symbol = RuntimeTuplesModule.requiredMethod("size")
877+
lazy val RuntimeTuples_tail: Symbol = RuntimeTuplesModule.requiredMethod("tail")
878+
lazy val RuntimeTuples_concat: Symbol = RuntimeTuplesModule.requiredMethod("concat")
879+
lazy val RuntimeTuples_toArray: Symbol = RuntimeTuplesModule.requiredMethod("toArray")
880+
lazy val RuntimeTuples_productToArray: Symbol = RuntimeTuplesModule.requiredMethod("productToArray")
881+
lazy val RuntimeTuples_isInstanceOfTuple: Symbol = RuntimeTuplesModule.requiredMethod("isInstanceOfTuple")
882+
lazy val RuntimeTuples_isInstanceOfEmptyTuple: Symbol = RuntimeTuplesModule.requiredMethod("isInstanceOfEmptyTuple")
883+
lazy val RuntimeTuples_isInstanceOfNonEmptyTuple: Symbol = RuntimeTuplesModule.requiredMethod("isInstanceOfNonEmptyTuple")
884884

885885
// Annotation base classes
886886
@tu lazy val AnnotationClass: ClassSymbol = requiredClass("scala.annotation.Annotation")

compiler/src/dotty/tools/dotc/transform/TupleOptimizations.scala

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
2424
def phaseName: String = "genericTuples"
2525

2626
override def transformApply(tree: tpd.Apply)(using Context): tpd.Tree =
27-
if (!tree.symbol.exists || tree.symbol.owner != defn.RuntimeTupleModuleClass) tree
28-
else if (tree.symbol == defn.RuntimeTuple_cons) transformTupleCons(tree)
29-
else if (tree.symbol == defn.RuntimeTuple_tail) transformTupleTail(tree)
30-
else if (tree.symbol == defn.RuntimeTuple_size) transformTupleSize(tree)
31-
else if (tree.symbol == defn.RuntimeTuple_concat) transformTupleConcat(tree)
32-
else if (tree.symbol == defn.RuntimeTuple_apply) transformTupleApply(tree)
33-
else if (tree.symbol == defn.RuntimeTuple_toArray) transformTupleToArray(tree)
27+
if (!tree.symbol.exists || tree.symbol.owner != defn.RuntimeTuplesModuleClass) tree
28+
else if (tree.symbol == defn.RuntimeTuples_cons) transformTupleCons(tree)
29+
else if (tree.symbol == defn.RuntimeTuples_tail) transformTupleTail(tree)
30+
else if (tree.symbol == defn.RuntimeTuples_size) transformTupleSize(tree)
31+
else if (tree.symbol == defn.RuntimeTuples_concat) transformTupleConcat(tree)
32+
else if (tree.symbol == defn.RuntimeTuples_apply) transformTupleApply(tree)
33+
else if (tree.symbol == defn.RuntimeTuples_toArray) transformTupleToArray(tree)
3434
else tree
3535

3636
private def transformTupleCons(tree: tpd.Apply)(using Context): Tree = {
@@ -49,7 +49,7 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
4949
else {
5050
// val it = Iterator.single(head) ++ tail.asInstanceOf[Product].productIterator
5151
// TupleN+1(it.next(), ..., it.next())
52-
val fullIterator = ref(defn.RuntimeTuple_consIterator).appliedToArgs(head :: tail :: Nil)
52+
val fullIterator = ref(defn.RuntimeTuples_consIterator).appliedToArgs(head :: tail :: Nil)
5353
evalOnce(fullIterator) { it =>
5454
knownTupleFromIterator(tpes.length, it).asInstance(tree.tpe)
5555
}
@@ -127,7 +127,7 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
127127
else {
128128
// val it = self.asInstanceOf[Product].productIterator ++ that.asInstanceOf[Product].productIterator
129129
// TupleN+M(it.next(), ..., it.next())
130-
val fullIterator = ref(defn.RuntimeTuple_concatIterator).appliedToArgs(tree.args)
130+
val fullIterator = ref(defn.RuntimeTuples_concatIterator).appliedToArgs(tree.args)
131131
evalOnce(fullIterator) { it =>
132132
knownTupleFromIterator(n + m, it).asInstance(tree.tpe)
133133
}
@@ -176,7 +176,7 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
176176
ref(defn.ArrayModule).select("emptyObjectArray".toTermName).ensureApplied
177177
else if (size <= MaxTupleArity)
178178
// scala.runtime.Tuple.productToArray(tup.asInstanceOf[Product])
179-
ref(defn.RuntimeTuple_productToArray).appliedTo(tup.asInstance(defn.ProductClass.typeRef))
179+
ref(defn.RuntimeTuples_productToArray).appliedTo(tup.asInstance(defn.ProductClass.typeRef))
180180
else
181181
// tup.asInstanceOf[TupleXXL].elems.clone()
182182
tup.asInstance(defn.TupleXXLClass.typeRef).select(nme.toArray)

compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ object TypeTestsCasts {
321321
*/
322322
def transformTypeTest(expr: Tree, testType: Type, flagUnrelated: Boolean): Tree = testType.dealias match {
323323
case tref: TermRef if tref.symbol == defn.EmptyTupleModule =>
324-
ref(defn.RuntimeTuple_isInstanceOfEmptyTuple).appliedTo(expr)
324+
ref(defn.RuntimeTuples_isInstanceOfEmptyTuple).appliedTo(expr)
325325
case _: SingletonType =>
326326
expr.isInstance(testType).withSpan(tree.span)
327327
case OrType(tp1, tp2) =>
@@ -343,11 +343,11 @@ object TypeTestsCasts {
343343
.and(isArrayTest(e))
344344
}
345345
case tref: TypeRef if tref.symbol == defn.TupleClass =>
346-
ref(defn.RuntimeTuple_isInstanceOfTuple).appliedTo(expr)
346+
ref(defn.RuntimeTuples_isInstanceOfTuple).appliedTo(expr)
347347
case tref: TypeRef if tref.symbol == defn.NonEmptyTupleClass =>
348-
ref(defn.RuntimeTuple_isInstanceOfNonEmptyTuple).appliedTo(expr)
348+
ref(defn.RuntimeTuples_isInstanceOfNonEmptyTuple).appliedTo(expr)
349349
case AppliedType(tref: TypeRef, _) if tref.symbol == defn.PairClass =>
350-
ref(defn.RuntimeTuple_isInstanceOfNonEmptyTuple).appliedTo(expr)
350+
ref(defn.RuntimeTuples_isInstanceOfNonEmptyTuple).appliedTo(expr)
351351
case _ =>
352352
val erasedTestType = erasure(testType)
353353
transformIsInstanceOf(expr, erasedTestType, erasedTestType, flagUnrelated)
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
package scala
2+
import annotation.showAsInfix
3+
import compiletime._
4+
5+
/** Tuple of arbitrary arity */
6+
sealed trait Tuple extends Product {
7+
import Tuple._
8+
9+
/** Create a copy this tuple as an Array */
10+
inline def toArray: Array[Object] =
11+
runtime.Tuples.toArray(this)
12+
13+
/** Create a copy this tuple as a List */
14+
inline def toList: List[Union[this.type]] =
15+
this.productIterator.toList
16+
.asInstanceOf[List[Union[this.type]]]
17+
18+
/** Create a copy this tuple as an IArray */
19+
inline def toIArray: IArray[Object] =
20+
runtime.Tuples.toIArray(this)
21+
22+
/** Return a new tuple by prepending the element to `this` tuple.
23+
* This operation is O(this.size)
24+
*/
25+
inline def *: [H, This >: this.type <: Tuple] (x: H): H *: This =
26+
runtime.Tuples.cons(x, this).asInstanceOf[H *: This]
27+
28+
/** Return a new tuple by concatenating `this` tuple with `that` tuple.
29+
* This operation is O(this.size + that.size)
30+
*/
31+
inline def ++ [This >: this.type <: Tuple](that: Tuple): Concat[This, that.type] =
32+
runtime.Tuples.concat(this, that).asInstanceOf[Concat[This, that.type]]
33+
34+
/** Return the size (or arity) of the tuple */
35+
inline def size[This >: this.type <: Tuple]: Size[This] =
36+
runtime.Tuples.size(this).asInstanceOf[Size[This]]
37+
38+
/** Given two tuples, `(a1, ..., an)` and `(a1, ..., an)`, returns a tuple
39+
* `((a1, b1), ..., (an, bn))`. If the two tuples have different sizes,
40+
* the extra elements of the larger tuple will be disregarded.
41+
* The result is typed as `((A1, B1), ..., (An, Bn))` if at least one of the
42+
* tuple types has a `EmptyTuple` tail. Otherwise the result type is
43+
* `(A1, B1) *: ... *: (Ai, Bi) *: Tuple`
44+
*/
45+
inline def zip[This >: this.type <: Tuple, T2 <: Tuple](t2: T2): Zip[This, T2] =
46+
runtime.Tuples.zip(this, t2).asInstanceOf[Zip[This, T2]]
47+
48+
/** Called on a tuple `(a1, ..., an)`, returns a new tuple `(f(a1), ..., f(an))`.
49+
* The result is typed as `(F[A1], ..., F[An])` if the tuple type is fully known.
50+
* If the tuple is of the form `a1 *: ... *: Tuple` (that is, the tail is not known
51+
* to be the cons type.
52+
*/
53+
inline def map[F[_]](f: [t] => t => F[t]): Map[this.type, F] =
54+
runtime.Tuples.map(this, f).asInstanceOf[Map[this.type, F]]
55+
56+
/** Given a tuple `(a1, ..., am)`, returns the tuple `(a1, ..., an)` consisting
57+
* of its first n elements.
58+
*/
59+
inline def take[This >: this.type <: Tuple](n: Int): Take[This, n.type] =
60+
runtime.Tuples.take(this, n).asInstanceOf[Take[This, n.type]]
61+
62+
63+
/** Given a tuple `(a1, ..., am)`, returns the tuple `(an+1, ..., am)` consisting
64+
* all its elements except the first n ones.
65+
*/
66+
inline def drop[This >: this.type <: Tuple](n: Int): Drop[This, n.type] =
67+
runtime.Tuples.drop(this, n).asInstanceOf[Drop[This, n.type]]
68+
69+
/** Given a tuple `(a1, ..., am)`, returns a pair of the tuple `(a1, ..., an)`
70+
* consisting of the first n elements, and the tuple `(an+1, ..., am)` consisting
71+
* of the remaining elements.
72+
*/
73+
inline def splitAt[This >: this.type <: Tuple](n: Int): Split[This, n.type] =
74+
runtime.Tuples.splitAt(this, n).asInstanceOf[Split[This, n.type]]
75+
}
76+
77+
object Tuple {
78+
79+
/** Type of the head of a tuple */
80+
type Head[X <: NonEmptyTuple] = X match {
81+
case x *: _ => x
82+
}
83+
84+
/** Type of the tail of a tuple */
85+
type Tail[X <: NonEmptyTuple] <: Tuple = X match {
86+
case _ *: xs => xs
87+
}
88+
89+
/** Type of the concatenation of two tuples */
90+
type Concat[X <: Tuple, +Y <: Tuple] <: Tuple = X match {
91+
case EmptyTuple => Y
92+
case x1 *: xs1 => x1 *: Concat[xs1, Y]
93+
}
94+
95+
/** Type of the element a position N in the tuple X */
96+
type Elem[X <: Tuple, N <: Int] = X match {
97+
case x *: xs =>
98+
N match {
99+
case 0 => x
100+
case S[n1] => Elem[xs, n1]
101+
}
102+
}
103+
104+
/** Literal constant Int size of a tuple */
105+
type Size[X <: Tuple] <: Int = X match {
106+
case EmptyTuple => 0
107+
case x *: xs => S[Size[xs]]
108+
}
109+
110+
/** Fold a tuple `(T1, ..., Tn)` into `F[T1, F[... F[Tn, Z]...]]]` */
111+
type Fold[T <: Tuple, Z, F[_, _]] = T match
112+
case EmptyTuple => Z
113+
case h *: t => F[h, Fold[t, Z, F]]
114+
115+
/** Converts a tuple `(T1, ..., Tn)` to `(F[T1], ..., F[Tn])` */
116+
type Map[Tup <: Tuple, F[_]] <: Tuple = Tup match {
117+
case EmptyTuple => EmptyTuple
118+
case h *: t => F[h] *: Map[t, F]
119+
}
120+
121+
/** Converts a tuple `(T1, ..., Tn)` to a flattened `(..F[T1], ..., ..F[Tn])` */
122+
type FlatMap[Tup <: Tuple, F[_] <: Tuple] <: Tuple = Tup match {
123+
case EmptyTuple => EmptyTuple
124+
case h *: t => Concat[F[h], FlatMap[t, F]]
125+
}
126+
127+
/** Filters out those members of the tuple for which the predicate `P` returns `false`.
128+
* A predicate `P[X]` is a type that can be either `true` or `false`. For example:
129+
* ```
130+
* type IsString[x] = x match {
131+
* case String => true
132+
* case _ => false
133+
* }
134+
* Filter[(1, "foo", 2, "bar"), IsString] =:= ("foo", "bar")
135+
* ```
136+
*/
137+
type Filter[Tup <: Tuple, P[_] <: Boolean] <: Tuple = Tup match {
138+
case EmptyTuple => EmptyTuple
139+
case h *: t => P[h] match {
140+
case true => h *: Filter[t, P]
141+
case false => Filter[t, P]
142+
}
143+
}
144+
145+
/** Given two tuples, `A1 *: ... *: An * At` and `B1 *: ... *: Bn *: Bt`
146+
* where at least one of `At` or `Bt` is `EmptyTuple` or `Tuple`,
147+
* returns the tuple type `(A1, B1) *: ... *: (An, Bn) *: Ct`
148+
* where `Ct` is `EmptyTuple` if `At` or `Bt` is `EmptyTuple`, otherwise `Ct` is `Tuple`.
149+
*/
150+
type Zip[T1 <: Tuple, T2 <: Tuple] <: Tuple = (T1, T2) match {
151+
case (h1 *: t1, h2 *: t2) => (h1, h2) *: Zip[t1, t2]
152+
case (EmptyTuple, _) => EmptyTuple
153+
case (_, EmptyTuple) => EmptyTuple
154+
case _ => Tuple
155+
}
156+
157+
/** Converts a tuple `(F[T1], ..., F[Tn])` to `(T1, ... Tn)` */
158+
type InverseMap[X <: Tuple, F[_]] <: Tuple = X match {
159+
case F[x] *: t => x *: InverseMap[t, F]
160+
case EmptyTuple => EmptyTuple
161+
}
162+
163+
/** Implicit evidence. IsMappedBy[F][X] is present in the implicit scope iff
164+
* X is a tuple for which each element's type is constructed via `F`. E.g.
165+
* (F[A1], ..., F[An]), but not `(F[A1], B2, ..., F[An])` where B2 does not
166+
* have the shape of `F[A]`.
167+
*/
168+
type IsMappedBy[F[_]] = [X <: Tuple] =>> X =:= Map[InverseMap[X, F], F]
169+
170+
/** Transforms a tuple `(T1, ..., Tn)` into `(T1, ..., Ti)`. */
171+
type Take[T <: Tuple, N <: Int] <: Tuple = N match {
172+
case 0 => EmptyTuple
173+
case S[n1] => T match {
174+
case EmptyTuple => EmptyTuple
175+
case x *: xs => x *: Take[xs, n1]
176+
}
177+
}
178+
179+
/** Transforms a tuple `(T1, ..., Tn)` into `(Ti+1, ..., Tn)`. */
180+
type Drop[T <: Tuple, N <: Int] <: Tuple = N match {
181+
case 0 => T
182+
case S[n1] => T match {
183+
case EmptyTuple => EmptyTuple
184+
case x *: xs => Drop[xs, n1]
185+
}
186+
}
187+
188+
/** Splits a tuple (T1, ..., Tn) into a pair of two tuples `(T1, ..., Ti)` and
189+
* `(Ti+1, ..., Tn)`.
190+
*/
191+
type Split[T <: Tuple, N <: Int] = (Take[T, N], Drop[T, N])
192+
193+
/** Given a tuple `(T1, ..., Tn)`, returns a union of its
194+
* member types: `T1 | ... | Tn`. Returns `Nothing` if the tuple is empty.
195+
*/
196+
type Union[T <: Tuple] = Fold[T, Nothing, [x, y] =>> x | y]
197+
198+
/** Empty tuple */
199+
def apply(): EmptyTuple = EmptyTuple
200+
201+
/** Tuple with one element */
202+
def apply[T](x: T): T *: EmptyTuple = Tuple1(x)
203+
204+
/** Matches an empty tuple. */
205+
def unapply(x: EmptyTuple): true = true
206+
207+
/** Convert an array into a tuple of unknown arity and types */
208+
def fromArray[T](xs: Array[T]): Tuple = {
209+
val xs2 = xs match {
210+
case xs: Array[Object] => xs
211+
case xs => xs.map(_.asInstanceOf[Object])
212+
}
213+
runtime.Tuples.fromArray(xs2).asInstanceOf[Tuple]
214+
}
215+
216+
/** Convert an immutable array into a tuple of unknown arity and types */
217+
def fromIArray[T](xs: IArray[T]): Tuple = {
218+
val xs2: IArray[Object] = xs match {
219+
case xs: IArray[Object] @unchecked => xs
220+
case xs =>
221+
// TODO support IArray.map
222+
xs.asInstanceOf[Array[T]].map(_.asInstanceOf[Object]).asInstanceOf[IArray[Object]]
223+
}
224+
runtime.Tuples.fromIArray(xs2).asInstanceOf[Tuple]
225+
}
226+
227+
/** Convert a Product into a tuple of unknown arity and types */
228+
def fromProduct(product: Product): Tuple =
229+
runtime.Tuples.fromProduct(product)
230+
231+
def fromProductTyped[P <: Product](p: P)(using m: scala.deriving.Mirror.ProductOf[P]): m.MirroredElemTypes =
232+
runtime.Tuples.fromProduct(p).asInstanceOf[m.MirroredElemTypes]
233+
}
234+
235+
/** A tuple of 0 elements */
236+
type EmptyTuple = EmptyTuple.type
237+
238+
/** A tuple of 0 elements. */
239+
object EmptyTuple extends Tuple {
240+
override def productArity: Int = 0
241+
242+
@throws(classOf[IndexOutOfBoundsException])
243+
override def productElement(n: Int): Any =
244+
throw new IndexOutOfBoundsException(n.toString())
245+
246+
def canEqual(that: Any): Boolean = this == that
247+
248+
override def toString(): String = "()"
249+
}
250+
251+
/** Tuple of arbitrary non-zero arity */
252+
sealed trait NonEmptyTuple extends Tuple {
253+
import Tuple._
254+
255+
/** Get the i-th element of this tuple.
256+
* Equivalent to productElement but with a precise return type.
257+
*/
258+
inline def apply[This >: this.type <: NonEmptyTuple](n: Int): Elem[This, n.type] =
259+
runtime.Tuples.apply(this, n).asInstanceOf[Elem[This, n.type]]
260+
261+
/** Get the head of this tuple */
262+
inline def head[This >: this.type <: NonEmptyTuple]: Head[This] =
263+
runtime.Tuples.apply(this, 0).asInstanceOf[Head[This]]
264+
265+
/** Get the tail of this tuple.
266+
* This operation is O(this.size)
267+
*/
268+
inline def tail[This >: this.type <: NonEmptyTuple]: Tail[This] =
269+
runtime.Tuples.tail(this).asInstanceOf[Tail[This]]
270+
271+
}
272+
273+
@showAsInfix
274+
sealed abstract class *:[+H, +T <: Tuple] extends NonEmptyTuple
275+
276+
object *: {
277+
def unapply[H, T <: Tuple](x: H *: T): (H, T) = (x.head, x.tail)
278+
}

0 commit comments

Comments
 (0)