Skip to content

Commit 3e90f1e

Browse files
committed
Add Tree.of and Term.of to transform Expr into Tree
This is replacement for `Expr.asReflectTree` (which replaced `unseal`). This version of the API aligns with `Type.of`, `TypeRepr.of` and `TypeTree.of`. By requiring the `Tree` or `Term` modules to do the transformation we can ensure that all uses of the reflection API have the `qctx.reflect` import or explicit path. This delimits in a clearer way where the reflect API is used.
1 parent 88541a3 commit 3e90f1e

File tree

92 files changed

+207
-179
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+207
-179
lines changed

compiler/src/scala/quoted/internal/impl/QuoteContextImpl.scala

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,25 +47,20 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, QuoteUnpickl
4747

4848
extension [T](self: scala.quoted.Expr[T]):
4949
def show: String =
50-
reflect.TreeMethodsImpl.show(self.asReflectTree)
50+
reflect.TreeMethodsImpl.show(reflect.Term.of(self))
5151

5252
def showAnsiColored: String =
53-
reflect.TreeMethodsImpl.showAnsiColored(self.asReflectTree)
53+
reflect.TreeMethodsImpl.showAnsiColored(reflect.Term.of(self))
5454

5555
def matches(that: scala.quoted.Expr[Any]): Boolean =
56-
treeMatch(self.asReflectTree, that.asReflectTree).nonEmpty
57-
58-
def asReflectTree: reflect.Term =
59-
val expr = self.asInstanceOf[ExprImpl]
60-
expr.checkScopeId(QuoteContextImpl.this.hashCode)
61-
expr.tree
56+
treeMatch(reflect.Term.of(self), reflect.Term.of(that)).nonEmpty
6257

6358
end extension
6459

6560
extension [X](self: scala.quoted.Expr[Any]):
6661
/** Checks is the `quoted.Expr[?]` is valid expression of type `X` */
6762
def isExprOf(using scala.quoted.Type[X]): Boolean =
68-
reflect.TypeReprMethodsImpl.<:<(self.asReflectTree.tpe)(reflect.TypeRepr.of[X])
63+
reflect.TypeReprMethodsImpl.<:<(reflect.Term.of(self).tpe)(reflect.TypeRepr.of[X])
6964

7065
/** Convert this to an `quoted.Expr[X]` if this expression is a valid expression of type `X` or throws */
7166
def asExprOf(using scala.quoted.Type[X]): scala.quoted.Expr[X] = {
@@ -74,7 +69,7 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, QuoteUnpickl
7469
else
7570
throw Exception(
7671
s"""Expr cast exception: ${self.show}
77-
|of type: ${reflect.TypeReprMethodsImpl.show(self.asReflectTree.tpe)}
72+
|of type: ${reflect.TypeReprMethodsImpl.show(reflect.Term.of(self).tpe)}
7873
|did not conform to type: ${reflect.TypeReprMethodsImpl.show(reflect.TypeRepr.of[X])}
7974
|""".stripMargin
8075
)
@@ -89,7 +84,9 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, QuoteUnpickl
8984

9085
type Tree = tpd.Tree
9186

92-
object Tree extends TreeModule
87+
object Tree extends TreeModule:
88+
def of(expr: Expr[Any]): Tree = Term.of(expr)
89+
end Tree
9390

9491
object TreeMethodsImpl extends TreeMethods:
9592
extension (self: Tree):
@@ -328,6 +325,11 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, QuoteUnpickl
328325
end TermTypeTest
329326

330327
object Term extends TermModule:
328+
def of(expr: Expr[Any]): Term =
329+
val exprImpl = expr.asInstanceOf[ExprImpl]
330+
exprImpl.checkScopeId(QuoteContextImpl.this.hashCode)
331+
exprImpl.tree
332+
331333
def betaReduce(tree: Term): Option[Term] =
332334
tree match
333335
case app @ tpd.Apply(tpd.Select(fn, nme.apply), args) if dotc.core.Symbols.defn.isFunctionType(fn.tpe) =>
@@ -2551,8 +2553,8 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, QuoteUnpickl
25512553

25522554
object ExprMatch extends ExprMatchModule:
25532555
def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutinee: scala.quoted.Expr[Any])(using pattern: scala.quoted.Expr[Any]): Option[Tup] =
2554-
val scrutineeTree = QuoteContextImpl.this.asReflectTree(scrutinee)
2555-
val patternTree = QuoteContextImpl.this.asReflectTree(pattern)
2556+
val scrutineeTree = reflect.Term.of(scrutinee)
2557+
val patternTree = reflect.Term.of(pattern)
25562558
treeMatch(scrutineeTree, patternTree).asInstanceOf[Option[Tup]]
25572559
end ExprMatch
25582560

