Skip to content

Commit ec621f0

Browse files
Merge pull request #9057 from dotty-staging/bootstrap-lib
Move Tuple and deriving to bootstrapped lib
2 parents 3c28893 + 28a7a90 commit ec621f0

File tree

6 files changed

+759
-0
lines changed

6 files changed

+759
-0
lines changed
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
package scala
2+
import annotation.showAsInfix
3+
import compiletime._
4+
import internal._
5+
6+
// non-bootstrapped
7+
8+
/** Tuple of arbitrary arity */
9+
sealed trait Tuple extends Any {
10+
import Tuple._
11+
12+
/** Create a copy this tuple as an Array */
13+
inline def toArray: Array[Object] =
14+
scala.runtime.Tuple.toArray(this)
15+
16+
/** Create a copy this tuple as an IArray */
17+
inline def toIArray: IArray[Object] =
18+
scala.runtime.Tuple.toIArray(this)
19+
20+
/** Return a new tuple by prepending the element to `this` tuple.
21+
* This operation is O(this.size)
22+
*/
23+
inline def *: [H, This >: this.type <: Tuple] (x: H): H *: This =
24+
scala.runtime.Tuple.cons(x, this).asInstanceOf[H *: This]
25+
26+
/** Return a new tuple by concatenating `this` tuple with `that` tuple.
27+
* This operation is O(this.size + that.size)
28+
*/
29+
inline def ++ [This >: this.type <: Tuple](that: Tuple): Concat[This, that.type] =
30+
scala.runtime.Tuple.concat(this, that).asInstanceOf[Concat[This, that.type]]
31+
32+
/** Return the size (or arity) of the tuple */
33+
inline def size[This >: this.type <: Tuple]: Size[This] =
34+
scala.runtime.Tuple.size(this).asInstanceOf[Size[This]]
35+
36+
/** Given two tuples, `(a1, ..., an)` and `(a1, ..., an)`, returns a tuple
37+
* `((a1, b1), ..., (an, bn))`. If the two tuples have different sizes,
38+
* the extra elements of the larger tuple will be disregarded.
39+
* The result is typed as `((A1, B1), ..., (An, Bn))` if at least one of the
40+
* tuple types has a `Unit` tail. Otherwise the result type is
41+
* `(A1, B1) *: ... *: (Ai, Bi) *: Tuple`
42+
*/
43+
inline def zip[This >: this.type <: Tuple, T2 <: Tuple](t2: T2): Zip[This, T2] =
44+
scala.runtime.Tuple.zip(this, t2).asInstanceOf[Zip[This, T2]]
45+
46+
/** Called on a tuple `(a1, ..., an)`, returns a new tuple `(f(a1), ..., f(an))`.
47+
* The result is typed as `(F[A1], ..., F[An])` if the tuple type is fully known.
48+
* If the tuple is of the form `a1 *: ... *: Tuple` (that is, the tail is not known
49+
* to be the cons type.
50+
*/
51+
inline def map[F[_]](f: [t] => t => F[t]): Map[this.type, F] =
52+
scala.runtime.Tuple.map(this, f).asInstanceOf[Map[this.type, F]]
53+
54+
/** Given a tuple `(a1, ..., am)`, returns the tuple `(a1, ..., an)` consisting
55+
* of its first n elements.
56+
*/
57+
inline def take[This >: this.type <: Tuple](n: Int): Take[This, n.type] =
58+
scala.runtime.Tuple.take(this, n).asInstanceOf[Take[This, n.type]]
59+
60+
61+
/** Given a tuple `(a1, ..., am)`, returns the tuple `(an+1, ..., am)` consisting
62+
* all its elements except the first n ones.
63+
*/
64+
inline def drop[This >: this.type <: Tuple](n: Int): Drop[This, n.type] =
65+
scala.runtime.Tuple.drop(this, n).asInstanceOf[Drop[This, n.type]]
66+
67+
/** Given a tuple `(a1, ..., am)`, returns a pair of the tuple `(a1, ..., an)`
68+
* consisting of the first n elements, and the tuple `(an+1, ..., am)` consisting
69+
* of the remaining elements.
70+
*/
71+
inline def splitAt[This >: this.type <: Tuple](n: Int): Split[This, n.type] =
72+
scala.runtime.Tuple.splitAt(this, n).asInstanceOf[Split[This, n.type]]
73+
}
74+
75+
object Tuple {
76+
77+
/** Type of the head of a tuple */
78+
type Head[X <: NonEmptyTuple] = X match {
79+
case x *: _ => x
80+
}
81+
82+
/** Type of the tail of a tuple */
83+
type Tail[X <: NonEmptyTuple] <: Tuple = X match {
84+
case _ *: xs => xs
85+
}
86+
87+
/** Type of the concatenation of two tuples */
88+
type Concat[X <: Tuple, +Y <: Tuple] <: Tuple = X match {
89+
case Unit => Y
90+
case x1 *: xs1 => x1 *: Concat[xs1, Y]
91+
}
92+
93+
/** Type of the element a position N in the tuple X */
94+
type Elem[X <: Tuple, N <: Int] = X match {
95+
case x *: xs =>
96+
N match {
97+
case 0 => x
98+
case S[n1] => Elem[xs, n1]
99+
}
100+
}
101+
102+
/** Literal constant Int size of a tuple */
103+
type Size[X <: Tuple] <: Int = X match {
104+
case Unit => 0
105+
case x *: xs => S[Size[xs]]
106+
}
107+
108+
/** Converts a tuple `(T1, ..., Tn)` to `(F[T1], ..., F[Tn])` */
109+
type Map[Tup <: Tuple, F[_]] <: Tuple = Tup match {
110+
case Unit => Unit
111+
case h *: t => F[h] *: Map[t, F]
112+
}
113+
114+
/** Given two tuples, `A1 *: ... *: An * At` and `B1 *: ... *: Bn *: Bt`
115+
* where at least one of `At` or `Bt` is `Unit` or `Tuple`,
116+
* returns the tuple type `(A1, B1) *: ... *: (An, Bn) *: Ct`
117+
* where `Ct` is `Unit` if `At` or `Bt` is `Unit`, otherwise `Ct` is `Tuple`.
118+
*/
119+
type Zip[T1 <: Tuple, T2 <: Tuple] <: Tuple = (T1, T2) match {
120+
case (h1 *: t1, h2 *: t2) => (h1, h2) *: Zip[t1, t2]
121+
case (Unit, _) => Unit
122+
case (_, Unit) => Unit
123+
case _ => Tuple
124+
}
125+
126+
/** Converts a tuple `(F[T1], ..., F[Tn])` to `(T1, ... Tn)` */
127+
type InverseMap[X <: Tuple, F[_]] <: Tuple = X match {
128+
case F[x] *: t => x *: InverseMap[t, F]
129+
case Unit => Unit
130+
}
131+
132+
/** Implicit evidence. IsMappedBy[F][X] is present in the implicit scope iff
133+
* X is a tuple for which each element's type is constructed via `F`. E.g.
134+
* (F[A1], ..., F[An]), but not `(F[A1], B2, ..., F[An])` where B2 does not
135+
* have the shape of `F[A]`.
136+
*/
137+
type IsMappedBy[F[_]] = [X <: Tuple] =>> X =:= Map[InverseMap[X, F], F]
138+
139+
/** Transforms a tuple `(T1, ..., Tn)` into `(T1, ..., Ti)`. */
140+
type Take[T <: Tuple, N <: Int] <: Tuple = N match {
141+
case 0 => Unit
142+
case S[n1] => T match {
143+
case Unit => Unit
144+
case x *: xs => x *: Take[xs, n1]
145+
}
146+
}
147+
148+
/** Transforms a tuple `(T1, ..., Tn)` into `(Ti+1, ..., Tn)`. */
149+
type Drop[T <: Tuple, N <: Int] <: Tuple = N match {
150+
case 0 => T
151+
case S[n1] => T match {
152+
case Unit => Unit
153+
case x *: xs => Drop[xs, n1]
154+
}
155+
}
156+
157+
/** Splits a tuple (T1, ..., Tn) into a pair of two tuples `(T1, ..., Ti)` and
158+
* `(Ti+1, ..., Tn)`.
159+
*/
160+
type Split[T <: Tuple, N <: Int] = (Take[T, N], Drop[T, N])
161+
162+
/** Convert an array into a tuple of unknown arity and types */
163+
def fromArray[T](xs: Array[T]): Tuple = {
164+
val xs2 = xs match {
165+
case xs: Array[Object] => xs
166+
case xs => xs.map(_.asInstanceOf[Object])
167+
}
168+
scala.runtime.Tuple.fromArray(xs2).asInstanceOf[Tuple]
169+
}
170+
171+
/** Convert an immutable array into a tuple of unknown arity and types */
172+
def fromIArray[T](xs: IArray[T]): Tuple = {
173+
val xs2: IArray[Object] = xs match {
174+
case xs: IArray[Object] => xs
175+
case xs =>
176+
// TODO support IArray.map
177+
xs.asInstanceOf[Array[T]].map(_.asInstanceOf[Object]).asInstanceOf[IArray[Object]]
178+
}
179+
scala.runtime.Tuple.fromIArray(xs2).asInstanceOf[Tuple]
180+
}
181+
182+
/** Convert a Product into a tuple of unknown arity and types */
183+
def fromProduct(product: Product): Tuple =
184+
scala.runtime.Tuple.fromProduct(product)
185+
186+
def fromProductTyped[P <: Product](p: P)(using m: scala.deriving.Mirror.ProductOf[P]): m.MirroredElemTypes =
187+
Tuple.fromArray(p.productIterator.toArray).asInstanceOf[m.MirroredElemTypes] // TODO use toIArray of Object to avoid double/triple array copy
188+
}
189+
190+
/** Tuple of arbitrary non-zero arity */
191+
sealed trait NonEmptyTuple extends Tuple with Product {
192+
import Tuple._
193+
194+
/** Get the i-th element of this tuple.
195+
* Equivalent to productElement but with a precise return type.
196+
*/
197+
inline def apply[This >: this.type <: NonEmptyTuple](n: Int): Elem[This, n.type] =
198+
scala.runtime.Tuple.apply(this, n).asInstanceOf[Elem[This, n.type]]
199+
200+
/** Get the head of this tuple */
201+
inline def head[This >: this.type <: NonEmptyTuple]: Head[This] =
202+
scala.runtime.Tuple.apply(this, 0).asInstanceOf[Head[This]]
203+
204+
/** Get the tail of this tuple.
205+
* This operation is O(this.size)
206+
*/
207+
inline def tail[This >: this.type <: NonEmptyTuple]: Tail[This] =
208+
scala.runtime.Tuple.tail(this).asInstanceOf[Tail[This]]
209+
210+
}
211+
212+
@showAsInfix
213+
sealed abstract class *:[+H, +T <: Tuple] extends NonEmptyTuple
214+
215+
object *: {
216+
def unapply[H, T <: Tuple](x: H *: T): (H, T) = (x.head, x.tail)
217+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package scala
2+
3+
// non bootstrapped
4+
5+
object deriving {
6+
7+
/** Mirrors allows typelevel access to enums, case classes and objects, and their sealed parents.
8+
*/
9+
sealed trait Mirror {
10+
11+
/** The mirrored *-type */
12+
type MirroredMonoType
13+
14+
/** The name of the type */
15+
type MirroredLabel <: String
16+
17+
/** The names of the product elements */
18+
type MirroredElemLabels <: Tuple
19+
}
20+
21+
object Mirror {
22+
23+
/** The Mirror for a sum type */
24+
trait Sum extends Mirror { self =>
25+
/** The ordinal number of the case class of `x`. For enums, `ordinal(x) == x.ordinal` */
26+
def ordinal(x: MirroredMonoType): Int
27+
}
28+
29+
/** The Mirror for a product type */
30+
trait Product extends Mirror {
31+
32+
/** Create a new instance of type `T` with elements taken from product `p`. */
33+
def fromProduct(p: scala.Product): MirroredMonoType
34+
}
35+
36+
trait Singleton extends Product {
37+
type MirroredMonoType = this.type
38+
type MirroredType = this.type
39+
type MirroredElemTypes = Unit
40+
type MirroredElemLabels = Unit
41+
def fromProduct(p: scala.Product) = this
42+
}
43+
44+
/** A proxy for Scala 2 singletons, which do not inherit `Singleton` directly */
45+
class SingletonProxy(val value: AnyRef) extends Product {
46+
type MirroredMonoType = value.type
47+
type MirroredType = value.type
48+
type MirroredElemTypes = Unit
49+
type MirroredElemLabels = Unit
50+
def fromProduct(p: scala.Product) = value
51+
}
52+
53+
type Of[T] = Mirror { type MirroredType = T; type MirroredMonoType = T ; type MirroredElemTypes <: Tuple }
54+
type ProductOf[T] = Mirror.Product { type MirroredType = T; type MirroredMonoType = T ; type MirroredElemTypes <: Tuple }
55+
type SumOf[T] = Mirror.Sum { type MirroredType = T; type MirroredMonoType = T; type MirroredElemTypes <: Tuple }
56+
}
57+
58+
/** Helper class to turn arrays into products */
59+
class ArrayProduct(val elems: Array[AnyRef]) extends Product {
60+
def this(size: Int) = this(new Array[AnyRef](size))
61+
def canEqual(that: Any): Boolean = true
62+
def productElement(n: Int) = elems(n)
63+
def productArity = elems.length
64+
override def productIterator: Iterator[Any] = elems.iterator
65+
def update(n: Int, x: Any) = elems(n) = x.asInstanceOf[AnyRef]
66+
}
67+
68+
/** The empty product */
69+
object EmptyProduct extends ArrayProduct(Array.emptyObjectArray)
70+
71+
/** Helper method to select a product element */
72+
def productElement[T](x: Any, idx: Int) =
73+
x.asInstanceOf[Product].productElement(idx).asInstanceOf[T]
74+
}

0 commit comments

Comments
 (0)