Skip to content

Commit b55981b

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 8a3f063 commit b55981b

File tree

16 files changed

+101
-98
lines changed

16 files changed

+101
-98
lines changed

docs/docs/reference/metaprogramming/macros.md

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

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

636-
* `scala.quoted.Unlifted`: matches an expression of a value (or list of values) and returns the value (or list of values).
637-
* `scala.quoted.Const`/`scala.quoted.Consts`: Same as `Unlifted` but only works on primitive values.
636+
* `scala.quoted.Expr`/`scala.quoted.Exprs`: matches an expression of a value (or list of values) and returns the value (or list of values).
637+
* `scala.quoted.Const`/`scala.quoted.Consts`: Same as `Expr`/`Exprs` but only works on primitive values.
638638
* `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]]`.
639639

640640

641641
These could be used in the following way to optimize any call to `sum` that has statically known values.
642642
```scala
643643
inline def sum(inline args: Int*): Int = ${ sumExpr('args) }
644644
private def sumExpr(argsExpr: Expr[Seq[Int]])(using Quotes): Expr[Int] = argsExpr match {
645-
case Varargs(Unlifted(args)) => // args is of type Seq[Int]
645+
case Varargs(Exprs(args)) => // args is of type Seq[Int]
646646
Expr(args.sum) // precompute result of sum
647647
case Varargs(argExprs) => // argExprs is of type Seq[Expr[Int]]
648648
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/neg-macros/i6432/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ object Macro {
99
import quotes.reflect._
1010
sc match {
1111
case '{ StringContext(${Varargs(parts)}: _*) } =>
12-
for (part @ Const(s) <- parts)
12+
for (part @ Expr(s) <- parts)
1313
report.error(s, Term.of(part).pos)
1414
}
1515
'{}

tests/neg-macros/i6432b/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ object Macro {
99
import quotes.reflect._
1010
sc match {
1111
case '{ StringContext(${Varargs(parts)}: _*) } =>
12-
for (part @ Const(s) <- parts)
12+
for (part @ Expr(s) <- parts)
1313
report.error(s, Term.of(part).pos)
1414
}
1515
'{}

tests/neg-macros/inline-macro-staged-interpreter/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ object E {
1010

1111
implicit def ev1[T: Type]: Unliftable[E[T]] = new Unliftable {
1212
def fromExpr(x: Expr[E[T]]) = x match {
13-
case '{ I(${Const(n)}) } => Some(I(n).asInstanceOf[E[T]])
13+
case '{ I(${Expr(n)}) } => Some(I(n).asInstanceOf[E[T]])
1414
case '{ Plus[T](${Value(x)}, ${Value(y)})(using $op) } if op.matches('{Plus2.IPlus}) => Some(Plus(x, y)(using Plus2.IPlus.asInstanceOf[Plus2[T]]).asInstanceOf[E[T]])
1515
case _ => None
1616
}

tests/run-macros/flops-rewrite-2/Macro_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ private def rewriteMacro[T: Type](x: Expr[T])(using Quotes): Expr[T] = {
2626
case (_, Some(_)) => '{ $y * $x }
2727
case _ => '{ $x * $y }
2828
}
29-
case '{ power(${Const(x)}, ${Const(y)}) } =>
29+
case '{ power(${Expr(x)}, ${Expr(y)}) } =>
3030
Expr(power(x, y))
31-
case '{ power($x, ${Const(y)}) } =>
31+
case '{ power($x, ${Expr(y)}) } =>
3232
if y == 0 then '{1}
3333
else '{ times($x, power($x, ${Expr(y-1)})) }
3434
}),

tests/run-macros/flops-rewrite-3/Macro_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ private def rewriteMacro[T: Type](x: Expr[T])(using Quotes): Expr[T] = {
2525
case (_, Some(_)) => '{ $y * $x }
2626
case _ => '{ $x * $y }
2727
}
28-
case '{ power(${Const(x)}, ${Const(y)}) } =>
28+
case '{ power(${Expr(x)}, ${Expr(y)}) } =>
2929
Expr(power(x, y))
30-
case '{ power($x, ${Const(y)}) } =>
30+
case '{ power($x, ${Expr(y)}) } =>
3131
if y == 0 then '{1}
3232
else '{ times($x, power($x, ${Expr(y-1)})) }
3333
}

tests/run-macros/inline-macro-staged-interpreter/Macro_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ object E {
1111

1212
implicit def ev1[T: Type]: Unliftable[E[T]] = new Unliftable { // TODO use type class derivation
1313
def fromExpr(x: Expr[E[T]]) = (x match {
14-
case '{ I(${Const(n)}) } => Some(I(n))
15-
case '{ D(${Const(n)}) } => Some(D(n))
14+
case '{ I(${Expr(n)}) } => Some(I(n))
15+
case '{ D(${Expr(n)}) } => Some(D(n))
1616
case '{ Plus[Int](${Value(x)}, ${Value(y)})(using $op) } => Some(Plus(x, y)(using Plus2.IPlus))
1717
case '{ Plus[Double](${Value(x)}, ${Value(y)})(using $op) } => Some(Plus(x, y)(using Plus2.DPlus))
1818
case '{ Times[Int](${Value(x)}, ${Value(y)})(using $op) } => Some(Times(x, y)(using Times2.ITimes))

tests/run-macros/quote-matcher-symantics-1/quoted_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ object Macros {
1010

1111
def lift(e: Expr[DSL]): Expr[T] = e match {
1212

13-
case '{ LitDSL(${ Const(c) }) } =>
13+
case '{ LitDSL(${ Expr(c) }) } =>
1414
'{ $sym.value(${Expr(c)}) }
1515

1616
case '{ ($x: DSL) + ($y: DSL) } =>

tests/run-macros/quote-matcher-symantics-2/quoted_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ object Macros {
2121

2222
def lift(e: Expr[DSL])(implicit env: Map[Int, Expr[T]]): Expr[T] = e match {
2323

24-
case '{ LitDSL(${Const(c)}) } => sym.value(c)
24+
case '{ LitDSL(${Expr(c)}) } => sym.value(c)
2525

2626
case '{ ($x: DSL) + ($y: DSL) } => sym.plus(lift(x), lift(y))
2727

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)