Skip to content

Commit 9cba8f5

Browse files
committed
Fix Expr.{unlift, unliftOrError} and add missing Unliftables
* Fix `unlift` to recive the most precise `Unliftable`. Previously we could not add `Unliftable[List[T]]` because the implicit search would fail with an ambigouity between `Unliftable[List[T]]` and `Unliftable[List[T]]`. this came from the `U >: T` bound that was added to workarround the covariant `T`. As extension methods we can simply have the same `T` for the expression type and the unliftable type. This way, we also find the most precise `T`/`Unliftable[T]` available. * Add unliftable for `Nil`/`List` * Add unliftable for `None`/`Some` * Add unliftable for `Map` * Add unliftable for `Set` * Add unliftable for `Left`/`Right` * Add unliftable for `EmptyTuple` * Support `->` in `Tuple2`
1 parent b8825a2 commit 9cba8f5

File tree

6 files changed

+352
-80
lines changed

6 files changed

+352
-80
lines changed

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

+21-16
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,6 @@ abstract class Expr[+T] private[scala] {
1313
def showWith(syntaxHighlight: SyntaxHighlight)(using qctx: QuoteContext): String =
1414
this.unseal.showWith(syntaxHighlight)
1515

16-
/** Return the unlifted value of this expression.
17-
*
18-
* Returns `None` if the expression does not contain a value or contains side effects.
19-
* Otherwise returns the `Some` of the value.
20-
*/
21-
final def unlift[U >: T](using qctx: QuoteContext, unlift: Unliftable[U]): Option[U] =
22-
unlift(this)
23-
24-
/** Return the unlifted value of this expression.
25-
*
26-
* Emits an error and throws if the expression does not contain a value or contains side effects.
27-
* Otherwise returns the value.
28-
*/
29-
final def unliftOrError[U >: T](using qctx: QuoteContext, unlift: Unliftable[U]): U =
30-
unlift(this).getOrElse(report.throwError(s"Expected a known value. \n\nThe value of: $show\ncould not be unlifted using $unlift", this))
31-
3216
/** Pattern matches `this` against `that`. Effectively performing a deep equality check.
3317
* It does the equivalent of
3418
* ```
@@ -61,6 +45,27 @@ abstract class Expr[+T] private[scala] {
6145

6246
object Expr {
6347

48+
extension [T](expr: Expr[T]):
49+
/** Return the unlifted value of this expression.
50+
*
51+
* Returns `None` if the expression does not contain a value or contains side effects.
52+
* Otherwise returns the `Some` of the value.
53+
*/
54+
def unlift(using qctx: QuoteContext, unlift: Unliftable[T]): Option[T] =
55+
unlift(expr)
56+
57+
/** Return the unlifted value of this expression.
58+
*
59+
* Emits an error and throws if the expression does not contain a value or contains side effects.
60+
* Otherwise returns the value.
61+
*/
62+
def unliftOrError(using qctx: QuoteContext, unlift: Unliftable[T]): T =
63+
def reportError =
64+
val msg = s"Expected a known value. \n\nThe value of: ${expr.show}\ncould not be unlifted using $unlift"
65+
report.throwError(msg, expr)
66+
unlift(expr).getOrElse(reportError)
67+
end extension
68+
6469
/** `e.betaReduce` returns an expression that is functionally equivalent to `e`,
6570
* however if `e` is of the form `((y1, ..., yn) => e2)(x1, ..., xn)`
6671
* then it optimizes this the top most call by returning the result of beta-reducing the application.

0 commit comments

Comments
 (0)