Skip to content

Use unlift/unliftOrError in code examples #10571

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

Merged
Merged
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
6 changes: 3 additions & 3 deletions docs/docs/reference/changed-features/numeric-literals.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,8 @@ method in the `FromDigits` given instance. That method is defined in terms of a
implementation method `fromDigitsImpl`. Here is its definition:
```scala
private def fromDigitsImpl(digits: Expr[String])(using ctx: Quotes): Expr[BigFloat] =
digits match {
case Const(ds) =>
digits.unlift match {
case Some(ds) =>
try {
val BigFloat(m, e) = apply(ds)
'{BigFloat(${Expr(m)}, ${Expr(e)})}
Expand All @@ -218,7 +218,7 @@ implementation method `fromDigitsImpl`. Here is its definition:
ctx.error(ex.getMessage)
'{BigFloat(0, 0)}
}
case digits =>
case None =>
'{apply($digits)}
}
} // end BigFloat
Expand Down
29 changes: 9 additions & 20 deletions docs/docs/reference/metaprogramming/macros.md
Original file line number Diff line number Diff line change
Expand Up @@ -633,25 +633,20 @@ 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.Unlifted`: matches an expression of a value (or list of values) and returns the value (or list of values).
* `scala.quoted.Const`/`scala.quoted.Consts`: Same as `Unlifted` but only works on primitive values.
* `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.
```scala
inline def sum(inline args: Int*): Int = ${ sumExpr('args) }
private def sumExpr(argsExpr: Expr[Seq[Int]])(using Quotes): Expr[Int] = argsExpr match {
case Varargs(Consts(args)) => // args is of type Seq[Int]
case Varargs(Unlifted(args)) => // args is of type Seq[Int]
Expr(args.sum) // precompute result of sum
case Varargs(argExprs) => // argExprs is of type Seq[Expr[Int]]
val staticSum: Int = argExprs.map {
case Const(arg) => arg
case _ => 0
}.sum
val dynamicSum: Seq[Expr[Int]] = argExprs.filter {
case Const(_) => false
case arg => true
}
val staticSum: Int = argExprs.map(_.unlift.getOrElse(0))
val dynamicSum: Seq[Expr[Int]] = argExprs.filter(_.unlift.isEmpty)
dynamicSum.foldLeft(Expr(staticSum))((acc, arg) => '{ $acc + $arg })
case _ =>
'{ $argsExpr.sum }
Expand Down Expand Up @@ -688,14 +683,8 @@ private def sumExpr(args1: Seq[Expr[Int]])(using Quotes): Expr[Int] = {
case arg => Seq(arg)
}
val args2 = args1.flatMap(flatSumArgs)
val staticSum: Int = args2.map {
case Const(arg) => arg
case _ => 0
}.sum
val dynamicSum: Seq[Expr[Int]] = args2.filter {
case Const(_) => false
case arg => true
}
val staticSum: Int = args2.map(_.unlift.getOrElse(0)).sum
val dynamicSum: Seq[Expr[Int]] = args2.filter(_.unlift.isEmpty)
dynamicSum.foldLeft(Expr(staticSum))((acc, arg) => '{ $acc + $arg })
}
```
Expand Down Expand Up @@ -771,8 +760,8 @@ private def evalExpr(e: Expr[Int])(using Quotes): Expr[Int] = {
// body: Expr[Int => Int] where the argument represents references to y
evalExpr(Expr.betaReduce(body)(evalExpr(x)))
case '{ ($x: Int) * ($y: Int) } =>
(x, y) match
case (Const(a), Const(b)) => Expr(a * b)
(x.unlift, y.unlift) match
case (Some(a), Some(b)) => Expr(a * b)
case _ => e
case _ => e
}
Expand Down
6 changes: 3 additions & 3 deletions tests/neg-macros/BigFloat/BigFloatFromDigitsImpl_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import scala.quoted._

object BigFloatFromDigitsImpl:
def apply(digits: Expr[String])(using Quotes): Expr[BigFloat] =
digits match
case Const(ds) =>
digits.unlift match
case Some(ds) =>
try
val BigFloat(m, e) = BigFloat(ds)
'{BigFloat(${Expr(m)}, ${Expr(e)})}
catch case ex: FromDigits.FromDigitsException =>
quotes.reflect.report.error(ex.getMessage)
'{BigFloat(0, 0)}
case digits =>
case None =>
'{BigFloat($digits)}
4 changes: 2 additions & 2 deletions tests/neg-macros/GenericNumLits/EvenFromDigitsImpl_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import scala.quoted._
import Even._

object EvenFromDigitsImpl:
def apply(digits: Expr[String])(using Quotes): Expr[Even] = digits match {
case Const(ds) =>
def apply(digits: Expr[String])(using Quotes): Expr[Even] = digits.unlift match {
case Some(ds) =>
val ev =
try evenFromDigits(ds)
catch {
Expand Down
6 changes: 3 additions & 3 deletions tests/run-macros/BigFloat/BigFloatFromDigitsImpl_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import scala.quoted._

object BigFloatFromDigitsImpl:
def apply(digits: Expr[String])(using Quotes): Expr[BigFloat] =
digits match
case Const(ds) =>
digits.unlift match
case Some(ds) =>
try
val BigFloat(m, e) = BigFloat(ds)
'{BigFloat(${Expr(m)}, ${Expr(e)})}
catch case ex: FromDigits.FromDigitsException =>
import quotes.reflect.report
report.error(ex.getMessage)
'{BigFloat(0, 0)}
case digits =>
case None =>
'{BigFloat($digits)}
2 changes: 1 addition & 1 deletion tests/run-macros/enum-nat-macro/Macros_2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ import Nat._
case 0 => acc
case n => inner[Succ[N]](n - 1, '{Succ($acc)})

val Const(i) = int
val i = int.unliftOrError
require(i >= 0)
inner[Zero.type](i, '{Zero})
18 changes: 9 additions & 9 deletions tests/run-macros/flops-rewrite-2/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ private def rewriteMacro[T: Type](x: Expr[T])(using Quotes): Expr[T] = {
postTransform = List(
Transformation[Int] {
case '{ plus($x, $y) } =>
(x, y) match {
case (Const(0), _) => y
case (Const(a), Const(b)) => Expr(a + b)
case (_, Const(_)) => '{ $y + $x }
(x.unlift, y.unlift) match {
case (Some(0), _) => y
case (Some(a), Some(b)) => Expr(a + b)
case (_, Some(_)) => '{ $y + $x }
case _ => '{ $x + $y }
}
case '{ times($x, $y) } =>
(x, y) match {
case (Const(0), _) => '{0}
case (Const(1), _) => y
case (Const(a), Const(b)) => Expr(a * b)
case (_, Const(_)) => '{ $y * $x }
(x.unlift, y.unlift) match {
case (Some(0), _) => '{0}
case (Some(1), _) => y
case (Some(a), Some(b)) => Expr(a * b)
case (_, Some(_)) => '{ $y * $x }
case _ => '{ $x * $y }
}
case '{ power(${Const(x)}, ${Const(y)}) } =>
Expand Down
18 changes: 9 additions & 9 deletions tests/run-macros/flops-rewrite-3/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@ private def rewriteMacro[T: Type](x: Expr[T])(using Quotes): Expr[T] = {
val rewriter = Rewriter().withFixPoint.withPost(
Transformation.safe[Int] {
case '{ plus($x, $y) } =>
(x, y) match {
case (Const(0), _) => y
case (Const(a), Const(b)) => Expr(a + b)
case (_, Const(_)) => '{ $y + $x }
(x.unlift, y.unlift) match {
case (Some(0), _) => y
case (Some(a), Some(b)) => Expr(a + b)
case (_, Some(_)) => '{ $y + $x }
case _ => '{ $x + $y }
}
case '{ times($x, $y) } =>
(x, y) match {
case (Const(0), _) => '{0}
case (Const(1), _) => y
case (Const(a), Const(b)) => Expr(a * b)
case (_, Const(_)) => '{ $y * $x }
(x.unlift, y.unlift) match {
case (Some(0), _) => '{0}
case (Some(1), _) => y
case (Some(a), Some(b)) => Expr(a * b)
case (_, Some(_)) => '{ $y * $x }
case _ => '{ $x * $y }
}
case '{ power(${Const(x)}, ${Const(y)}) } =>
Expand Down
4 changes: 2 additions & 2 deletions tests/run-macros/i8671/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ object FileName {

def createFileName(fileName: Expr[String])(using Quotes): Expr[FileName] =
import quotes.reflect.report
fileName match {
case e@Const(s) =>
fileName.unlift match {
case Some(s) =>
fileNameFromString(s) match {
case Right(fn) =>
'{FileName.unsafe(${Expr(fn.name)})} // Or `Expr(fn)` if there is a `Liftable[FileName]`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ object Macros {
private def impl(self: Expr[StringContext], args: Expr[Seq[String]])(using Quotes): Expr[String] = {
(self, args) match {
case ('{ StringContext(${Varargs(parts)}: _*) }, Varargs(args1)) =>
val strParts = parts.map { case Const(str) => str.reverse }
val strArgs = args1.map { case Const(str) => str }
val strParts = parts.map(_.unliftOrError.reverse)
val strArgs = args1.map(_.unliftOrError)
Expr(StringContext(strParts: _*).s(strArgs: _*))
case _ => ???
}
Expand Down
10 changes: 2 additions & 8 deletions tests/run-macros/quoted-matching-docs-2/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,7 @@ private def sumExpr(args1: Seq[Expr[Int]])(using Quotes): Expr[Int] = {
case arg => Seq(arg)
}
val args2 = args1.flatMap(flatSumArgs)
val staticSum: Int = args2.map {
case Const(arg) => arg
case _ => 0
}.sum
val dynamicSum: Seq[Expr[Int]] = args2.filter {
case Const(_) => false
case arg => true
}
val staticSum: Int = args2.map(_.unlift.getOrElse(0)).sum
val dynamicSum: Seq[Expr[Int]] = args2.filter(_.unlift.isEmpty)
dynamicSum.foldLeft(Expr(staticSum))((acc, arg) => '{ $acc + $arg })
}
10 changes: 2 additions & 8 deletions tests/run-macros/quoted-matching-docs/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,8 @@ private def sumExpr(argsExpr: Expr[Seq[Int]])(using Quotes) : Expr[Int] = {
case Varargs(Consts(args)) => // args is of type Seq[Int]
Expr(args.sum) // precompute result of sum
case Varargs(argExprs) => // argExprs is of type Seq[Expr[Int]]
val staticSum: Int = argExprs.map {
case Const(arg) => arg
case _ => 0
}.sum
val dynamicSum: Seq[Expr[Int]] = argExprs.filter {
case Const(_) => false
case arg => true
}
val staticSum: Int = argExprs.map(_.unlift.getOrElse(0)).sum
val dynamicSum: Seq[Expr[Int]] = argExprs.filter(_.unlift.isEmpty)
dynamicSum.foldLeft(Expr(staticSum))((acc, arg) => '{ $acc + $arg })
case _ =>
'{ $argsExpr.sum }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ private def evalExpr(using Quotes)(e: Expr[Int]): Expr[Int] = {
case '{ val y: Int = $x; $body(y): Int } =>
evalExpr(Expr.betaReduce('{$body(${evalExpr(x)})}))
case '{ ($x: Int) * ($y: Int) } =>
(x, y) match
case (Const(a), Const(b)) => Expr(a * b)
(x.unlift, y.unlift) match
case (Some(a), Some(b)) => Expr(a * b)
case _ => e
case _ => e
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ object Macro {

private def fooCore(parts: Seq[Expr[String]], args: Seq[Expr[Any]], reporter: Reporter)(using Quotes): Expr[String] = {
for ((part, idx) <- parts.zipWithIndex) {
val Const(v: String) = part
val v = part.unliftOrError
if (v.contains("#"))
reporter.errorOnPart("Cannot use #", idx)
}
Expand Down