docs/docs/reference/metaprogramming/tasty-reflect.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ trees. For example the `Literal(_)` extractor used below.
4242
```scala
4343
def natConstImpl(x: Expr[Int])(using qctx: QuoteContext): Expr[Int] = {
4444
import qctx.reflect._
45-
val xTree: Term = x.unseal
45+
val xTree: Term = Term.of(x)
4646
xTree match {
4747
case Inlined(_, _, Literal(Constant(n: Int))) =>
4848
if (n <= 0) {

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ object Expr {
1414
* Some bindings may be elided as an early optimization.
1515
*/
1616
def betaReduce[T](expr: Expr[T])(using qctx: QuoteContext): Expr[T] =
17-
qctx.reflect.Term.betaReduce(expr.unseal) match
17+
import qctx.reflect._
18+
Term.betaReduce(Term.of(expr)) match
1819
case Some(expr1) => expr1.asExpr.asInstanceOf[Expr[T]]
1920
case _ => expr
2021

@@ -24,7 +25,7 @@ object Expr {
2425
*/
2526
def block[T](statements: List[Expr[Any]], expr: Expr[T])(using qctx: QuoteContext): Expr[T] = {
2627
import qctx.reflect._
27-
Block(statements.map(_.unseal), expr.unseal).asExpr.asInstanceOf[Expr[T]]
28+
Block(statements.map(Term.of), Term.of(expr)).asExpr.asInstanceOf[Expr[T]]
2829
}
2930

3031
/** Lift a value into an expression containing the construction of that value */

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ trait ExprMap:
104104
type X
105105
val expr = tree.asExpr.asInstanceOf[Expr[X]]
106106
val t = tpe.asType.asInstanceOf[Type[X]]
107-
transform(expr)(using qctx, t).unseal
107+
val transformedExpr = transform(expr)(using qctx, t)
108+
Term.of(transformedExpr)
108109
case _ =>
109110
transformTermChildren(tree, tpe)
110111

@@ -144,7 +145,7 @@ trait ExprMap:
144145
trees mapConserve (transformTypeCaseDef(_))
145146

146147
}
147-
new MapChildren().transformTermChildren(e.unseal, TypeRepr.of[T]).asExprOf[T]
148+
new MapChildren().transformTermChildren(Term.of(e), TypeRepr.of[T]).asExprOf[T]
148149
}
149150

150151
end ExprMap

library/src/scala/quoted/Const.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ object Const {
2323
case Inlined(_, Nil, e) => rec(e)
2424
case _ => None
2525
}
26-
rec(expr.unseal)
26+
rec(Term.of(expr))
2727
}
2828

2929
}

library/src/scala/quoted/QuoteContext.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,13 @@ trait QuoteContext { self: internal.QuoteUnpickler & internal.QuoteMatching =>
4848
unlift.fromExpr(self)(using QuoteContext.this).getOrElse(reportError)
4949

5050
/** View this expression `quoted.Expr[T]` as a `Term` */
51+
@deprecated("Use reflect.Term.of", "")
5152
def unseal: reflect.Term = self.asReflectTree // TODO remove
5253

5354
/** View this expression `quoted.Expr[T]` as a `Term` */
54-
def asReflectTree: reflect.Term
55+
@deprecated("Use reflect.Term.of", "")
56+
def asReflectTree: reflect.Term = // TODO remove
57+
reflect.Term.of(self)
5558
end extension
5659

5760
// Extension methods for `Expr[Any]` that take another explicit type parameter

library/src/scala/quoted/Reflection.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,10 @@ trait Reflection { reflection =>
129129

130130
val Tree: TreeModule
131131

132-
trait TreeModule { this: Tree.type => }
132+
trait TreeModule { this: Tree.type =>
133+
/** Returns the Term representation this expression */
134+
def of(expr: Expr[Any]): Tree
135+
}
133136

134137
given TreeMethods as TreeMethods = TreeMethodsImpl
135138
protected val TreeMethodsImpl: TreeMethods
@@ -372,6 +375,9 @@ trait Reflection { reflection =>
372375

373376
trait TermModule { this: Term.type =>
374377

378+
/** Returns the Term representation this expression */
379+
def of(expr: Expr[Any]): Term
380+
375381
/** Returns a term that is functionally equivalent to `t`,
376382
* however if `t` is of the form `((y1, ..., yn) => e2)(e1, ..., en)`
377383
* then it optimizes this the top most call by returning the `Some`

library/src/scala/quoted/Varargs.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ object Varargs {
1717
*/
1818
def apply[T](xs: Seq[Expr[T]])(using tp: Type[T], qctx: QuoteContext): Expr[Seq[T]] = {
1919
import qctx.reflect._
20-
Repeated(xs.map[Term](_.unseal).toList, TypeTree.of[T]).asExpr.asInstanceOf[Expr[Seq[T]]]
20+
Repeated(xs.map(Term.of).toList, TypeTree.of[T]).asExpr.asInstanceOf[Expr[Seq[T]]]
2121
}
2222

2323
/** Matches a literal sequence of expressions and return a sequence of expressions.
@@ -40,7 +40,7 @@ object Varargs {
4040
case Inlined(_, Nil, e) => rec(e)
4141
case _ => None
4242
}
43-
rec(expr.unseal)
43+
rec(Term.of(expr))
4444
}
4545

4646
}

library/src/scala/quoted/report.scala

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ object report:
44

55
/** Report an error at the position of the macro expansion */
66
def error(msg: => String)(using qctx: QuoteContext): Unit =
7-
qctx.reflect.Reporting.error(msg, qctx.reflect.Position.ofMacroExpansion)
7+
import qctx.reflect._
8+
Reporting.error(msg, Position.ofMacroExpansion)
89

910
/** Report an error at the on the position of `expr` */
1011
def error(msg: => String, expr: Expr[Any])(using qctx: QuoteContext): Unit =
11-
qctx.reflect.Reporting.error(msg, expr.unseal.pos)
12+
import qctx.reflect._
13+
Reporting.error(msg, Term.of(expr).pos)
1214

1315
/** Report an error at the position of the macro expansion and throws a StopQuotedContext */
1416
def throwError(msg: => String)(using qctx: QuoteContext): Nothing = {
@@ -23,11 +25,13 @@ object report:
2325

2426
/** Report a warning */
2527
def warning(msg: => String)(using qctx: QuoteContext): Unit =
26-
qctx.reflect.Reporting.warning(msg, qctx.reflect.Position.ofMacroExpansion)
28+
import qctx.reflect._
29+
Reporting.warning(msg, Position.ofMacroExpansion)
2730

2831
/** Report a warning at the on the position of `expr` */
29-
def warning(msg: => String, expr: Expr[_])(using qctx: QuoteContext): Unit =
30-
qctx.reflect.Reporting.warning(msg, expr.unseal.pos)
32+
def warning(msg: => String, expr: Expr[Any])(using qctx: QuoteContext): Unit =
33+
import qctx.reflect._
34+
Reporting.warning(msg, Term.of(expr).pos)
3135

3236
/** Throwable used to stop the expansion of a macro after an error was reported */
3337
class StopQuotedContext extends Throwable

tests/neg-macros/i6432/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ object Macro {
1010
sc match {
1111
case '{ StringContext(${Varargs(parts)}: _*) } =>
1212
for (part @ Const(s) <- parts)
13-
Reporting.error(s, part.unseal.pos)
13+
Reporting.error(s, Term.of(part).pos)
1414
}
1515
'{}
1616
}

tests/neg-macros/i6432b/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ object Macro {
1010
sc match {
1111
case '{ StringContext(${Varargs(parts)}: _*) } =>
1212
for (part @ Const(s) <- parts)
13-
Reporting.error(s, part.unseal.pos)
13+
Reporting.error(s, Term.of(part).pos)
1414
}
1515
'{}
1616
}

tests/neg-macros/i6976/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ object macros {
77

88
def mcrImpl(body: Expr[Any])(using ctx: QuoteContext) : Expr[Any] = {
99
import ctx.reflect._
10-
body.unseal match { case Block(_, _) => '{2} }
10+
Term.of(body) match { case Block(_, _) => '{2} }
1111
}
1212
}

tests/neg-macros/i7698.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ trait Show[T] {
55
}
66

77
def showInterpolatorImpl(sc: Expr[StringContext], argsExpr: Expr[Seq[Any]])(using qctx: QuoteContext): Expr[String] =
8-
argsExpr.unseal match
8+
import qctx.reflect._
9+
Term.of(argsExpr) match
910
case '{ $arg: $t } => // error
1011
case '[ Int ] => // error
1112
???

tests/neg-macros/i9801/Macro_1.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ def triggerStackOverflow(n: Int): Expr[Double] = {
1111
inline def loop(inline prog: Double): Double = ${impl('prog)}
1212

1313
def impl(prog: Expr[Double])(using QuoteContext) : Expr[Double] =
14+
import qctx.reflect._
1415
try {
1516
triggerStackOverflow(0)
1617
} catch {
1718
case e =>
18-
qctx.reflect.Reporting.error(e.getMessage, prog.unseal.pos)
19+
qctx.reflect.Reporting.error(e.getMessage, Term.of(prog).pos)
1920
'{ 42.0 }
2021
}

tests/neg-macros/tasty-macro-assert-1/quoted_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ object Asserts {
1515
def impl(cond: Expr[Boolean])(using qctx: QuoteContext) : Expr[Unit] = {
1616
import qctx.reflect._
1717

18-
val tree = cond.unseal
18+
val tree = Term.of(cond)
1919

2020
def isOps(tpe: TypeRepr): Boolean = tpe match {
2121
case tpe: TermRef => tpe.termSymbol.isDefDef && tpe.name == "Ops"// TODO check that the parent is Asserts

tests/neg-macros/tasty-macro-assert-2/quoted_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ object Asserts {
1515
def impl(cond: Expr[Boolean])(using qctx: QuoteContext) : Expr[Unit] = {
1616
import qctx.reflect._
1717

18-
val tree = cond.unseal
18+
val tree = Term.of(cond)
1919

2020
def isOps(tpe: TypeRepr): Boolean = tpe match {
2121
case tpe: TermRef => tpe.termSymbol.isDefDef && tpe.name == "Ops"// TODO check that the parent is Asserts

tests/neg-macros/tasty-macro-error/quoted_1.scala

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

77
def impl(x: Expr[Any])(using qctx: QuoteContext) : Expr[Unit] = {
88
import qctx.reflect._
9-
Reporting.error("here is the the argument is " + x.unseal.underlyingArgument.show, x.unseal.underlyingArgument.pos)
9+
Reporting.error("here is the the argument is " + Term.of(x).underlyingArgument.show, Term.of(x).underlyingArgument.pos)
1010
'{}
1111
}
1212

tests/neg-macros/tasty-macro-positions/quoted_1.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ object Macros {
66

77
def impl(x: Expr[Any])(using qctx: QuoteContext) : Expr[Unit] = {
88
import qctx.reflect._
9-
val pos = x.unseal.underlyingArgument.pos
10-
Reporting.error("here is the the argument is " + x.unseal.underlyingArgument.show, pos)
11-
Reporting.error("here (+5) is the the argument is " + x.unseal.underlyingArgument.show, pos.sourceFile, pos.start + 5, pos.end + 5)
9+
val pos = Term.of(x).underlyingArgument.pos
10+
Reporting.error("here is the the argument is " + Term.of(x).underlyingArgument.show, pos)
11+
Reporting.error("here (+5) is the the argument is " + Term.of(x).underlyingArgument.show, pos.sourceFile, pos.start + 5, pos.end + 5)
1212
'{}
1313
}
1414

tests/neg-macros/tasty-string-interpolator-position-a/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ object FIntepolator {
1111

1212
def apply(strCtxExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]])(using qctx: QuoteContext) : Expr[String] = {
1313
import qctx.reflect._
14-
Reporting.error("there are no parts", strCtxExpr.unseal.underlyingArgument.pos)
14+
Reporting.error("there are no parts", Term.of(strCtxExpr).underlyingArgument.pos)
1515
'{ ($strCtxExpr).s($argsExpr: _*) }
1616
}
1717

tests/neg-macros/tasty-string-interpolator-position-b/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ object Macro {
1010
object FIntepolator {
1111
def apply(strCtxExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]])(using qctx: QuoteContext) : Expr[String] = {
1212
import qctx.reflect._
13-
Reporting.error("there are no args", argsExpr.unseal.underlyingArgument.pos)
13+
Reporting.error("there are no args", Term.of(argsExpr).underlyingArgument.pos)
1414
'{ ($strCtxExpr).s($argsExpr: _*) }
1515
}
1616

tests/neg-staging/i5941/macro_1.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ object Lens {
1717
import util._
1818
// obj.copy(field = value)
1919
def setterBody(obj: Expr[S], value: Expr[T], field: String): Expr[S] =
20-
Select.overloaded(obj.unseal, "copy", Nil, NamedArg(field, value.unseal) :: Nil, TypeBounds.empty).asExprOf[S]
20+
Select.overloaded(Term.of(obj), "copy", Nil, NamedArg(field, Term.of(value)) :: Nil, TypeBounds.empty).asExprOf[S]
2121

22-
// exception: getter.unseal.underlyingArgument
23-
getter.unseal match {
22+
// exception: Term.of(getter).underlyingArgument
23+
Term.of(getter) match {
2424
case Inlined(
2525
None, Nil,
2626
Block(

tests/pending/run/tasty-comments/quoted_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ object Macros {
99
def impl[T](x: Expr[T])(using qctx: QuoteContext) : Expr[Unit] = {
1010
import qctx.reflect._
1111

12-
val tree = x.unseal
12+
val tree = Term.of(x)
1313
tree.symbol.comment.map(_.raw) match {
1414
case Some(str) => '{ println(${str}) }
1515
case None => '{ println() }

tests/pos-macros/i6171/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ object scalatest {
66

77
def assertImpl(x: Expr[Any])(using qctx: QuoteContext) : Expr[Unit] = {
88
import qctx.reflect._
9-
x.unseal.underlyingArgument
9+
Term.of(x).underlyingArgument
1010
'{ () }
1111
}
1212
}

tests/pos-macros/i6535/Macro_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ object scalatest {
99
import util._
1010
import ValDef.let
1111

12-
cond.unseal.underlyingArgument match {
12+
Term.of(cond).underlyingArgument match {
1313
case t @ Apply(Select(lhs, op), rhs :: Nil) =>
1414
let(lhs) { left =>
1515
let(rhs) { right =>
@@ -19,7 +19,7 @@ object scalatest {
1919
val r = right.asExpr
2020
val b = result.asExprOf[Boolean]
2121
val code = '{ scala.Predef.assert($b) }
22-
code.unseal
22+
Term.of(code)
2323
}
2424
}
2525
}.asExprOf[Unit]

tests/pos-macros/i7011/Macros_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ inline def mcr(body: => Any): Unit = ${mcrImpl('body)}
55
def mcrImpl[T](body: Expr[Any])(using QuoteContext) : Expr[Any] = {
66
import qctx.reflect._
77

8-
val bTree = body.unseal
8+
val bTree = Term.of(body)
99
val under = bTree.underlyingArgument
1010

1111
val res = '{Box(${under.asInstanceOf[Term].asExpr})}

tests/pos-macros/i7030/Macros_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ def innerImpl(exprs: Expr[Any])(using QuoteContext): Expr[Any] =
77
inline def outer(expr: => Any): Any = ${outerImpl('expr)}
88
def outerImpl(body: Expr[Any])(using QuoteContext): Expr[Any] = {
99
import qctx.reflect._
10-
body.unseal.underlyingArgument.asExpr
10+
Term.of(body).underlyingArgument.asExpr
1111
}

tests/pos-macros/i8325/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ object A:
1313

1414
def transformImplExpr[A:Type](using qctx: QuoteContext)(expr: Expr[A]): Expr[A] = {
1515
import qctx.reflect._
16-
expr.unseal match {
16+
Term.of(expr) match {
1717
case Inlined(x,y,z) => transformImplExpr(z.asExpr.asInstanceOf[Expr[A]])
1818
case Apply(fun,args) => '{ A.pure(${Apply(fun,args).asExpr.asInstanceOf[Expr[A]]}) }
1919
case other => expr

0 commit comments

Comments
 (0)