Skip to content

Add Expr.asTerm #10694

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
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ object FieldsImpl:
val retType = TypeTree.of[T].tpe
def isProjectField(s: Symbol) =
s.isValDef && s.tree.asInstanceOf[ValDef].tpt.tpe <:< retType
val projectsTree = Term.of(from)
val projectsTree = from.asTerm
val symbols = TypeTree.of[V].symbol.fields.filter(isProjectField)
val selects = symbols.map(Select(projectsTree, _).asExprOf[T])
'{ println(${Expr(retType.show)}); ${Varargs(selects)} }
32 changes: 16 additions & 16 deletions compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,17 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler

extension [T](self: scala.quoted.Expr[T]):
def show: String =
reflect.Printer.TreeCode.show(reflect.Term.of(self))
reflect.Printer.TreeCode.show(reflect.asTerm(self))

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

end extension

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

/** Convert this to an `quoted.Expr[X]` if this expression is a valid expression of type `X` or throws */
def asExprOf(using scala.quoted.Type[X]): scala.quoted.Expr[X] = {
Expand All @@ -67,7 +67,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
else
throw Exception(
s"""Expr cast exception: ${self.show}
|of type: ${reflect.Printer.TypeReprCode.show(reflect.Term.of(self).tpe)}
|of type: ${reflect.Printer.TypeReprCode.show(reflect.asTerm(self).tpe)}
|did not conform to type: ${reflect.Printer.TypeReprCode.show(reflect.TypeRepr.of[X])}
|""".stripMargin
)
Expand All @@ -76,11 +76,16 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler

object reflect extends reflectModule:

extension (expr: Expr[Any]):
def asTerm: Term =
val exprImpl = expr.asInstanceOf[ExprImpl]
exprImpl.checkScopeId(QuotesImpl.this.hashCode)
exprImpl.tree
end extension

type Tree = tpd.Tree

object Tree extends TreeModule:
def of(expr: Expr[Any]): Tree = Term.of(expr)
end Tree
object Tree extends TreeModule

given TreeMethods: TreeMethods with
extension (self: Tree):
Expand Down Expand Up @@ -340,11 +345,6 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
end TermTypeTest

object Term extends TermModule:
def of(expr: Expr[Any]): Term =
val exprImpl = expr.asInstanceOf[ExprImpl]
exprImpl.checkScopeId(QuotesImpl.this.hashCode)
exprImpl.tree

def betaReduce(tree: Term): Option[Term] =
tree match
case app @ tpd.Apply(tpd.Select(fn, nme.apply), args) if dotc.core.Symbols.defn.isFunctionType(fn.tpe) =>
Expand Down Expand Up @@ -2588,7 +2588,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
dotc.report.error(msg, Position.ofMacroExpansion)

def error(msg: String, expr: Expr[Any]): Unit =
dotc.report.error(msg, Term.of(expr).pos)
dotc.report.error(msg, asTerm(expr).pos)

def error(msg: String, pos: Position): Unit =
dotc.report.error(msg, pos)
Expand All @@ -2609,7 +2609,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
dotc.report.warning(msg, Position.ofMacroExpansion)

def warning(msg: String, expr: Expr[Any]): Unit =
dotc.report.warning(msg, Term.of(expr).pos)
dotc.report.warning(msg, asTerm(expr).pos)

def warning(msg: String, pos: Position): Unit =
dotc.report.warning(msg, pos)
Expand Down Expand Up @@ -2716,8 +2716,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler

object ExprMatch extends ExprMatchModule:
def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutinee: scala.quoted.Expr[Any])(using pattern: scala.quoted.Expr[Any]): Option[Tup] =
val scrutineeTree = reflect.Term.of(scrutinee)
val patternTree = reflect.Term.of(pattern)
val scrutineeTree = reflect.asTerm(scrutinee)
val patternTree = reflect.asTerm(pattern)
treeMatch(scrutineeTree, patternTree).asInstanceOf[Option[Tup]]
end ExprMatch

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/reference/metaprogramming/tasty-reflect.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ trees. For example the `Literal(_)` extractor used below.
```scala
def natConstImpl(x: Expr[Int])(using Quotes): Expr[Int] = {
import quotes.reflect._
val xTree: Term = Term.of(x)
val xTree: Term = x.asTerm
xTree match {
case Inlined(_, _, Literal(Constant(n: Int))) =>
if (n <= 0) {
Expand Down
4 changes: 2 additions & 2 deletions library/src-bootstrapped/scala/quoted/Expr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ object Expr {
*/
def betaReduce[T](expr: Expr[T])(using Quotes): Expr[T] =
import quotes.reflect._
Term.betaReduce(Term.of(expr)) match
Term.betaReduce(expr.asTerm) match
case Some(expr1) => expr1.asExpr.asInstanceOf[Expr[T]]
case _ => expr

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

/** Creates an expression that will construct the value `x` */
Expand Down
2 changes: 1 addition & 1 deletion library/src-bootstrapped/scala/quoted/FromExpr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ object FromExpr {
case Inlined(_, Nil, e) => rec(e)
case _ => None
}
rec(Term.of(expr))
rec(expr.asTerm)
}

/** Default implementation of `FromExpr[Option]`
Expand Down
2 changes: 1 addition & 1 deletion library/src/scala/quoted/Const.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ object Const {
case Inlined(_, Nil, e) => rec(e)
case _ => None
}
rec(Term.of(expr))
rec(expr.asTerm)
}

}
6 changes: 3 additions & 3 deletions library/src/scala/quoted/ExprMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,13 @@ trait ExprMap:
transformTermChildren(tree, tpe)(owner)
case _ if tree.isExpr =>
// WARNING: Never do a cast like this in user code (accepable within the stdlib).
// In theory we should use `tree.asExpr match { case '{ $expr: t } => Term.of(transform(expr)) }`
// In theory we should use `tree.asExpr match { case '{ $expr: t } => transform(expr).asTerm }`
// This is to avoid conflicts when re-boostrapping the library.
type X
val expr = tree.asExpr.asInstanceOf[Expr[X]]
val t = tpe.asType.asInstanceOf[Type[X]]
val transformedExpr = transform(expr)(using t)
Term.of(transformedExpr)
transformedExpr.asTerm
case _ =>
transformTermChildren(tree, tpe)(owner)

Expand Down Expand Up @@ -145,7 +145,7 @@ trait ExprMap:
trees.mapConserve(x => transformTypeCaseDef(x)(owner))

}
new MapChildren().transformTermChildren(Term.of(e), TypeRepr.of[T])(Symbol.spliceOwner).asExprOf[T]
new MapChildren().transformTermChildren(e.asTerm, TypeRepr.of[T])(Symbol.spliceOwner).asExprOf[T]
}

