Skip to content

Use extension methods in TASTy Reflect #7399

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
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
2 changes: 1 addition & 1 deletion community-build/community-projects/scalatest
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,6 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend
if (self.symbol.is(core.Flags.JavaDefined)) Nil // FIXME should also support java packages
else self.symbol.info.decls.iterator.map(definitionFromSym).toList

def PackageDef_symbol(self: PackageDef)(given Context): Symbol = self.symbol

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice simplification of the contract 👍

type ClassDef = tpd.TypeDef

def matchClassDef(tree: Tree)(given Context): Option[ClassDef] = tree match {
Expand All @@ -171,7 +169,6 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend
def ClassDef_derived(self: ClassDef)(given Context): List[TypeTree] = ClassDef_rhs(self).derived.asInstanceOf[List[TypeTree]]
def ClassDef_self(self: ClassDef)(given Context): Option[ValDef] = optional(ClassDef_rhs(self).self)
def ClassDef_body(self: ClassDef)(given Context): List[Statement] = ClassDef_rhs(self).body
def ClassDef_symbol(self: ClassDef)(given Context): Symbol = self.symbol.asClass
private def ClassDef_rhs(self: ClassDef) = self.rhs.asInstanceOf[tpd.Template]

def ClassDef_copy(original: ClassDef)(name: String, constr: DefDef, parents: List[Term | TypeTree], derived: List[TypeTree], selfOpt: Option[ValDef], body: List[Statement])(given Context): ClassDef = {
Expand All @@ -187,7 +184,6 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend
}

def TypeDef_rhs(self: TypeDef)(given Context): TypeTree | TypeBoundsTree = self.rhs
def TypeDef_symbol(self: TypeDef)(given Context): Symbol = self.symbol.asType

def TypeDef_apply(symbol: Symbol)(given Context): TypeDef = withDefaultPos(tpd.TypeDef(symbol.asType))
def TypeDef_copy(original: TypeDef)(name: String, rhs: TypeTree | TypeBoundsTree)(given Context): TypeDef =
Expand All @@ -204,7 +200,6 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend
def DefDef_paramss(self: DefDef)(given Context): List[List[ValDef]] = self.vparamss
def DefDef_returnTpt(self: DefDef)(given Context): TypeTree = self.tpt
def DefDef_rhs(self: DefDef)(given Context): Option[Tree] = optional(self.rhs)
def DefDef_symbol(self: DefDef)(given Context): Symbol = self.symbol.asTerm

def DefDef_apply(symbol: Symbol, rhsFn: List[Type] => List[List[Term]] => Option[Term])(given Context): DefDef =
withDefaultPos(tpd.polyDefDef(symbol.asTerm, tparams => vparamss => rhsFn(tparams)(vparamss).getOrElse(tpd.EmptyTree)))
Expand All @@ -221,7 +216,6 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend

def ValDef_tpt(self: ValDef)(given Context): TypeTree = self.tpt
def ValDef_rhs(self: ValDef)(given Context): Option[Tree] = optional(self.rhs)
def ValDef_symbol(self: ValDef)(given Context): Symbol = self.symbol.asTerm

def ValDef_apply(symbol: Symbol, rhs: Option[Term])(given Context): ValDef =
tpd.ValDef(symbol.asTerm, rhs.getOrElse(tpd.EmptyTree))
Expand All @@ -238,7 +232,6 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend
case _ => None
}

def Term_pos(self: Term)(given Context): Position = self.sourcePos
def Term_tpe(self: Term)(given Context): Type = self.tpe
def Term_underlyingArgument(self: Term)(given Context): Term = self.underlyingArgument
def Term_underlying(self: Term)(given Context): Term = self.underlying
Expand Down Expand Up @@ -629,7 +622,6 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend
val NameKinds.OuterSelectName(_, levels) = self.name
levels
}
def SelectOuter_tpe(self: SelectOuter)(given Context): Type = self.tpe.stripTypeVar

