Skip to content

Rename reflect/reify and make them plain methods #5474

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 @@ -8,16 +8,16 @@ import dotty.tools.dotc.reporting.diagnostic.MessageContainer
trait QuotedOpsImpl extends scala.tasty.reflect.QuotedOps with CoreImpl {

def QuotedExprDeco[T](x: scala.quoted.Expr[T]): QuotedExprAPI = new QuotedExprAPI {
def reflect(implicit ctx: Context): Term = PickledQuotes.quotedExprToTree(x)
def unseal(implicit ctx: Context): Term = PickledQuotes.quotedExprToTree(x)
}

def QuotedTypeDeco[T](x: scala.quoted.Type[T]): QuotedTypeAPI = new QuotedTypeAPI {
def reflect(implicit ctx: Context): TypeTree = PickledQuotes.quotedTypeToTree(x)
def unseal(implicit ctx: Context): TypeTree = PickledQuotes.quotedTypeToTree(x)
}

def TermToQuoteDeco(term: Term): TermToQuotedAPI = new TermToQuotedAPI {

def reify[T: scala.quoted.Type](implicit ctx: Context): scala.quoted.Expr[T] = {
def seal[T: scala.quoted.Type](implicit ctx: Context): scala.quoted.Expr[T] = {
typecheck(ctx)
new scala.quoted.Exprs.TastyTreeExpr(term).asInstanceOf[scala.quoted.Expr[T]]
}
Expand All @@ -28,7 +28,7 @@ trait QuotedOpsImpl extends scala.tasty.reflect.QuotedOps with CoreImpl {
ctx0.typerState.setReporter(new Reporter {
def doReport(m: MessageContainer)(implicit ctx: Context): Unit = ()
})
val tp = QuotedTypeDeco(implicitly[scala.quoted.Type[T]]).reflect
val tp = QuotedTypeDeco(implicitly[scala.quoted.Type[T]]).unseal
ctx0.typer.typed(term, tp.tpe)
if (ctx0.reporter.hasErrors) {
val stack = new Exception().getStackTrace
Expand Down
15 changes: 8 additions & 7 deletions docs/docs/reference/tasty-reflect.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
---
layout: doc-page
title: "TASTy reflect"
title: "TASTy Reflect"
---

TASTy Reflect enables inspection and construction of Typed Abstract Syntax Trees (TAST).
It may be used on quoted expressions (`quoted.Expr`) and quoted types (`quoted.Type`) from [Principled Meta-programming](./principled-meta-programming.html)
or on full TASTy files.

If you are writing macros, please first read [Principled Meta-programming](./principled-meta-programming.html).
If you are writing macros, please first read [Principled Meta-programming](./principled-meta-programming.html).
You may find all you need without using TASTy Reflect.


Expand All @@ -32,13 +32,13 @@ def natConstImpl(x: Expr[Int])(implicit reflection: Reflection): Expr[Int] = {
}
```

`import reflection._` will provide a `reflect` extension method on `quoted.Expr` and `quoted.Type` which return a `reflection.Term` and `reflection.TypeTree` respectively.
`import reflection._` will provide a `unseal` extension method on `quoted.Expr` and `quoted.Type` which return a `reflection.Term` and `reflection.TypeTree` respectively.
It will also import all extractors and methods on TASTy Reflect trees. For example the `Term.Literal(_)` extractor used below.

```scala
def natConstImpl(x: Expr[Int])(implicit reflection: Reflection): Expr[Int] = {
import reflection._
val xTree: Term = x.reflect
val xTree: Term = x.unseal
xTree match {
case Term.Literal(Constant.Int(n)) =>
if (n <= 0)
Expand All @@ -53,9 +53,10 @@ def natConstImpl(x: Expr[Int])(implicit reflection: Reflection): Expr[Int] = {
To easily know which extractors are needed, the `reflection.Term.show` method returns the string representation of the extractors.

The method `reflection.Term.reify[T]` provides a way to to go back to a `quoted.Expr`.
Note that the type must be set explicitly and that if it does not conform to it an exception will be thrown.
Note that the type must be set explicitly and that if it does not conform to it an exception will be thrown.
In the code above we could have replaced `n.toExpr` by `xTree.reify[Int]`.



## Inspect a TASTy file

To inspect the TASTy Reflect trees of a TASTy file a consumer can be defined in the following way.
Expand All @@ -78,7 +79,7 @@ object Test {
}
}
```

## TASTy Reflect API

TASTy Reflect provides the following types:
Expand Down
6 changes: 3 additions & 3 deletions library/src/scala/tasty/reflect/QuotedOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ trait QuotedOps extends Core {

trait QuotedExprAPI {
/** View this expression `Expr[T]` as a `Term` */
def reflect(implicit ctx: Context): Term
def unseal(implicit ctx: Context): Term
}
implicit def QuotedExprDeco[T](expr: quoted.Expr[T]): QuotedExprAPI

trait QuotedTypeAPI {
/** View this expression `Type[T]` as a `TypeTree` */
def reflect(implicit ctx: Context): TypeTree
def unseal(implicit ctx: Context): TypeTree
}
implicit def QuotedTypeDeco[T](tpe: quoted.Type[T]): QuotedTypeAPI

trait TermToQuotedAPI {
/** Convert `Term` to an `Expr[T]` and check that it conforms to `T` */
def reify[T: scala.quoted.Type](implicit ctx: Context): scala.quoted.Expr[T]
def seal[T: scala.quoted.Type](implicit ctx: Context): scala.quoted.Expr[T]
}
implicit def TermToQuoteDeco(term: Term): TermToQuotedAPI

Expand Down
2 changes: 1 addition & 1 deletion library/src/scala/tasty/util/ConstantExtractor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ class ConstantExtractor[R <: Reflection with Singleton](val reflect: Reflection)
case Term.Inlined(_, Nil, e) => const(e)
case _ => None
}
const(expr.reflect)
const(expr.unseal)
}
}
4 changes: 2 additions & 2 deletions tests/neg/tasty-macro-assert/quoted_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ object Asserts {
def impl(cond: Expr[Boolean])(implicit reflect: Reflection): Expr[Unit] = {
import reflect._

val tree = cond.reflect
val tree = cond.unseal

def isOps(tpe: TypeOrBounds): Boolean = tpe match {
case Type.SymRef(IsDefSymbol(sym), _) => sym.name == "Ops" // TODO check that the parent is Asserts
Expand All @@ -34,7 +34,7 @@ object Asserts {

tree match {
case Term.Inlined(_, Nil, Term.Apply(Term.Select(OpsTree(left), op, _), right :: Nil)) =>
'(assertTrue(~left.reify[Boolean])) // Buggy code. To generate the errors
'(assertTrue(~left.seal[Boolean])) // Buggy code. To generate the errors
case _ =>
'(assertTrue(~cond))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ object Foo {
case IsValSymbol(sym) => sym.tree.show.toExpr
case IsBindSymbol(sym) => sym.tree.show.toExpr
}
x.reflect match {
x.unseal match {
case Term.Inlined(None, Nil, arg) => definitionString(arg)
case arg => definitionString(arg) // TODO should all by name parameters be in an inline node?
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ object Foo {
case IsValSymbol(sym) => sym.tree.show.toExpr
case IsBindSymbol(sym) => sym.tree.show.toExpr
}
x.reflect match {
x.unseal match {
case Term.Inlined(None, Nil, arg) => definitionString(arg)
case arg => definitionString(arg) // TODO should all by name parameters be in an inline node?
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ object Macros {
}
}

val tree = x.reflect
val tree = x.unseal
output.traverseTree(tree)
'(print(~buff.result().toExpr))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ object Foo {
case _ => '("NO DEFINTION")
}

x.reflect match {
x.unseal match {
case Term.Inlined(None, Nil, arg) => definitionString(arg)
case arg => definitionString(arg) // TODO should all by name parameters be in an inline node
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ object Foo {
case _ => '("NO DEFINTION")
}

x.reflect match {
x.unseal match {
case Term.Inlined(None, Nil, arg) => definitionString(arg)
case arg => definitionString(arg) // TODO should all by name parameters be in an inline node
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,31 @@ object TypeToolbox {
inline def =:=[A, B]: Boolean = ~tpEqImpl('[A], '[B])
private def tpEqImpl[A, B](a: Type[A], b: Type[B])(implicit reflect: Reflection): Expr[Boolean] = {
import reflect._
val res = a.reflect.tpe =:= b.reflect.tpe
val res = a.unseal.tpe =:= b.unseal.tpe
res.toExpr
}

/** is `tp1` a subtype of `tp2` */
inline def <:<[A, B]: Boolean = ~tpLEqImpl('[A], '[B])
private def tpLEqImpl[A, B](a: Type[A], b: Type[B])(implicit reflect: Reflection): Expr[Boolean] = {
import reflect._
val res = a.reflect.tpe <:< b.reflect.tpe
val res = a.unseal.tpe <:< b.unseal.tpe
res.toExpr
}

/** type associated with the tree */
inline def typeOf[T, Expected](a: T): Boolean = ~typeOfImpl('(a), '[Expected])
private def typeOfImpl(a: Expr[_], expected: Type[_])(implicit reflect: Reflection): Expr[Boolean] = {
import reflect._
val res = a.reflect.tpe =:= expected.reflect.tpe
val res = a.unseal.tpe =:= expected.unseal.tpe
res.toExpr
}

/** does the type refer to a case class? */
inline def isCaseClass[A]: Boolean = ~isCaseClassImpl('[A])
private def isCaseClassImpl(tp: Type[_])(implicit reflect: Reflection): Expr[Boolean] = {
import reflect._
val res = tp.reflect.symbol match {
val res = tp.unseal.symbol match {
case IsClassSymbol(sym) => sym.flags.isCase
case _ => false
}
Expand All @@ -44,66 +44,66 @@ object TypeToolbox {
inline def caseFields[T]: List[String] = ~caseFieldsImpl('[T])
private def caseFieldsImpl(tp: Type[_])(implicit reflect: Reflection): Expr[List[String]] = {
import reflect._
val fields = tp.reflect.symbol.asClass.caseFields.map(_.name)
val fields = tp.unseal.symbol.asClass.caseFields.map(_.name)
fields.toExpr
}

inline def fieldIn[T](inline mem: String): String = ~fieldInImpl('[T], mem)
private def fieldInImpl(t: Type[_], mem: String)(implicit reflect: Reflection): Expr[String] = {
import reflect._
val field = t.reflect.symbol.asClass.field(mem)
val field = t.unseal.symbol.asClass.field(mem)
field.map(_.name).getOrElse("").toExpr
}

inline def fieldsIn[T]: Seq[String] = ~fieldsInImpl('[T])
private def fieldsInImpl(t: Type[_])(implicit reflect: Reflection): Expr[Seq[String]] = {
import reflect._
val fields = t.reflect.symbol.asClass.fields
val fields = t.unseal.symbol.asClass.fields
fields.map(_.name).toList.toExpr
}

inline def methodIn[T](inline mem: String): Seq[String] = ~methodInImpl('[T], mem)
private def methodInImpl(t: Type[_], mem: String)(implicit reflect: Reflection): Expr[Seq[String]] = {
import reflect._
t.reflect.symbol.asClass.classMethod(mem).map(_.name).toExpr
t.unseal.symbol.asClass.classMethod(mem).map(_.name).toExpr
}

inline def methodsIn[T]: Seq[String] = ~methodsInImpl('[T])
private def methodsInImpl(t: Type[_])(implicit reflect: Reflection): Expr[Seq[String]] = {
import reflect._
t.reflect.symbol.asClass.classMethods.map(_.name).toExpr
t.unseal.symbol.asClass.classMethods.map(_.name).toExpr
}

inline def method[T](inline mem: String): Seq[String] = ~methodImpl('[T], mem)
private def methodImpl(t: Type[_], mem: String)(implicit reflect: Reflection): Expr[Seq[String]] = {
import reflect._
t.reflect.symbol.asClass.method(mem).map(_.name).toExpr
t.unseal.symbol.asClass.method(mem).map(_.name).toExpr
}

inline def methods[T]: Seq[String] = ~methodsImpl('[T])
private def methodsImpl(t: Type[_])(implicit reflect: Reflection): Expr[Seq[String]] = {
import reflect._
t.reflect.symbol.asClass.methods.map(_.name).toExpr
t.unseal.symbol.asClass.methods.map(_.name).toExpr
}

inline def typeTag[T](x: T): String = ~typeTagImpl('[T])
private def typeTagImpl(tp: Type[_])(implicit reflect: Reflection): Expr[String] = {
import reflect._
val res = tp.reflect.tpe.showCode
val res = tp.unseal.tpe.showCode
res.toExpr
}

inline def companion[T1, T2]: Boolean = ~companionImpl('[T1], '[T2])
private def companionImpl(t1: Type[_], t2: Type[_])(implicit reflect: Reflection): Expr[Boolean] = {
import reflect._
val res = t1.reflect.symbol.asClass.companionModule.contains(t2.reflect.symbol)
val res = t1.unseal.symbol.asClass.companionModule.contains(t2.unseal.symbol)
res.toExpr
}

inline def companionName[T1]: String = ~companionNameImpl('[T1])
private def companionNameImpl(tp: Type[_])(implicit reflect: Reflection): Expr[String] = {
import reflect._
val companionClassOpt = tp.reflect.symbol match {
val companionClassOpt = tp.unseal.symbol match {
case IsClassSymbol(sym) => sym.companionClass
case IsValSymbol(sym) => sym.companionClass
case _ => None
Expand Down
2 changes: 1 addition & 1 deletion tests/run-separate-compilation/i5119/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ object Macro {
implicit inline def XmlQuote(sc: => StringContext): StringContextOps = new StringContextOps(sc)
def impl(sc: Expr[StringContext], args: Expr[Seq[Any]])(implicit reflect: Reflection): Expr[String] = {
import reflect._
(sc.reflect.underlyingArgument.show + "\n" + args.reflect.underlyingArgument.show).toExpr
(sc.unseal.underlyingArgument.show + "\n" + args.unseal.underlyingArgument.show).toExpr
}
}
2 changes: 1 addition & 1 deletion tests/run-separate-compilation/i5119b/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ object Macro {

def impl(arg1: Expr[Any], arg2: Expr[Any])(implicit reflect: Reflection): Expr[String] = {
import reflect._
(arg1.reflect.underlyingArgument.show + "\n" + arg2.reflect.underlyingArgument.show).toExpr
(arg1.unseal.underlyingArgument.show + "\n" + arg2.unseal.underlyingArgument.show).toExpr
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ object Macros {

def impl[T](x: Expr[T])(implicit reflect: Reflection): Expr[Unit] = {
import reflect._
val tree = x.reflect
val tree = x.unseal
'{
println()
println("tree: " + ~tree.show.toExpr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ object Macros {
}
}

val tree = x.reflect
val tree = x.unseal
output.traverseTree(tree)
'(print(~buff.result().toExpr))
}
Expand Down
2 changes: 1 addition & 1 deletion tests/run-separate-compilation/tasty-eval/quoted_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ object Macros {
override def value(e: Expr[Int])(implicit reflect: Reflection): Option[Int] = {
import reflect._

e.reflect.tpe match {
e.unseal.tpe match {
case Type.SymRef(IsValSymbol(sym), pre) =>
sym.tree.tpt.tpe match {
case Type.ConstantType(Constant.Int(i)) => Some(i)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ object Macros {
def impl[T](x: Expr[T])(implicit reflect: Reflection): Expr[Unit] = {
import reflect._

val tree = x.reflect
val tree = x.unseal
val treeStr = tree.show
val treeTpeStr = tree.tpe.show

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ object Macros {
def impl[T](x: Expr[T])(implicit reflect: Reflection): Expr[Unit] = {
import reflect._

val tree = x.reflect
val tree = x.unseal

val treeStr = tree.show
val treeTpeStr = tree.tpe.show
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ object Macros {
}
}

val tree = x.reflect
val tree = x.unseal
traverser.traverseTree(tree)
'(print(~buff.result().toExpr))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ object Macros {
def impl[T](x: Type[T])(implicit reflect: Reflection): Expr[Unit] = {
import reflect._

val tree = x.reflect
val tree = x.unseal
'{
println(~tree.show.toExpr)
println(~tree.tpe.show.toExpr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ object Index {
case _ => Nil
}

val key = name(k.reflect.tpe)
val keys = name(h.reflect.tpe) :: names(t.reflect.tpe)
val key = name(k.unseal.tpe)
val keys = name(h.unseal.tpe) :: names(t.unseal.tpe)

val index = keys.indexOf(key)

Expand Down
Loading