Skip to content

Commit 8fb7783

Browse files
committed
Add scala.quoted.Expr.unapply as dual of Expr.apply
`Expr.unapply` replaces `Unlifted.unapply` using the same signature that uses an `Unliftable` to perform the unlifting. The overload the works on sequences of expression is moved to `Exprs.unapply` (similar to `Consts.unapply`).
1 parent f57055c commit 8fb7783

File tree

8 files changed

+91
-88
lines changed

8 files changed

+91
-88
lines changed

docs/docs/reference/metaprogramming/macros.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -632,16 +632,16 @@ It is possible to deconstruct or extract values out of `Expr` using pattern matc
632632

633633
`scala.quoted` contains objects that can help extracting values from `Expr`.
634634

635-
* `scala.quoted.Unlifted`: matches an expression of a value (or list of values) and returns the value (or list of values).
636-
* `scala.quoted.Const`/`scala.quoted.Consts`: Same as `Unlifted` but only works on primitive values.
637-
* `scala.quoted.Varargs`: matches an explicit sequence of expressions and returns them. These sequences are useful to get individual `Expr[T]` out of a varargs expression of type `Expr[Seq[T]]`.
635+
* `scala.quoted.Expr`/`scala.quoted.Exprs`: matches an expression of a value (or list of values) and returns the value (or list of values).
636+
* `scala.quoted.Const`/`scala.quoted.Consts`: Same as `Expr`/`Exprs` but only works on primitive values.
637+
* `scala.quoted.Varargs`: matches an explicit sequence of expresions and returns them. These sequences are useful to get individual `Expr[T]` out of a varargs expression of type `Expr[Seq[T]]`.
638638

639639

640640
These could be used in the following way to optimize any call to `sum` that has statically known values.
641641
```scala
642642
inline def sum(inline args: Int*): Int = ${ sumExpr('args) }
643643
private def sumExpr(argsExpr: Expr[Seq[Int]])(using Quotes): Expr[Int] = argsExpr match {
644-
case Varargs(Unlifted(args)) => // args is of type Seq[Int]
644+
case Varargs(Exprs(args)) => // args is of type Seq[Int]
645645
Expr(args.sum) // precompute result of sum
646646
case Varargs(argExprs) => // argExprs is of type Seq[Expr[Int]]
647647
val staticSum: Int = argExprs.map(_.unlift.getOrElse(0))

library/src-bootstrapped/scala/quoted/Expr.scala

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,22 @@ object Expr {
2929
}
3030

3131
/** Lift a value into an expression containing the construction of that value */
32-
def apply[T](x: T)(using lift: Liftable[T])(using Quotes): Expr[T] =
33-
lift.toExpr(x)
32+
def apply[T](x: T)(using Liftable[T])(using Quotes): Expr[T] =
33+
scala.Predef.summon[Liftable[T]].toExpr(x)
34+
35+
/** Matches expressions containing values and extracts the value.
36+
*
37+
* Usage:
38+
* ```
39+
* case '{ ... ${expr @ Expr(value)}: T ...} =>
40+
* // expr: Expr[T]
41+
* // value: T
42+
* ```
43+
*
44+
* To directly unlift an expression `expr: Expr[T]` consider using `expr.unlift`/`expr.unliftOrError` insead.
45+
*/
46+
def unapply[T](x: Expr[T])(using Unliftable[T])(using Quotes): Option[T] =
47+
scala.Predef.summon[Unliftable[T]].fromExpr(x)
3448

3549
/** Lifts this sequence of expressions into an expression of a sequence
3650
*

library/src-bootstrapped/scala/quoted/Unliftable.scala

Lines changed: 61 additions & 61 deletions
Large diffs are not rendered by default.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
package scala.quoted
22

33
abstract class Expr[+T] private[scala]
4+
5+
object Expr:
6+
def unapply[T](x: Expr[T])(using Unliftable[T])(using Quotes): Option[T] = ???

library/src/scala/quoted/Unlifted.scala renamed to library/src/scala/quoted/Exprs.scala

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,15 @@
11
package scala.quoted
22

33
/** Value expressions */
4-
object Unlifted {
5-
6-
/** Matches expressions containing values and extracts the value.
7-
*
8-
* Usage:
9-
* ```
10-
* case '{ ... ${expr @ Unlifted(value)}: T ...} =>
11-
* // expr: Expr[T]
12-
* // value: T
13-
* ```
14-
*
15-
* To directly unlift an expression `expr: Expr[T]` consider using `expr.unlift`/`expr.unliftOrError` insead.
16-
*/
17-
def unapply[T](expr: Expr[T])(using Unliftable[T])(using Quotes): Option[T] =
18-
summon[Unliftable[T]].fromExpr(expr)
4+
object Exprs {
195

206
/** Matches literal sequence of literal constant value expressions and return a sequence of values.
217
*
228
* Usage:
239
* ```scala
2410
* inline def sum(args: Int*): Int = ${ sumExpr('args) }
2511
* def sumExpr(argsExpr: Expr[Seq[Int]])(using Quotes): Expr[Int] = argsExpr match
26-
* case Varargs(Unlifted(args)) =>
12+
* case Varargs(Exprs(args)) =>
2713
* // args: Seq[Int]
2814
* ...
2915
* }
@@ -34,8 +20,8 @@ object Unlifted {
3420
val builder = Seq.newBuilder[T]
3521
val iter = exprs.iterator
3622
while iter.hasNext do
37-
iter.next() match
38-
case Unlifted(value) => builder += value
23+
iter.next().unlift match
24+
case Some(value) => builder += value
3925
case _ => return None
4026
Some(builder.result())
4127

tests/run-macros/xml-interpolation-5/Macros_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ object XmlQuote {
2626

2727
def impl(receiver: Expr[SCOps.StringContext], args: Expr[Seq[Any]])(using Quotes): Expr[Xml] = {
2828
val string = receiver match {
29-
case '{ SCOps(${Unlifted(sc)}) } => Expr(sc.parts.mkString("??"))
29+
case '{ SCOps(${Expr(sc)}) } => Expr(sc.parts.mkString("??"))
3030
}
3131
'{new Xml(${string}, $args.toList)}
3232
}

tests/run-macros/xml-interpolation-6/Macros_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ object XmlQuote {
2626

2727
def impl(receiver: Expr[SCOps.StringContext], args: Expr[Seq[Any]])(using Quotes): Expr[Xml] = {
2828
val string = receiver match {
29-
case '{ SCOps(${Unlifted(sc)}): SCOps.StringContext } => sc.parts.mkString("??")
29+
case '{ SCOps(${Expr(sc)}): SCOps.StringContext } => sc.parts.mkString("??")
3030
}
3131
'{new Xml(${Expr(string)}, $args.toList)}
3232
}

tests/run-macros/xml-interpolation-7/Macros_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ object XmlQuote {
2626

2727
def impl(receiver: Expr[XMLOps.StringContext], args: Expr[Seq[Any]])(using Quotes): Expr[Xml] = {
2828
val string = receiver match {
29-
case '{ XMLOps.xml(${Unlifted(sc)}) } => sc.parts.mkString("??")
29+
case '{ XMLOps.xml(${Expr(sc)}) } => sc.parts.mkString("??")
3030
}
3131
'{new Xml(${Expr(string)}, $args.toList)}
3232
}

0 commit comments

Comments
 (0)