diff --git a/library/src/scala/NamedTuple.scala b/library/src/scala/NamedTuple.scala index f88f7760365b..1d45781f898d 100644 --- a/library/src/scala/NamedTuple.scala +++ b/library/src/scala/NamedTuple.scala @@ -1,5 +1,7 @@ package scala import compiletime.ops.boolean.* +import compiletime.summonAll +import collection.immutable.ListMap import language.experimental.captureChecking @@ -30,7 +32,7 @@ object NamedTuple: import NamedTupleDecomposition.{Names, DropNames} export NamedTupleDecomposition.{ Names, DropNames, - apply, size, init, head, last, tail, take, drop, splitAt, ++, map, reverse, zip, toList, toArray, toIArray + apply, size, init, head, last, tail, take, drop, splitAt, ++, map, reverse, zip, toList, toArray, toIArray, toListMap } extension [N <: Tuple, V <: Tuple](x: NamedTuple[N, V]) @@ -209,6 +211,12 @@ object NamedTupleDecomposition: /** An immutable array consisting of all element values */ inline def toIArray: IArray[Object] = x.toTuple.toIArray + /** An immutable map consisting of all element values preserving an order of fields. + * Keys are the names of the elements. + */ + inline def toListMap: ListMap[String, Tuple.Union[V]] = + inline compiletime.constValueTuple[N].toList match + case names: List[String] => ListMap.from(names.zip(x.toList)) end extension /** The names of a named tuple, represented as a tuple of literal string values. */ diff --git a/tests/run/named-tuple-ops.scala b/tests/run/named-tuple-ops.scala index 8c6db6f2fa1c..0dfd0ab7d1ec 100644 --- a/tests/run/named-tuple-ops.scala +++ b/tests/run/named-tuple-ops.scala @@ -1,5 +1,6 @@ //> using options -source future import scala.compiletime.asMatchable +import scala.collection.immutable.ListMap type City = (name: String, zip: Int, pop: Int) type Raw = (String, Int, Int) @@ -82,7 +83,10 @@ type Labels = (x: String, y: String) val _: List[String | Int] = cityFields assert(cityFields == List("Lausanne", 1000, 140000)) - val citArr = city.toArray - val _: List[String | Int] = cityFields - assert(cityFields == List("Lausanne", 1000, 140000)) + val cityArr = city.toArray + val _: Array[Object] = cityArr + assert(cityArr.sameElements(Array("Lausanne", 1000, 140000))) + val cityMap = city.toListMap + val _: ListMap[String, String | Int] = cityMap + assert(cityMap == ListMap("name" -> "Lausanne", "zip" -> 1000, "pop" -> 140000))