Skip to content

Commit 53f0bcc

Browse files
committed
Add Expr.asTree and Expr.asTerm
* Add `Expr.asTree` and `Expr.asTerm` under `reflect` * Deprecate `Tree.of` and `Term.of` for simpler migration from M2 to M3 This change make the intent of the operation clearer. We call `asTerm` to see the expression as a `Term` just like we call `asExpr` make the `Term` and `Expr[Any]`. It will simplify code that needs to acceess the trees. As these are extension methods, they can also be accessed explicilty using `reflect.asTerm(expr)` or `reflect.asTree(expr)` which can be useful in some situations.
1 parent c042be9 commit 53f0bcc

File tree

95 files changed

+205
-191
lines changed

Some content is hidden

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

95 files changed

+205
-191
lines changed

community-build/src/scala/dotty/communitybuild/FieldsImpl.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ object FieldsImpl:
1111
val retType = TypeTree.of[T].tpe
1212
def isProjectField(s: Symbol) =
1313
s.isValDef && s.tree.asInstanceOf[ValDef].tpt.tpe <:< retType
14-
val projectsTree = Term.of(from)
14+
val projectsTree = from.asTerm
1515
val symbols = TypeTree.of[V].symbol.memberMethods.filter(isProjectField)
1616
val selects = symbols.map(Select(projectsTree, _).asExprOf[T])
1717
'{ println(${Expr(retType.show)}); ${Varargs(selects)} }

compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,20 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
4848

4949
extension [T](self: scala.quoted.Expr[T]):
5050
def show: String =
51-
reflect.TreeMethods.show(reflect.Term.of(self))
51+
reflect.TreeMethods.show(reflect.asTerm(self))
5252

5353
def showAnsiColored: String =
54-
reflect.TreeMethods.showAnsiColored(reflect.Term.of(self))
54+
reflect.TreeMethods.showAnsiColored(reflect.asTerm(self))
5555

5656
def matches(that: scala.quoted.Expr[Any]): Boolean =
57-
treeMatch(reflect.Term.of(self), reflect.Term.of(that)).nonEmpty
57+
treeMatch(reflect.asTerm(self), reflect.asTerm(that)).nonEmpty
5858

5959
end extension
6060

6161
extension [X](self: scala.quoted.Expr[Any]):
6262
/** Checks is the `quoted.Expr[?]` is valid expression of type `X` */
6363
def isExprOf(using scala.quoted.Type[X]): Boolean =
64-
reflect.TypeReprMethods.<:<(reflect.Term.of(self).tpe)(reflect.TypeRepr.of[X])
64+
reflect.TypeReprMethods.<:<(reflect.asTerm(self).tpe)(reflect.TypeRepr.of[X])
6565