end ExprMap
13 changes: 9 additions & 4 deletions library/src/scala/quoted/Quotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
* import scala.quoted._
* def f(expr: Expr[Int])(using Quotes) =
* import quotes.reflect._
* val tree: Tree = Term.of(expr)
* val ast: Term = expr.asTerm
* ...
* ```
*
Expand Down Expand Up @@ -201,11 +201,14 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
*/
trait reflectModule { self: reflect.type =>

/** Returns the `Term` representation this expression */
extension (expr: Expr[Any])
def asTerm: Term

///////////////
// TREES //
///////////////


/** Tree representing code written in the source */
type Tree <: AnyRef

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

/** Makes extension methods on `Tree` available without any imports */
Expand Down Expand Up @@ -509,7 +513,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
trait TermModule { this: Term.type =>

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

/** Returns a term that is functionally equivalent to `t`,
* however if `t` is of the form `((y1, ..., yn) => e2)(e1, ..., en)`
Expand Down
4 changes: 2 additions & 2 deletions library/src/scala/quoted/Varargs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ object Varargs {
*/
def apply[T](xs: Seq[Expr[T]])(using Type[T])(using Quotes): Expr[Seq[T]] = {
import quotes.reflect._
Repeated(xs.map(Term.of).toList, TypeTree.of[T]).asExpr.asInstanceOf[Expr[Seq[T]]]
Repeated(xs.map(_.asTerm).toList, TypeTree.of[T]).asExpr.asInstanceOf[Expr[Seq[T]]]
}

/** Matches a literal sequence of expressions and return a sequence of expressions.
Expand All @@ -44,7 +44,7 @@ object Varargs {
case Inlined(_, Nil, e) => rec(e)
case _ => None
}
rec(Term.of(expr))
rec(expr.asTerm)
}

}
2 changes: 1 addition & 1 deletion tests/neg-macros/i6432/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ object Macro {
sc match {
case '{ StringContext(${Varargs(parts)}: _*) } =>
for (part @ Const(s) <- parts)
report.error(s, Term.of(part).pos)
report.error(s, part.asTerm.pos)
}
'{}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-macros/i6432b/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ object Macro {
sc match {
case '{ StringContext(${Varargs(parts)}: _*) } =>
for (part @ Const(s) <- parts)
report.error(s, Term.of(part).pos)
report.error(s, part.asTerm.pos)
}
'{}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-macros/i6976/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ object macros {

def mcrImpl(body: Expr[Any])(using ctx: Quotes) : Expr[Any] = {
import ctx.reflect._
Term.of(body) match { case Block(_, _) => '{2} }
body.asTerm match { case Block(_, _) => '{2} }
}
}
2 changes: 1 addition & 1 deletion tests/neg-macros/i7698.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ trait Show[T] {

def showInterpolatorImpl(sc: Expr[StringContext], argsExpr: Expr[Seq[Any]])(using Quotes): Expr[String] =
import quotes.reflect._
Term.of(argsExpr) match
argsExpr.asTerm match
case '{ $arg: $t } => // error
case '[ Int ] => // error
???
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-macros/i9801/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ def impl(prog: Expr[Double])(using Quotes) : Expr[Double] =
triggerStackOverflow(0)
} catch {
case e =>
quotes.reflect.report.error(e.getMessage, Term.of(prog).pos)
quotes.reflect.report.error(e.getMessage, prog.asTerm.pos)
'{ 42.0 }
}
2 changes: 1 addition & 1 deletion tests/neg-macros/tasty-macro-assert-1/quoted_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ object Asserts {
def impl(cond: Expr[Boolean])(using Quotes) : Expr[Unit] = {
import quotes.reflect._

val tree = Term.of(cond)
val tree = cond.asTerm

def isOps(tpe: TypeRepr): Boolean = tpe match {
case tpe: TermRef => tpe.termSymbol.isDefDef && tpe.name == "Ops"// TODO check that the parent is Asserts
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-macros/tasty-macro-assert-2/quoted_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ object Asserts {
def impl(cond: Expr[Boolean])(using Quotes) : Expr[Unit] = {
import quotes.reflect._

val tree = Term.of(cond)
val tree = cond.asTerm

def isOps(tpe: TypeRepr): Boolean = tpe match {
case tpe: TermRef => tpe.termSymbol.isDefDef && tpe.name == "Ops"// TODO check that the parent is Asserts
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-macros/tasty-macro-error/quoted_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ object Macros {

def impl(x: Expr[Any])(using Quotes) : Expr[Unit] = {
import quotes.reflect._
report.error("here is the the argument is " + Term.of(x).underlyingArgument.show, Term.of(x).underlyingArgument.pos)
report.error("here is the the argument is " + x.asTerm.underlyingArgument.show, x.asTerm.underlyingArgument.pos)
'{}
}

Expand Down
6 changes: 3 additions & 3 deletions tests/neg-macros/tasty-macro-positions/quoted_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ object Macros {

def impl(x: Expr[Any])(using Quotes) : Expr[Unit] = {
import quotes.reflect._
val pos = Term.of(x).underlyingArgument.pos
report.error("here is the the argument is " + Term.of(x).underlyingArgument.show, pos)
report.error("here (+5) is the the argument is " + Term.of(x).underlyingArgument.show, Position(pos.sourceFile, pos.start + 5, pos.end + 5))
val pos = x.asTerm.underlyingArgument.pos
report.error("here is the the argument is " + x.asTerm.underlyingArgument.show, pos)
report.error("here (+5) is the the argument is " + x.asTerm.underlyingArgument.show, Position(pos.sourceFile, pos.start + 5, pos.end + 5))
'{}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ object FIntepolator {

def apply(strCtxExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]])(using Quotes) : Expr[String] = {
import quotes.reflect._
report.error("there are no parts", Term.of(strCtxExpr).underlyingArgument.pos)
report.error("there are no parts", strCtxExpr.asTerm.underlyingArgument.pos)
'{ ($strCtxExpr).s($argsExpr: _*) }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ object Macro {
object FIntepolator {
def apply(strCtxExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]])(using Quotes) : Expr[String] = {
import quotes.reflect._
report.error("there are no args", Term.of(argsExpr).underlyingArgument.pos)
report.error("there are no args", argsExpr.asTerm.underlyingArgument.pos)
'{ ($strCtxExpr).s($argsExpr: _*) }
}

Expand Down
4 changes: 2 additions & 2 deletions tests/neg-staging/i5941/macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ object Lens {
import util._
// obj.copy(field = value)
def setterBody(obj: Expr[S], value: Expr[T], field: String): Expr[S] =
Select.overloaded(Term.of(obj), "copy", Nil, NamedArg(field, Term.of(value)) :: Nil, TypeBounds.empty).asExprOf[S]
Select.overloaded(obj.asTerm, "copy", Nil, NamedArg(field, value.asTerm) :: Nil, TypeBounds.empty).asExprOf[S]

// exception: Term.of(getter).underlyingArgument
Term.of(getter) match {
getter.asTerm match {
case Inlined(
None, Nil,
Block(
Expand Down
2 changes: 1 addition & 1 deletion tests/pending/run/tasty-comments/quoted_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ object Macros {
def impl[T](x: Expr[T])(using Quotes) : Expr[Unit] = {
import quotes.reflect._

val tree = Term.of(x)
val tree = x.asTerm
tree.symbol.comment.map(_.raw) match {
case Some(str) => '{ println(${str}) }
case None => '{ println() }
Expand Down
4 changes: 2 additions & 2 deletions tests/pos-macros/i10151/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ object X:
case l@Literal(x) =>
l.asExpr match
case '{ $l: lit } =>
Term.of('{ CBM.pure(${term.asExprOf[lit]}) })
'{ CBM.pure(${term.asExprOf[lit]}) }.asTerm
case other =>
throw RuntimeException(s"Not supported $other")

Expand Down Expand Up @@ -89,5 +89,5 @@ object X:
}
changes.transformTerm(body)(Symbol.spliceOwner)

val r = transform(Term.of(f)).asExprOf[CB[T]]
val r = transform(f.asTerm).asExprOf[CB[T]]
r
6 changes: 3 additions & 3 deletions tests/pos-macros/i10211/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ object X:
val tb = transform(b).asExprOf[CB[Int]]
val mt = MethodType(List("p"))(_ => List(b.tpe.widen), _ => TypeRepr.of[Boolean])
val mapLambda = Lambda(Symbol.spliceOwner, mt, (_, x) => Select.overloaded(obj,"==",List(),List(x.head.asInstanceOf[Term]))).asExprOf[Int=>Boolean]
Term.of('{ CBM.map($tb)($mapLambda) })
'{ CBM.map($tb)($mapLambda) }.asTerm
case Block(stats, last) => Block(stats, transform(last))
case Inlined(x,List(),body) => transform(body)
case l@Literal(x) =>
Term.of('{ CBM.pure(${term.asExpr}) })
'{ CBM.pure(${term.asExpr}) }.asTerm
case other =>
throw RuntimeException(s"Not supported $other")

Expand Down Expand Up @@ -99,4 +99,4 @@ object X:
}
changes.transformTerm(body)(Symbol.spliceOwner)

transform(Term.of(f)).asExprOf[CB[T]]
transform(f.asTerm).asExprOf[CB[T]]
Loading