def SelectOuter_apply(qualifier: Term, name: String, levels: Int)(given Context): SelectOuter =
withDefaultPos(tpd.Select(qualifier, NameKinds.OuterSelectName(name.toTermName, levels)))
Expand Down Expand Up @@ -660,8 +652,6 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend
case _ => if (x.isType) Some(x) else None
}

def TypeTree_pos(self: TypeTree)(given Context): Position = self.sourcePos
def TypeTree_symbol(self: TypeTree)(given Context): Symbol = self.symbol
def TypeTree_tpe(self: TypeTree)(given Context): Type = self.tpe.stripTypeVar

type Inferred = tpd.TypeTree
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ object ReflectionImpl {
val syntaxHighlight =
if (ctx.settings.color.value == "always") SyntaxHighlight.ANSI
else SyntaxHighlight.plain
new refl.SourceCodePrinter(syntaxHighlight).showTree(reflTree)(given reflCtx)
val printers = new scala.tasty.reflect.Printers(refl)
new printers.SourceCodePrinter(syntaxHighlight).showTree(reflTree)(given reflCtx)
}
}

10 changes: 5 additions & 5 deletions docs/docs/reference/metaprogramming/tasty-reflect.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,22 @@ import scala.quoted._
inline def natConst(x: => Int): Int = ${natConstImpl('{x})}

def natConstImpl(x: Expr[Int])(given qctx: QuoteContext): Expr[Int] = {
import qctx.tasty._
import qctx.tasty.{_, given}
...
}
```

### Sealing and Unsealing

`import qctx.tasty._` will provide an `unseal` extension method on `quoted.Expr`
`import qctx.tasty.{_, given}` will provide an `unseal` extension method on `quoted.Expr`
and `quoted.Type` which returns a `qctx.tasty.Term` that represents the tree of
the expression and `qctx.tasty.TypeTree` that represents the tree of the type
respectively. It will also import all extractors and methods on TASTy Reflect
trees. For example the `Literal(_)` extractor used below.

```scala
def natConstImpl(x: Expr[Int])(given qctx: QuoteContext): Expr[Int] = {
import qctx.tasty._
import qctx.tasty.{_, given}
val xTree: Term = x.unseal
xTree match {
case Inlined(_, _, Literal(Constant(n: Int))) =>
Expand Down Expand Up @@ -81,7 +81,7 @@ operation expression passed while calling the `macro` below.
inline def macro(param: => Boolean): Unit = ${ macroImpl('param) }

def macroImpl(param: Expr[Boolean])(given qctx: QuoteContext): Expr[Unit] = {
import qctx.tasty._
import qctx.tasty.{_, given}
import util._

param.unseal.underlyingArgument match {
Expand All @@ -103,7 +103,7 @@ point.

```scala
def macroImpl()(qctx: QuoteContext): Expr[Unit] = {
import qctx.tasty._
import qctx.tasty.{_, given}
val pos = rootPosition

val path = pos.sourceFile.jpath.toString
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ object StringContextMacro {
* quotes an error if the given Expr does not contain a list of arguments
*/
def getArgsExprs(argsExpr: Expr[Seq[Any]])(given qctx: QuoteContext): Option[List[Expr[Any]]] = {
import qctx.tasty._
import qctx.tasty.{_, given}
argsExpr.unseal.underlyingArgument match {
case Typed(Repeated(args, _), _) =>
Some(args.map(_.seal))
Expand All @@ -99,7 +99,7 @@ object StringContextMacro {
* @return the Expr containing the formatted and interpolated String or an error/warning if the parameters are not correct
*/
private def interpolate(strCtxExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]])(given qctx: QuoteContext): Expr[String] = {
import qctx.tasty._
import qctx.tasty.{_, given}
val sourceFile = strCtxExpr.unseal.pos.sourceFile

val (partsExpr, parts) = getPartsExprs(strCtxExpr) match {
Expand Down Expand Up @@ -165,7 +165,7 @@ object StringContextMacro {
* @return the Expr containing the formatted and interpolated String or an error/warning report if the parameters are not correct
*/
def interpolate(parts0 : List[String], args : List[Expr[Any]], argsExpr: Expr[Seq[Any]], reporter : Reporter)(given qctx: QuoteContext) : Expr[String] = {
import qctx.tasty._
import qctx.tasty.{_, given}

/** Checks if the number of arguments are the same as the number of formatting strings
*
Expand Down
4 changes: 2 additions & 2 deletions library/src-bootstrapped/scala/quoted/Liftable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ object Liftable {
private class PrimitiveLiftable[T <: Unit | Null | Int | Boolean | Byte | Short | Int | Long | Float | Double | Char | String] extends Liftable[T] {
/** Lift a primitive value `n` into `'{ n }` */
def toExpr(x: T) = (given qctx) => {
import qctx.tasty._
import qctx.tasty.{_, given}
Literal(Constant(x)).seal.asInstanceOf[Expr[T]]
}
}

given ClassIsLiftable[T] : Liftable[Class[T]] = new Liftable[Class[T]] {
/** Lift a `Class[T]` into `'{ classOf[T] }` */
def toExpr(x: Class[T]) = (given qctx) => {
import qctx.tasty._
import qctx.tasty.{_, given}
Ref(defn.Predef_classOf).appliedToType(Type(x)).seal.asInstanceOf[Expr[Class[T]]]
}
}
Expand Down
2 changes: 1 addition & 1 deletion library/src/scala/internal/quoted/Expr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ object Expr {
*/
def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutineeExpr: Expr[_])(implicit patternExpr: Expr[_],
hasTypeSplices: Boolean, qctx: QuoteContext): Option[Tup] = {
import qctx.tasty._
import qctx.tasty.{_, given}
new Matcher.QuoteMatcher[qctx.type].termMatch(scrutineeExpr.unseal, patternExpr.unseal, hasTypeSplices).asInstanceOf[Option[Tup]]
}

Expand Down
2 changes: 1 addition & 1 deletion library/src/scala/internal/quoted/Matcher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ private[quoted] object Matcher {

private final val debug = false

import qctx.tasty._
import qctx.tasty.{_, given}
import Matching._

private type Env = Set[(Symbol, Symbol)]
Expand Down
2 changes: 1 addition & 1 deletion library/src/scala/internal/quoted/Type.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ object Type {
*/
def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutineeType: Type[_])(implicit patternType: Type[_],
hasTypeSplices: Boolean, qctx: QuoteContext): Option[Tup] = {
import qctx.tasty._
import qctx.tasty.{_, given}
new Matcher.QuoteMatcher[qctx.type].typeTreeMatch(scrutineeType.unseal, patternType.unseal, hasTypeSplices).asInstanceOf[Option[Tup]]
}

Expand Down
16 changes: 8 additions & 8 deletions library/src/scala/quoted/Expr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ package quoted {
* ```
*/
def betaReduce[F, Args <: Tuple, R, G](f: Expr[F])(given tf: TupledFunction[F, Args => R], tg: TupledFunction[G, TupleOfExpr[Args] => Expr[R]], qctx: QuoteContext): G = {
import qctx.tasty._
import qctx.tasty.{_, given}
tg.untupled(args => qctx.tasty.internal.betaReduce(f.unseal, args.toArray.toList.map(_.asInstanceOf[QuoteContext => Expr[_]](qctx).unseal)).seal.asInstanceOf[Expr[R]])
}

Expand All @@ -51,19 +51,19 @@ package quoted {
* Note: The
*/
def betaReduceGiven[F, Args <: Tuple, R, G](f: Expr[F])(given tf: TupledFunction[F, (given Args) => R], tg: TupledFunction[G, TupleOfExpr[Args] => Expr[R]], qctx: QuoteContext): G = {
import qctx.tasty._
import qctx.tasty.{_, given}
tg.untupled(args => qctx.tasty.internal.betaReduce(f.unseal, args.toArray.toList.map(_.asInstanceOf[QuoteContext => Expr[_]](qctx).unseal)).seal.asInstanceOf[Expr[R]])
}

/** Returns a null expresssion equivalent to `'{null}` */
def nullExpr: (given QuoteContext) => Expr[Null] = (given qctx) => {
import qctx.tasty._
import qctx.tasty.{_, given}
Literal(Constant(null)).seal.asInstanceOf[Expr[Null]]
}

/** Returns a unit expresssion equivalent to `'{}` or `'{()}` */
def unitExpr: (given QuoteContext) => Expr[Unit] = (given qctx) => {
import qctx.tasty._
import qctx.tasty.{_, given}
Literal(Constant(())).seal.asInstanceOf[Expr[Unit]]
}

Expand All @@ -72,7 +72,7 @@ package quoted {
* will be equivalent to `'{ $s1; $s2; ...; $e }`.
*/
def block[T](statements: List[Expr[_]], expr: Expr[T])(given qctx: QuoteContext): Expr[T] = {
import qctx.tasty._
import qctx.tasty.{_, given}
Block(statements.map(_.unseal), expr.unseal).seal.asInstanceOf[Expr[T]]
}

Expand All @@ -92,7 +92,7 @@ package quoted {
* ```
*/
def ofSeq[T](xs: Seq[Expr[T]])(given tp: Type[T], qctx: QuoteContext): Expr[Seq[T]] = {
import qctx.tasty._
import qctx.tasty.{_, given}
Repeated(xs.map(_.unseal).toList, tp.unseal).seal.asInstanceOf[Expr[Seq[T]]]
}

Expand Down Expand Up @@ -168,8 +168,8 @@ package quoted {
}

/** Given a tuple of the form `(Expr[A1], ..., Expr[An])`, outputs a tuple `Expr[(A1, ..., An)]`. */
def ofTuple[T <: Tuple: Tuple.IsMappedBy[Expr]: Type](tup: T) (given ctx: QuoteContext): Expr[Tuple.InverseMap[T, Expr]] = {
import ctx.tasty._
def ofTuple[T <: Tuple: Tuple.IsMappedBy[Expr]: Type](tup: T) (given qctx: QuoteContext): Expr[Tuple.InverseMap[T, Expr]] = {
import qctx.tasty.{_, given}
val elems: Seq[Expr[_]] = tup.asInstanceOf[Product].productIterator.toSeq.asInstanceOf[Seq[Expr[_]]]
ofTuple(elems).cast[Tuple.InverseMap[T, Expr]]
}
Expand Down
14 changes: 7 additions & 7 deletions library/src/scala/quoted/QuoteContext.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,41 @@ import scala.quoted.show.SyntaxHighlight
* It contains the low-level Typed AST API `tasty` meta-programming API.
* This API does not have the static type guarantiees that `Expr` and `Type` provide.
*
* @param tasty Typed AST API. Usage: `def f(qctx: QuoteContext) = { import qctx.tasty._; ... }`.
* @param tasty Typed AST API. Usage: `def f(qctx: QuoteContext) = { import qctx.tasty.{_, given}; ... }`.
*/
class QuoteContext(val tasty: scala.tasty.Reflection) {

def show(expr: Expr[_], syntaxHighlight: SyntaxHighlight): String = {
import tasty._
import tasty.{_, given}
expr.unseal.show(syntaxHighlight)
}

def show(tpe: Type[_], syntaxHighlight: SyntaxHighlight): String = {
import tasty._
import tasty.{_, given}
tpe.unseal.show(syntaxHighlight)
}

/** Report an error */
def error(msg: => String): Unit = {
import tasty._
import tasty.{_, given}
tasty.error(msg, rootPosition)(given rootContext)
}

/** Report an error at the on the position of `expr` */
def error(msg: => String, expr: Expr[_]): Unit = {
import tasty._
import tasty.{_, given}
tasty.error(msg, expr.unseal.pos)(given rootContext)
}

/** Report a warning */
def warning(msg: => String): Unit = {
import tasty._
import tasty.{_, given}
tasty.warning(msg, rootPosition)(given rootContext)
}

/** Report a warning at the on the position of `expr` */
def warning(msg: => String, expr: Expr[_]): Unit = {
import tasty._
import tasty.{_, given}
tasty.warning(msg, expr.unseal.pos)(given rootContext)
}

Expand Down
18 changes: 9 additions & 9 deletions library/src/scala/quoted/Type.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,47 +18,47 @@ package quoted {
object Type {

given UnitTag(given qctx: QuoteContext): Type[Unit] = {
import qctx.tasty._
import qctx.tasty.{_, given}
defn.UnitType.seal.asInstanceOf[quoted.Type[Unit]]
}

given BooleanTag(given qctx: QuoteContext): Type[Boolean] = {
import qctx.tasty._
import qctx.tasty.{_, given}
defn.BooleanType.seal.asInstanceOf[quoted.Type[Boolean]]
}

given ByteTag(given qctx: QuoteContext): Type[Byte] = {
import qctx.tasty._
import qctx.tasty.{_, given}
defn.ByteType.seal.asInstanceOf[quoted.Type[Byte]]
}

given CharTag(given qctx: QuoteContext): Type[Char] = {
import qctx.tasty._
import qctx.tasty.{_, given}
defn.CharType.seal.asInstanceOf[quoted.Type[Char]]
}

given ShortTag(given qctx: QuoteContext): Type[Short] = {
import qctx.tasty._
import qctx.tasty.{_, given}
defn.ShortType.seal.asInstanceOf[quoted.Type[Short]]
}

given IntTag(given qctx: QuoteContext): Type[Int] = {
import qctx.tasty._
import qctx.tasty.{_, given}
defn.IntType.seal.asInstanceOf[quoted.Type[Int]]
}

given LongTag(given qctx: QuoteContext): Type[Long] = {
import qctx.tasty._
import qctx.tasty.{_, given}
defn.LongType.seal.asInstanceOf[quoted.Type[Long]]
}

given FloatTag(given qctx: QuoteContext): Type[Float] = {
import qctx.tasty._
import qctx.tasty.{_, given}
defn.FloatType.seal.asInstanceOf[quoted.Type[Float]]
}

given DoubleTag(given qctx: QuoteContext): Type[Double] = {
import qctx.tasty._
import qctx.tasty.{_, given}
defn.DoubleType.seal.asInstanceOf[quoted.Type[Double]]
}

Expand Down
2 changes: 1 addition & 1 deletion library/src/scala/quoted/matching/Const.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ package matching
object Const {

def unapply[T](expr: Expr[T])(given qctx: QuoteContext): Option[T] = {
import qctx.tasty._
import qctx.tasty.{_, given}
def rec(tree: Term): Option[T] = tree match {
case Literal(c) => Some(c.value.asInstanceOf[T])
case Block(Nil, e) => rec(e)
Expand Down
2 changes: 1 addition & 1 deletion library/src/scala/quoted/matching/ExprSeq.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ object ExprSeq {

/** Matches a literal sequence of expressions */
def unapply[T](expr: Expr[Seq[T]])(given qctx: QuoteContext): Option[Seq[Expr[T]]] = {
import qctx.tasty._
import qctx.tasty.{_, given}
def rec(tree: Term): Option[Seq[Expr[T]]] = tree match {
case Typed(Repeated(elems, _), _) => Some(elems.map(x => x.seal.asInstanceOf[Expr[T]]))
case Block(Nil, e) => rec(e)
Expand Down
Loading