6666
/** Convert this to an `quoted.Expr[X]` if this expression is a valid expression of type `X` or throws */
6767
def asExprOf(using scala.quoted.Type[X]): scala.quoted.Expr[X] = {
@@ -70,7 +70,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
7070
else
7171
throw Exception(
7272
s"""Expr cast exception: ${self.show}
73-
|of type: ${reflect.TypeReprMethods.show(reflect.Term.of(self).tpe)}
73+
|of type: ${reflect.TypeReprMethods.show(reflect.asTerm(self).tpe)}
7474
|did not conform to type: ${reflect.TypeReprMethods.show(reflect.TypeRepr.of[X])}
7575
|""".stripMargin
7676
)
@@ -79,11 +79,17 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
7979

8080
object reflect extends reflectModule:
8181

82+
extension (expr: Expr[Any]):
83+
def asTree: Tree = expr.asTerm
84+
def asTerm: Term =
85+
val exprImpl = expr.asInstanceOf[ExprImpl]
86+
exprImpl.checkScopeId(QuotesImpl.this.hashCode)
87+
exprImpl.tree
88+
end extension
89+
8290
type Tree = tpd.Tree
8391

84-
object Tree extends TreeModule:
85-
def of(expr: Expr[Any]): Tree = Term.of(expr)
86-
end Tree
92+
object Tree extends TreeModule
8793

8894
given TreeMethods: TreeMethods with
8995
extension (self: Tree):
@@ -350,11 +356,6 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
350356
end TermTypeTest
351357

352358
object Term extends TermModule:
353-
def of(expr: Expr[Any]): Term =
354-
val exprImpl = expr.asInstanceOf[ExprImpl]
355-
exprImpl.checkScopeId(QuotesImpl.this.hashCode)
356-
exprImpl.tree
357-
358359
def betaReduce(tree: Term): Option[Term] =
359360
tree match
360361
case app @ tpd.Apply(tpd.Select(fn, nme.apply), args) if dotc.core.Symbols.defn.isFunctionType(fn.tpe) =>
@@ -2624,7 +2625,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
26242625
dotc.report.error(msg, Position.ofMacroExpansion)
26252626

26262627
def error(msg: String, expr: Expr[Any]): Unit =
2627-
dotc.report.error(msg, Term.of(expr).pos)
2628+
dotc.report.error(msg, asTerm(expr).pos)
26282629

26292630
def error(msg: String, pos: Position): Unit =
26302631
dotc.report.error(msg, pos)
@@ -2645,7 +2646,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
26452646
dotc.report.warning(msg, Position.ofMacroExpansion)
26462647

26472648
def warning(msg: String, expr: Expr[Any]): Unit =
2648-
dotc.report.warning(msg, Term.of(expr).pos)
2649+
dotc.report.warning(msg, asTerm(expr).pos)
26492650

26502651
def warning(msg: String, pos: Position): Unit =
26512652
dotc.report.warning(msg, pos)
@@ -2717,8 +2718,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
27172718

27182719
object ExprMatch extends ExprMatchModule:
27192720
def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutinee: scala.quoted.Expr[Any])(using pattern: scala.quoted.Expr[Any]): Option[Tup] =
2720-
val scrutineeTree = reflect.Term.of(scrutinee)
2721-
val patternTree = reflect.Term.of(pattern)
2721+
val scrutineeTree = reflect.asTerm(scrutinee)
2722+
val patternTree = reflect.asTerm(pattern)
27222723
treeMatch(scrutineeTree, patternTree).asInstanceOf[Option[Tup]]
27232724
end ExprMatch
27242725

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 Quotes): Expr[Int] = {
4444
import quotes.reflect._
45-
val xTree: Term = Term.of(x)
45+
val xTree: Term = x.asTerm
4646
xTree match {
4747
case Inlined(_, _, Literal(Constant(n: Int))) =>
4848
if (n <= 0) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ object Expr {
1919
*/
2020
def betaReduce[T](expr: Expr[T])(using Quotes): Expr[T] =
2121
import quotes.reflect._
22-
Term.betaReduce(Term.of(expr)) match
22+
Term.betaReduce(expr.asTerm) match
2323
case Some(expr1) => expr1.asExpr.asInstanceOf[Expr[T]]
2424
case _ => expr
2525

@@ -29,7 +29,7 @@ object Expr {
2929
*/
3030
def block[T](statements: List[Expr[Any]], expr: Expr[T])(using Quotes): Expr[T] = {
3131
import quotes.reflect._
32-
Block(statements.map(Term.of), Term.of(expr)).asExpr.asInstanceOf[Expr[T]]
32+
Block(statements.map(asTerm), expr.asTerm).asExpr.asInstanceOf[Expr[T]]
3333
}
3434

3535
/** Creates an expression that will construct the value `x` */

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ object FromExpr {
9090
case Inlined(_, Nil, e) => rec(e)
9191
case _ => None
9292
}
93-
rec(Term.of(expr))
93+
rec(expr.asTerm)
9494
}
9595

9696
/** Default implementation of `FromExpr[Option]`

library/src/scala/quoted/Const.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ object Const {
3232
case Inlined(_, Nil, e) => rec(e)
3333
case _ => None
3434
}
35-
rec(Term.of(expr))
35+
rec(expr.asTerm)
3636
}
3737

3838
}

library/src/scala/quoted/ExprMap.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,13 @@ trait ExprMap:
100100
transformTermChildren(tree, tpe)(owner)
101101
case _ if tree.isExpr =>
102102
// WARNING: Never do a cast like this in user code (accepable within the stdlib).
103-
// In theory we should use `tree.asExpr match { case '{ $expr: t } => Term.of(transform(expr)) }`
103+
// In theory we should use `tree.asExpr match { case '{ $expr: t } => transform(expr).asTerm }`
104104
// This is to avoid conflicts when re-boostrapping the library.
105105
type X
106106
val expr = tree.asExpr.asInstanceOf[Expr[X]]
107107
val t = tpe.asType.asInstanceOf[Type[X]]
108108
val transformedExpr = transform(expr)(using t)
109-
Term.of(transformedExpr)
109+
transformedExpr.asTerm
110110
case _ =>
111111
transformTermChildren(tree, tpe)(owner)
112112

@@ -145,7 +145,7 @@ trait ExprMap:
145145
trees.mapConserve(x => transformTypeCaseDef(x)(owner))
146146

147147
}
148-
new MapChildren().transformTermChildren(Term.of(e), TypeRepr.of[T])(Symbol.spliceOwner).asExprOf[T]
148+
new MapChildren().transformTermChildren(e.asTerm, TypeRepr.of[T])(Symbol.spliceOwner).asExprOf[T]
149149
}
150150

151151
end ExprMap

library/src/scala/quoted/Quotes.scala

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
7979
* import scala.quoted._
8080
* def f(expr: Expr[Int])(using Quotes) =
8181
* import quotes.reflect._
82-
* val tree: Tree = Term.of(expr)
82+
* val ast: Term = expr.asTerm // or `expr.asTree`
8383
* ...
8484
* ```
8585
*
@@ -204,11 +204,22 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
204204
*/
205205
trait reflectModule { self: reflect.type =>
206206

207+
extension (expr: Expr[Any]):
208+
209+
/** Returns the `Tree` representation this expression.
210+
* Same as `asTerm` but typed as a `Tree`.
211+
*/
212+
def asTree: Tree
213+
214+
/** Returns the `Term` representation this expression */
215+
def asTerm: Term
216+
217+
end extension
218+
207219
///////////////
208220
// TREES //
209221
///////////////
210222

211-
212223
/** Tree representing code written in the source */
213224
type Tree <: AnyRef
214225

@@ -218,7 +229,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
218229
/** Methods of the module object `val Tree` */
219230
trait TreeModule { this: Tree.type =>
220231
/** Returns the Term representation this expression */
221-
def of(expr: Expr[Any]): Tree
232+
@deprecated("Use `expr.asTree` instead (must `import quotes.reflect._`). This will be removed in 3.0.0-RC1", "3.0.0-M3")
233+
def of(expr: Expr[Any]): Tree = expr.asTree
222234
}
223235

224236
/** Makes extension methods on `Tree` available without any imports */
@@ -521,7 +533,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
521533
trait TermModule { this: Term.type =>
522534

523535
/** Returns the Term representation this expression */
524-
def of(expr: Expr[Any]): Term
536+
@deprecated("Use `expr.asTerm` instead (must `import quotes.reflect._`). This will be removed in 3.0.0-RC1", "3.0.0-M3")
537+
def of(expr: Expr[Any]): Term = expr.asTerm
525538

526539
/** Returns a term that is functionally equivalent to `t`,
527540
* however if `t` is of the form `((y1, ..., yn) => e2)(e1, ..., en)`

library/src/scala/quoted/Varargs.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ object Varargs {
2121
*/
2222
def apply[T](xs: Seq[Expr[T]])(using Type[T])(using Quotes): Expr[Seq[T]] = {
2323
import quotes.reflect._
24-
Repeated(xs.map(Term.of).toList, TypeTree.of[T]).asExpr.asInstanceOf[Expr[Seq[T]]]
24+
Repeated(xs.map(_.asTerm).toList, TypeTree.of[T]).asExpr.asInstanceOf[Expr[Seq[T]]]
2525
}
2626

2727
/** Matches a literal sequence of expressions and return a sequence of expressions.
@@ -44,7 +44,7 @@ object Varargs {
4444
case Inlined(_, Nil, e) => rec(e)
4545
case _ => None
4646
}
47-
rec(Term.of(expr))
47+
rec(expr.asTerm)
4848
}
4949

5050
}

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-
report.error(s, Term.of(part).pos)
13+
report.error(s, part.asTree.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-
report.error(s, Term.of(part).pos)
13+
report.error(s, part.asTree.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: Quotes) : Expr[Any] = {
99
import ctx.reflect._
10-
Term.of(body) match { case Block(_, _) => '{2} }
10+
body.asTree match { case Block(_, _) => '{2} }
1111
}
1212
}

tests/neg-macros/i7698.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ trait Show[T] {
66

77
def showInterpolatorImpl(sc: Expr[StringContext], argsExpr: Expr[Seq[Any]])(using Quotes): Expr[String] =
88
import quotes.reflect._
9-
Term.of(argsExpr) match
9+
argsExpr.asTree match
1010
case '{ $arg: $t } => // error
1111
case '[ Int ] => // error
1212
???

tests/neg-macros/i9801/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ def impl(prog: Expr[Double])(using Quotes) : Expr[Double] =
1616
triggerStackOverflow(0)
1717
} catch {
1818
case e =>
19-
quotes.reflect.report.error(e.getMessage, Term.of(prog).pos)
19+
quotes.reflect.report.error(e.getMessage, prog.asTree.pos)
2020
'{ 42.0 }
2121
}

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 Quotes) : Expr[Unit] = {
1616
import quotes.reflect._
1717

18-
val tree = Term.of(cond)
18+
val tree = cond.asTree
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 Quotes) : Expr[Unit] = {
1616
import quotes.reflect._
1717

18-
val tree = Term.of(cond)
18+
val tree = cond.asTree
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 Quotes) : Expr[Unit] = {
88
import quotes.reflect._
9-
report.error("here is the the argument is " + Term.of(x).underlyingArgument.show, Term.of(x).underlyingArgument.pos)
9+
report.error("here is the the argument is " + x.asTerm.underlyingArgument.show, x.asTerm.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 Quotes) : Expr[Unit] = {
88
import quotes.reflect._
9-
val pos = Term.of(x).underlyingArgument.pos
10-
report.error("here is the the argument is " + Term.of(x).underlyingArgument.show, pos)
11-
report.error("here (+5) is the the argument is " + Term.of(x).underlyingArgument.show, Position(pos.sourceFile, pos.start + 5, pos.end + 5))
9+
val pos = x.asTerm.underlyingArgument.pos
10+
report.error("here is the the argument is " + x.asTerm.underlyingArgument.show, pos)
11+
report.error("here (+5) is the the argument is " + x.asTerm.underlyingArgument.show, Position(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 Quotes) : Expr[String] = {
1313
import quotes.reflect._
14-
report.error("there are no parts", Term.of(strCtxExpr).underlyingArgument.pos)
14+
report.error("there are no parts", strCtxExpr.asTerm.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 Quotes) : Expr[String] = {
1212
import quotes.reflect._
13-
report.error("there are no args", Term.of(argsExpr).underlyingArgument.pos)
13+
report.error("there are no args", argsExpr.asTerm.underlyingArgument.pos)
1414
'{ ($strCtxExpr).s($argsExpr: _*) }
1515
}
1616

tests/neg-staging/i5941/macro_1.scala

Lines changed: 2 additions & 2 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(Term.of(obj), "copy", Nil, NamedArg(field, Term.of(value)) :: Nil, TypeBounds.empty).asExprOf[S]
20+
Select.overloaded(obj.asTerm, "copy", Nil, NamedArg(field, value.asTerm) :: Nil, TypeBounds.empty).asExprOf[S]
2121

2222
// exception: Term.of(getter).underlyingArgument
23-
Term.of(getter) match {
23+
getter.asTerm 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 Quotes) : Expr[Unit] = {
1010
import quotes.reflect._
1111

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

tests/pos-macros/i10151/Macro_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ object X:
6060
case l@Literal(x) =>
6161
l.asExpr match
6262
case '{ $l: lit } =>
63-
Term.of('{ CBM.pure(${term.asExprOf[lit]}) })
63+
'{ CBM.pure(${term.asExprOf[lit]}) }.asTerm
6464
case other =>
6565
throw RuntimeException(s"Not supported $other")
6666

@@ -89,5 +89,5 @@ object X:
8989
}
9090
changes.transformTerm(body)(Symbol.spliceOwner)
9191

92-
val r = transform(Term.of(f)).asExprOf[CB[T]]
92+
val r = transform(f.asTerm).asExprOf[CB[T]]
9393
r

0 commit comments

Comments
 (0)