From f931a6d66078f22be8f5820261662efa0074d645 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Fri, 4 Oct 2024 18:13:09 +0200 Subject: [PATCH 1/4] Use the NamedTuple type ops for the result types of the term ops --- .../src-bootstrapped/scala/NamedTuple.scala | 43 ++++++++----------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/library/src-bootstrapped/scala/NamedTuple.scala b/library/src-bootstrapped/scala/NamedTuple.scala index 71bcd26a16e2..acc318b2be99 100644 --- a/library/src-bootstrapped/scala/NamedTuple.scala +++ b/library/src-bootstrapped/scala/NamedTuple.scala @@ -25,6 +25,7 @@ object NamedTuple: extension [V <: Tuple](x: V) inline def withNames[N <: Tuple]: NamedTuple[N, V] = x + import NamedTupleDecomposition.{Names, DropNames} export NamedTupleDecomposition.{ Names, DropNames, apply, size, init, head, last, tail, take, drop, splitAt, ++, map, reverse, zip, toList, toArray, toIArray @@ -134,65 +135,57 @@ object NamedTupleDecomposition: import NamedTuple.* extension [N <: Tuple, V <: Tuple](x: NamedTuple[N, V]) /** The value (without the name) at index `n` of this tuple */ - inline def apply(n: Int): Tuple.Elem[V, n.type] = + inline def apply(n: Int): Elem[NamedTuple[N, V], n.type] = inline x.toTuple match - case tup: NonEmptyTuple => tup(n).asInstanceOf[Tuple.Elem[V, n.type]] - case tup => tup.productElement(n).asInstanceOf[Tuple.Elem[V, n.type]] + case tup: NonEmptyTuple => tup(n).asInstanceOf[Elem[NamedTuple[N, V], n.type]] + case tup => tup.productElement(n).asInstanceOf[Elem[NamedTuple[N, V], n.type]] /** The number of elements in this tuple */ - inline def size: Tuple.Size[V] = x.toTuple.size + inline def size: Size[NamedTuple[N, V]] = x.toTuple.size /** The first element value of this tuple */ - inline def head: Tuple.Elem[V, 0] = apply(0) + inline def head: Head[NamedTuple[N, V]] = apply(0) /** The last element value of this tuple */ - inline def last: Tuple.Last[V] = apply(size - 1).asInstanceOf[Tuple.Last[V]] + inline def last: Last[NamedTuple[N, V]] = apply(size - 1).asInstanceOf[Tuple.Last[V]] /** The tuple consisting of all elements of this tuple except the last one */ - inline def init: NamedTuple[Tuple.Init[N], Tuple.Init[V]] = - x.toTuple.take(size - 1).asInstanceOf[NamedTuple[Tuple.Init[N], Tuple.Init[V]]] + inline def init: Init[NamedTuple[N, V]] = + x.toTuple.take(size - 1).asInstanceOf[Init[NamedTuple[N, V]]] /** The tuple consisting of all elements of this tuple except the first one */ - inline def tail: NamedTuple[Tuple.Tail[N], Tuple.Tail[V]] = - x.toTuple.drop(1).asInstanceOf[NamedTuple[Tuple.Tail[N], Tuple.Tail[V]]] + inline def tail: Tail[NamedTuple[N, V]] = + x.toTuple.drop(1).asInstanceOf[Tail[NamedTuple[N, V]]] /** The tuple consisting of the first `n` elements of this tuple, or all * elements if `n` exceeds `size`. */ - inline def take(n: Int): NamedTuple[Tuple.Take[N, n.type], Tuple.Take[V, n.type]] = - x.toTuple.take(n) + inline def take(n: Int): Take[NamedTuple[N, V], n.type] = x.toTuple.take(n) /** The tuple consisting of all elements of this tuple except the first `n` ones, * or no elements if `n` exceeds `size`. */ - inline def drop(n: Int): NamedTuple[Tuple.Drop[N, n.type], Tuple.Drop[V, n.type]] = - x.toTuple.drop(n) + inline def drop(n: Int): Drop[NamedTuple[N, V], n.type] = x.toTuple.drop(n) /** The tuple `(x.take(n), x.drop(n))` */ - inline def splitAt(n: Int): - (NamedTuple[Tuple.Take[N, n.type], Tuple.Take[V, n.type]], - NamedTuple[Tuple.Drop[N, n.type], Tuple.Drop[V, n.type]]) = - // would be nice if this could have type `Split[NamedTuple[N, V]]` instead, but - // we get a type error then. Similar for other methods here. - x.toTuple.splitAt(n) + inline def splitAt(n: Int): Split[NamedTuple[N, V], n.type] = x.toTuple.splitAt(n) /** The tuple consisting of all elements of this tuple followed by all elements * of tuple `that`. The names of the two tuples must be disjoint. */ inline def ++ [N2 <: Tuple, V2 <: Tuple](that: NamedTuple[N2, V2])(using Tuple.Disjoint[N, N2] =:= true) - : NamedTuple[Tuple.Concat[N, N2], Tuple.Concat[V, V2]] + : Concat[NamedTuple[N, V], NamedTuple[N2, V2]] = x.toTuple ++ that.toTuple /** The named tuple consisting of all element values of this tuple mapped by * the polymorphic mapping function `f`. The names of elements are preserved. * If `x = (n1 = v1, ..., ni = vi)` then `x.map(f) = `(n1 = f(v1), ..., ni = f(vi))`. */ - inline def map[F[_]](f: [t] => t => F[t]): NamedTuple[N, Tuple.Map[V, F]] = + inline def map[F[_]](f: [t] => t => F[t]): Map[NamedTuple[N, V], F] = x.toTuple.map(f).asInstanceOf[NamedTuple[N, Tuple.Map[V, F]]] /** The named tuple consisting of all elements of this tuple in reverse */ - inline def reverse: NamedTuple[Tuple.Reverse[N], Tuple.Reverse[V]] = - x.toTuple.reverse + inline def reverse: Reverse[NamedTuple[N, V]] = x.toTuple.reverse /** The named tuple consisting of all elements values of this tuple zipped * with corresponding element values in named tuple `that`. @@ -201,7 +194,7 @@ object NamedTupleDecomposition: * The names of `x` and `that` at the same index must be the same. * The result tuple keeps the same names as the operand tuples. */ - inline def zip[V2 <: Tuple](that: NamedTuple[N, V2]): NamedTuple[N, Tuple.Zip[V, V2]] = + inline def zip[V2 <: Tuple](that: NamedTuple[N, V2]): Zip[NamedTuple[N, V], NamedTuple[N, V2]] = x.toTuple.zip(that.toTuple) /** A list consisting of all element values */ From 12eb487179949815102d5a194ac25f5e7c26d0af Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Fri, 4 Oct 2024 18:34:19 +0200 Subject: [PATCH 2/4] Drop `asInstanceOf` from the NamedTuple term ops where possible --- library/src-bootstrapped/scala/NamedTuple.scala | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/library/src-bootstrapped/scala/NamedTuple.scala b/library/src-bootstrapped/scala/NamedTuple.scala index acc318b2be99..37ce031fba10 100644 --- a/library/src-bootstrapped/scala/NamedTuple.scala +++ b/library/src-bootstrapped/scala/NamedTuple.scala @@ -147,15 +147,14 @@ object NamedTupleDecomposition: inline def head: Head[NamedTuple[N, V]] = apply(0) /** The last element value of this tuple */ - inline def last: Last[NamedTuple[N, V]] = apply(size - 1).asInstanceOf[Tuple.Last[V]] + inline def last: Last[NamedTuple[N, V]] = apply(size - 1).asInstanceOf[Last[NamedTuple[N, V]]] /** The tuple consisting of all elements of this tuple except the last one */ inline def init: Init[NamedTuple[N, V]] = - x.toTuple.take(size - 1).asInstanceOf[Init[NamedTuple[N, V]]] + x.take(size - 1).asInstanceOf[Init[NamedTuple[N, V]]] /** The tuple consisting of all elements of this tuple except the first one */ - inline def tail: Tail[NamedTuple[N, V]] = - x.toTuple.drop(1).asInstanceOf[Tail[NamedTuple[N, V]]] + inline def tail: Tail[NamedTuple[N, V]] = x.toTuple.drop(1) /** The tuple consisting of the first `n` elements of this tuple, or all * elements if `n` exceeds `size`. @@ -182,7 +181,7 @@ object NamedTupleDecomposition: * If `x = (n1 = v1, ..., ni = vi)` then `x.map(f) = `(n1 = f(v1), ..., ni = f(vi))`. */ inline def map[F[_]](f: [t] => t => F[t]): Map[NamedTuple[N, V], F] = - x.toTuple.map(f).asInstanceOf[NamedTuple[N, Tuple.Map[V, F]]] + x.toTuple.map(f) /** The named tuple consisting of all elements of this tuple in reverse */ inline def reverse: Reverse[NamedTuple[N, V]] = x.toTuple.reverse @@ -198,7 +197,7 @@ object NamedTupleDecomposition: x.toTuple.zip(that.toTuple) /** A list consisting of all element values */ - inline def toList: List[Tuple.Union[V]] = x.toTuple.toList.asInstanceOf[List[Tuple.Union[V]]] + inline def toList: List[Tuple.Union[V]] = x.toTuple.toList /** An array consisting of all element values */ inline def toArray: Array[Object] = x.toTuple.toArray From 6a971b1eec85f887652482b492ad169c0e98a586 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Fri, 4 Oct 2024 19:06:17 +0200 Subject: [PATCH 3/4] Fix typos --- docs/_docs/reference/other-new-features/named-tuples.md | 4 ++-- library/src-bootstrapped/scala/NamedTuple.scala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/_docs/reference/other-new-features/named-tuples.md b/docs/_docs/reference/other-new-features/named-tuples.md index bf1ae4ca7046..0abc91e5ecf8 100644 --- a/docs/_docs/reference/other-new-features/named-tuples.md +++ b/docs/_docs/reference/other-new-features/named-tuples.md @@ -127,7 +127,7 @@ NamedTuple[("name", "age"), (String, Int)] A `NamedTuple[N, V]` type is publicly known to be a supertype (but not a subtype) of its value paramater `V`, which means that regular tuples can be assigned to named tuples but not _vice versa_. -The `NamedTuple` object contains a number of extension methods for named tuples hat mirror the same functions in `Tuple`. Examples are +The `NamedTuple` object contains a number of extension methods for named tuples that mirror the same functions in `Tuple`. Examples are `apply`, `head`, `tail`, `take`, `drop`, `++`, `map`, or `zip`. Similar to `Tuple`, the `NamedTuple` object also contains types such as `Elem`, `Head`, `Concat` that describe the results of these extension methods. @@ -154,7 +154,7 @@ that `c: C`, and that `n` is not otherwise legal as a name of a selection on `c` Then `c.n` is a legal selection, which expands to `c.selectDynamic("n").asInstanceOf[T]`. It is the task of the implementation of `selectDynamic` in `C` to ensure that its -computed result conforms to the predicted type `T` +computed result conforms to the predicted type `T`. As an example, assume we have a query type `Q[T]` defined as follows: diff --git a/library/src-bootstrapped/scala/NamedTuple.scala b/library/src-bootstrapped/scala/NamedTuple.scala index 37ce031fba10..f8a821dc45ef 100644 --- a/library/src-bootstrapped/scala/NamedTuple.scala +++ b/library/src-bootstrapped/scala/NamedTuple.scala @@ -186,7 +186,7 @@ object NamedTupleDecomposition: /** The named tuple consisting of all elements of this tuple in reverse */ inline def reverse: Reverse[NamedTuple[N, V]] = x.toTuple.reverse - /** The named tuple consisting of all elements values of this tuple zipped + /** The named tuple consisting of all element values of this tuple zipped * with corresponding element values in named tuple `that`. * If the two tuples have different sizes, * the extra elements of the larger tuple will be disregarded. From bd88a0f510a7c4c910e33bee2bf2ca8626ff78ea Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Wed, 9 Oct 2024 17:03:47 +0200 Subject: [PATCH 4/4] Add an explicit type instantiation in `NamedTuple.map` To avoid triggering a deep subtype comparison needed for the inference of the higher-kinded type parameter. --- library/src-bootstrapped/scala/NamedTuple.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src-bootstrapped/scala/NamedTuple.scala b/library/src-bootstrapped/scala/NamedTuple.scala index f8a821dc45ef..d105cf042f37 100644 --- a/library/src-bootstrapped/scala/NamedTuple.scala +++ b/library/src-bootstrapped/scala/NamedTuple.scala @@ -181,7 +181,7 @@ object NamedTupleDecomposition: * If `x = (n1 = v1, ..., ni = vi)` then `x.map(f) = `(n1 = f(v1), ..., ni = f(vi))`. */ inline def map[F[_]](f: [t] => t => F[t]): Map[NamedTuple[N, V], F] = - x.toTuple.map(f) + x.toTuple.map[F](f) /** The named tuple consisting of all elements of this tuple in reverse */ inline def reverse: Reverse[NamedTuple[N, V]] = x.toTuple.reverse