Skip to content

Add quoted.Exprs and move Value(s) into Expr(s) #8504

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/docs/reference/metaprogramming/macros.md
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ It is possible to deconstruct or extract values out of `Expr` using pattern matc
`scala.quoted` contains objects that can help extracting values from `Expr`.

* `scala.quoted.Const`/`scala.quoted.Consts`: matches an expression of a literal value (or list of values) and returns the value (or list of values).
* `scala.quoted.Value`/`scala.quoted.Values`: matches an expression of a value (or list of values) and returns the value (or list of values).
* `scala.quoted.Expr`/`scala.quoted.Exprs`: matches an expression of a value (or list of values) and returns the value (or list of values).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not intuitive --- Expr and values are very different, conceptually.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we say that Expr(x) takes a value and lifts it into and Expr, then case Expr(x) => takes the value out of the expression. It seems really intuitive but may need to be explained in a better way.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe unlift, to align with Unliftable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we would need to move Expr.apply to Lift.apply (or Lifted.apply). This would break a lot of code.

In a patterns Unlifted works better, which is a bit too long.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will open a PR with the alternative

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #8513. It does look semantically clearer. But has migration costs (a deprecation warining).

* `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]]`.

These could be used in the following way to optimize any call to `sum` that has statically known values.
Expand Down
12 changes: 12 additions & 0 deletions library/src/scala/quoted/Expr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ object Expr {
/** Lift a value into an expression containing the construction of that value */
def apply[T](x: T)(using qctx: QuoteContext, lift: Liftable[T]): Expr[T] = lift.toExpr(x)

/** Matches expressions containing values and extracts the value.
*
* Usage:
* ```
* (x: Expr[B]) match {
* case Expr(value) => ... // value: B
* }
* ```
*/
def unapply[T](expr: Expr[T])(using valueOf: ValueOfExpr[T], qxtc: QuoteContext): Option[T] =
valueOf(expr)

/** Lifts this sequence of expressions into an expression of a sequence
*
* Transforms a sequence of expression
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package scala.quoted

/** Value expressions */
object Values {
/** Sequences of expressions */
object Exprs {

/** Lift a sequence of values into a sequense of expressions containing the construction of each value */
def apply[T](xs: Seq[T])(using lift: Liftable[T], qctx: QuoteContext): Seq[Expr[T]] =
xs.map(x => Expr(x))

/** Matches literal sequence of literal constant value expressions and return a sequence of values.
*
* Usage:
* ```scala
* inline def sum(args: Int*): Int = ${ sumExpr('args) }
* def sumExpr(argsExpr: Expr[Seq[Int]])(using QuoteContext): Expr[Int] = argsExpr match
* case Varargs(Values(args)) =>
* case Varargs(Exprs(args)) =>
* // args: Seq[Int]
* ...
* }
Expand All @@ -18,8 +22,9 @@ object Values {
def unapply[T](exprs: Seq[Expr[T]])(using valueOf: ValueOfExpr[T], qctx: QuoteContext): Option[Seq[T]] =
exprs.foldRight(Option(List.empty[T])) { (elem, acc) =>
(elem, acc) match {
case (Value(value), Some(lst)) => Some(value :: lst)
case (Expr(value), Some(lst)) => Some(value :: lst)
case (_, _) => None
}
}

}
18 changes: 0 additions & 18 deletions library/src/scala/quoted/Value.scala

This file was deleted.

98 changes: 49 additions & 49 deletions library/src/scala/quoted/ValueOfExpr.scala

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions library/src/scala/quoted/matching/ValueSeq.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ object ValueSeq {
* }
* ```
*/
@deprecated("use scala.quoted.Varargs(scala.quoted.Value(_)) instead", "0.23.0")
@deprecated("use scala.quoted.Varargs(scala.quoted.Exprs(_)) instead", "0.23.0")
def unapply[T](expr: Expr[Seq[T]])(using valueOf: ValueOfExpr[T], qctx: QuoteContext): Option[Seq[T]] =
import scala.quoted.Const
expr match
case Varargs(Values(elems)) => Some(elems)
case Varargs(Exprs(elems)) => Some(elems)
case _ => None

}
4 changes: 2 additions & 2 deletions library/src/scala/quoted/matching/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ package object matching {
@deprecated("use scala.quoted.Lambda instead", "0.23.0")
val Lambda: quoted.Lambda.type = quoted.Lambda

@deprecated("use scala.quoted.Value instead", "0.23.0")
val Value: quoted.Value.type = quoted.Value
@deprecated("use scala.quoted.Expr instead", "0.23.0")
val Value: quoted.Expr.type = quoted.Expr

@deprecated("use scala.quoted.ValueOfExpr instead", "0.23.0")
val ValueOfExpr: quoted.ValueOfExpr.type = quoted.ValueOfExpr
Expand Down