Skip to content

Commit 4379077

Browse files
Merge pull request #9209 from dotty-staging/add-summonAll-and-constValueTuple
Add summonAll and constValueTuple
2 parents ffd6a58 + bf38180 commit 4379077

File tree

6 files changed

+68
-0
lines changed

6 files changed

+68
-0
lines changed

library/src/scala/Tuple.scala

+12
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,18 @@ object Tuple {
143143
}
144144
}
145145

146+
/**
147+
* Use this type to widen a self-type to a tuple. E.g.
148+
* ```
149+
* val x: (1, 3) = (1, 3)
150+
* val y: Widen[x.type] = x
151+
* ```
152+
*/
153+
type Widen[Tup <: Tuple] <: Tuple = Tup match {
154+
case EmptyTuple => EmptyTuple
155+
case h *: t => h *: t
156+
}
157+
146158
/** Given two tuples, `A1 *: ... *: An * At` and `B1 *: ... *: Bn *: Bt`
147159
* where at least one of `At` or `Bt` is `EmptyTuple` or `Tuple`,
148160
* returns the tuple type `(A1, B1) *: ... *: (An, Bn) *: Ct`

library/src/scala/compiletime/package.scala

+43
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ import scala.quoted._
44

55
package object compiletime {
66

7+
/** Use this method when you have a type, do not have a value for it but want to
8+
* pattern match on it. For example, given a type `Tup <: Tuple`, one can
9+
* pattern-match on it as follows:
10+
* ```
11+
* erasedValue[Tup] match {
12+
* case _: EmptyTuple => ...
13+
* case _: h *: t => ...
14+
* }
15+
* ```
16+
*/
717
erased def erasedValue[T]: T = ???
818

919
/** The error method is used to produce user-defined compile errors during inline expansion.
@@ -38,10 +48,29 @@ package object compiletime {
3848
transparent inline def (inline self: StringContext) code (inline args: Any*): String =
3949
${ dotty.internal.CompileTimeMacros.codeExpr('self, 'args) }
4050

51+
/** Same as `constValue` but returns a `None` if a constant value
52+
* cannot be constructed from the provided type. Otherwise returns
53+
* that value wrapped in `Some`.
54+
*/
4155
inline def constValueOpt[T]: Option[T] = ???
4256

57+
/** Given a constant, singleton type `T`, convert it to a value
58+
* of the same singleton type. For example: `assert(constValue[1] == 1)`.
59+
*/
4360
inline def constValue[T]: T = ???
4461

62+
/** Given a tuple type `(X1, ..., Xn)`, returns a tuple value
63+
* `(constValue[X1], ..., constValue[Xn])`.
64+
*/
65+
inline def constValueTuple[T <: Tuple]: Tuple.Widen[T]=
66+
val res =
67+
inline erasedValue[T] match
68+
case _: EmptyTuple => EmptyTuple
69+
case _: (t *: ts) => constValue[t] *: constValueTuple[ts]
70+
end match
71+
res.asInstanceOf[Tuple.Widen[T]]
72+
end constValueTuple
73+
4574
/** Summons first given matching one of the listed cases. E.g. in
4675
*
4776
* given B { ... }
@@ -68,6 +97,20 @@ package object compiletime {
6897
case t: T => t
6998
}
7099

100+
/** Given a tuple T, summons each of its member types and returns them in
101+
* a Tuple.
102+
*
103+
* @tparam T the tuple containing the types of the values to be summoned
104+
* @return the given values typed as elements of the tuple
105+
*/
106+
inline def summonAll[T <: Tuple]: Tuple.Widen[T] =
107+
val res =
108+
inline erasedValue[T] match
109+
case _: EmptyTuple => EmptyTuple
110+
case _: (t *: ts) => summonInline[t] *: summonAll[ts]
111+
end match
112+
res.asInstanceOf[Tuple.Widen[T]]
113+
end summonAll
71114

72115
/** Succesor of a natural number where zero is the type 0 and successors are reduced as if the definition was
73116
*

tests/run/constValueTuple.check

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
(foo,bar,10,2.5)

tests/run/constValueTuple.scala

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import compiletime.constValueTuple
2+
3+
@main def Test =
4+
println(constValueTuple["foo" *: "bar" *: 10 *: 2.5 *: EmptyTuple])

tests/run/summonAll.check

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
(10,foo,1.2)

tests/run/summonAll.scala

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import compiletime.summonAll
2+
3+
@main def Test =
4+
given as Int = 10
5+
given as String = "foo"
6+
given as Double = 1.2
7+
println(summonAll[Int *: String *: Double *: EmptyTuple])

0 commit comments

Comments
 (0)