-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make failing pc tests work again in non-bootstrapped mode (#21707)
Bring back experimental NamedTuple in non-bootstrapped src/library. Needed to make SignatureHelpTests and CompletionTests to go through. [test_non_bootstrapped]
- Loading branch information
Showing
1 changed file
with
228 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
package scala | ||
import scala.language.experimental.clauseInterleaving | ||
import annotation.experimental | ||
import compiletime.ops.boolean.* | ||
|
||
@experimental | ||
object NamedTuple: | ||
|
||
/** The type to which named tuples get mapped to. For instance, | ||
* (name: String, age: Int) | ||
* gets mapped to | ||
* NamedTuple[("name", "age"), (String, Int)] | ||
*/ | ||
opaque type NamedTuple[N <: Tuple, +V <: Tuple] >: V <: AnyNamedTuple = V | ||
|
||
/** A type which is a supertype of all named tuples */ | ||
opaque type AnyNamedTuple = Any | ||
|
||
def apply[N <: Tuple, V <: Tuple](x: V): NamedTuple[N, V] = x | ||
|
||
def unapply[N <: Tuple, V <: Tuple](x: NamedTuple[N, V]): Some[V] = Some(x) | ||
|
||
/** A named tuple expression will desugar to a call to `build`. For instance, | ||
* `(name = "Lyra", age = 23)` will desugar to `build[("name", "age")]()(("Lyra", 23))`. | ||
*/ | ||
inline def build[N <: Tuple]()[V <: Tuple](x: V): NamedTuple[N, V] = x | ||
|
||
extension [V <: Tuple](x: V) | ||
inline def withNames[N <: Tuple]: NamedTuple[N, V] = x | ||
|
||
export NamedTupleDecomposition.{ | ||
Names, DropNames, | ||
apply, size, init, head, last, tail, take, drop, splitAt, ++, map, reverse, zip, toList, toArray, toIArray | ||
} | ||
|
||
extension [N <: Tuple, V <: Tuple](x: NamedTuple[N, V]) | ||
|
||
// ALL METHODS DEPENDING ON `toTuple` MUST BE EXPORTED FROM `NamedTupleDecomposition` | ||
/** The underlying tuple without the names */ | ||
inline def toTuple: V = x | ||
|
||
// This intentionally works for empty named tuples as well. I think NonEmptyTuple is a dead end | ||
// and should be reverted, just like NonEmptyList is also appealing at first, but a bad idea | ||
// in the end. | ||
|
||
// inline def :* [L] (x: L): NamedTuple[Append[N, ???], Append[V, L] = ??? | ||
// inline def *: [H] (x: H): NamedTuple[??? *: N], H *: V] = ??? | ||
|
||
end extension | ||
|
||
/** The size of a named tuple, represented as a literal constant subtype of Int */ | ||
type Size[X <: AnyNamedTuple] = Tuple.Size[DropNames[X]] | ||
|
||
/** The type of the element value at position N in the named tuple X */ | ||
type Elem[X <: AnyNamedTuple, N <: Int] = Tuple.Elem[DropNames[X], N] | ||
|
||
/** The type of the first element value of a named tuple */ | ||
type Head[X <: AnyNamedTuple] = Elem[X, 0] | ||
|
||
/** The type of the last element value of a named tuple */ | ||
type Last[X <: AnyNamedTuple] = Tuple.Last[DropNames[X]] | ||
|
||
/** The type of a named tuple consisting of all elements of named tuple X except the first one */ | ||
type Tail[X <: AnyNamedTuple] = Drop[X, 1] | ||
|
||
/** The type of the initial part of a named tuple without its last element */ | ||
type Init[X <: AnyNamedTuple] = | ||
NamedTuple[Tuple.Init[Names[X]], Tuple.Init[DropNames[X]]] | ||
|
||
/** The type of the named tuple consisting of the first `N` elements of `X`, | ||
* or all elements if `N` exceeds `Size[X]`. | ||
*/ | ||
type Take[X <: AnyNamedTuple, N <: Int] = | ||
NamedTuple[Tuple.Take[Names[X], N], Tuple.Take[DropNames[X], N]] | ||
|
||
/** The type of the named tuple consisting of all elements of `X` except the first `N` ones, | ||
* or no elements if `N` exceeds `Size[X]`. | ||
*/ | ||
type Drop[X <: AnyNamedTuple, N <: Int] = | ||
NamedTuple[Tuple.Drop[Names[X], N], Tuple.Drop[DropNames[X], N]] | ||
|
||
/** The pair type `(Take(X, N), Drop[X, N]). */ | ||
type Split[X <: AnyNamedTuple, N <: Int] = (Take[X, N], Drop[X, N]) | ||
|
||
/** Type of the concatenation of two tuples `X` and `Y` */ | ||
type Concat[X <: AnyNamedTuple, Y <: AnyNamedTuple] = | ||
NamedTuple[Tuple.Concat[Names[X], Names[Y]], Tuple.Concat[DropNames[X], DropNames[Y]]] | ||
|
||
/** The type of the named tuple `X` mapped with the type-level function `F`. | ||
* If `X = (n1 : T1, ..., ni : Ti)` then `Map[X, F] = `(n1 : F[T1], ..., ni : F[Ti])`. | ||
*/ | ||
type Map[X <: AnyNamedTuple, F[_ <: Tuple.Union[DropNames[X]]]] = | ||
NamedTuple[Names[X], Tuple.Map[DropNames[X], F]] | ||
|
||
/** A named tuple with the elements of tuple `X` in reversed order */ | ||
type Reverse[X <: AnyNamedTuple] = | ||
NamedTuple[Tuple.Reverse[Names[X]], Tuple.Reverse[DropNames[X]]] | ||
|
||
/** The type of the named tuple consisting of all element values of | ||
* named tuple `X` zipped with corresponding element values of | ||
* named tuple `Y`. If the two tuples have different sizes, | ||
* the extra elements of the larger tuple will be disregarded. | ||
* The names of `X` and `Y` at the same index must be the same. | ||
* The result tuple keeps the same names as the operand tuples. | ||
* For example, if | ||
* ``` | ||
* X = (n1 : S1, ..., ni : Si) | ||
* Y = (n1 : T1, ..., nj : Tj) where j >= i | ||
* ``` | ||
* then | ||
* ``` | ||
* Zip[X, Y] = (n1 : (S1, T1), ..., ni: (Si, Ti)) | ||
* ``` | ||
* @syntax markdown | ||
*/ | ||
type Zip[X <: AnyNamedTuple, Y <: AnyNamedTuple] = | ||
Names[X] match | ||
case Names[Y] => | ||
NamedTuple[Names[X], Tuple.Zip[DropNames[X], DropNames[Y]]] | ||
|
||
/** A type specially treated by the compiler to represent all fields of a | ||
* class argument `T` as a named tuple. Or, if `T` is already a named tuple, | ||
* `From[T]` is the same as `T`. | ||
*/ | ||
type From[T] <: AnyNamedTuple | ||
|
||
/** The type of the empty named tuple */ | ||
type Empty = NamedTuple[EmptyTuple, EmptyTuple] | ||
|
||
/** The empty named tuple */ | ||
val Empty: Empty = EmptyTuple | ||
|
||
end NamedTuple | ||
|
||
/** Separate from NamedTuple object so that we can match on the opaque type NamedTuple. */ | ||
@experimental | ||
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 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]] | ||
|
||
/** The number of elements in this tuple */ | ||
inline def size: Tuple.Size[V] = x.toTuple.size | ||
|
||
/** The first element value of this tuple */ | ||
inline def head: Tuple.Elem[V, 0] = apply(0) | ||
|
||
/** The last element value of this tuple */ | ||
inline def last: Tuple.Last[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]]] | ||
|
||
/** 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]]] | ||
|
||
/** 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) | ||
|
||
/** 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) | ||
|
||
/** 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) | ||
|
||
/** 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]] | ||
= 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]] = | ||
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 | ||
|
||
/** The named tuple consisting of all elements 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. | ||
* 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]] = | ||
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]]] | ||
|
||
/** An array consisting of all element values */ | ||
inline def toArray: Array[Object] = x.toTuple.toArray | ||
|
||
/** An immutable array consisting of all element values */ | ||
inline def toIArray: IArray[Object] = x.toTuple.toIArray | ||
|
||
end extension | ||
|
||
/** The names of a named tuple, represented as a tuple of literal string values. */ | ||
type Names[X <: AnyNamedTuple] <: Tuple = X match | ||
case NamedTuple[n, _] => n | ||
|
||
/** The value types of a named tuple represented as a regular tuple. */ | ||
type DropNames[NT <: AnyNamedTuple] <: Tuple = NT match | ||
case NamedTuple[_, x] => x |