Skip to content

Add isExpr, asExpr, asExprOf, asTerm, asTypeTree and asQuotedType #9497

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

Closed
Closed
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
14 changes: 7 additions & 7 deletions library/src-bootstrapped/dotty/internal/StringContextMacro.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ object StringContextMacro {
*/
private def interpolate(strCtxExpr: Expr[StringContext], argsExpr: Expr[Seq[Any]])(using qctx: QuoteContext): Expr[String] = {
import qctx.tasty._
val sourceFile = strCtxExpr.unseal.pos.sourceFile
val sourceFile = strCtxExpr.asTerm.pos.sourceFile

val (partsExpr, parts) = strCtxExpr match {
case Expr.StringContext(p1 @ Consts(p2)) => (p1.toList, p2.toList)
Expand All @@ -76,28 +76,28 @@ object StringContextMacro {
private[this] var oldReported = false
def partError(message : String, index : Int, offset : Int) : Unit = {
reported = true
val positionStart = partsExpr(index).unseal.pos.start + offset
val positionStart = partsExpr(index).asTerm.pos.start + offset
error(message, sourceFile, positionStart, positionStart)
}
def partWarning(message : String, index : Int, offset : Int) : Unit = {
reported = true
val positionStart = partsExpr(index).unseal.pos.start + offset
val positionStart = partsExpr(index).asTerm.pos.start + offset
warning(message, sourceFile, positionStart, positionStart)
}

def argError(message : String, index : Int) : Unit = {
reported = true
error(message, args(index).unseal.pos)
error(message, args(index).asTerm.pos)
}

def strCtxError(message : String) : Unit = {
reported = true
val positionStart = strCtxExpr.unseal.pos.start
val positionStart = strCtxExpr.asTerm.pos.start
error(message, sourceFile, positionStart, positionStart)
}
def argsError(message : String) : Unit = {
reported = true
error(message, argsExpr.unseal.pos)
error(message, argsExpr.asTerm.pos)
}

def hasReported() : Boolean = {
Expand Down Expand Up @@ -658,7 +658,7 @@ object StringContextMacro {
case Some(argIndex, arg) => {
val (hasArgumentIndex, argumentIndex, flags, hasWidth, width, hasPrecision, precision, hasRelative, relativeIndex, conversion) = getFormatSpecifiers(part, argIndex, argIndex + 1, false, formattingStart)
if (!reporter.hasReported()){
val conversionWithType = checkFormatSpecifiers(argIndex + 1, hasArgumentIndex, argumentIndex, Some(argIndex + 1), start == 0, maxArgumentIndex, hasRelative, hasWidth, width, hasPrecision, precision, flags, conversion, Some(arg.unseal.tpe), part)
val conversionWithType = checkFormatSpecifiers(argIndex + 1, hasArgumentIndex, argumentIndex, Some(argIndex + 1), start == 0, maxArgumentIndex, hasRelative, hasWidth, width, hasPrecision, precision, flags, conversion, Some(arg.asTerm.tpe), part)
nextStart = conversion + 1
conversionWithType :: checkPart(part, nextStart, argument, maxArgumentIndex)
} else checkPart(part, conversion + 1, argument, maxArgumentIndex)
Expand Down
2 changes: 1 addition & 1 deletion library/src-bootstrapped/scala/quoted/Const.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ object Const {
case Inlined(_, Nil, e) => rec(e)
case _ => None
}
rec(expr.unseal)
rec(expr.asTerm)
}

}
36 changes: 21 additions & 15 deletions library/src-bootstrapped/scala/quoted/Expr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ abstract class Expr[+T] private[scala] {

/** Show a source code like representation of this expression without syntax highlight */
def show(using qctx: QuoteContext): String =
this.unseal.showWith(SyntaxHighlight.plain)
this.asTerm.showWith(SyntaxHighlight.plain)

/** Show a source code like representation of this expression */
def showWith(syntaxHighlight: SyntaxHighlight)(using qctx: QuoteContext): String =
this.unseal.showWith(syntaxHighlight)
this.asTerm.showWith(syntaxHighlight)

/** Return the unlifted value of this expression.
*
Expand Down Expand Up @@ -41,11 +41,14 @@ abstract class Expr[+T] private[scala] {
!scala.internal.quoted.Expr.unapply[EmptyTuple, EmptyTuple](this)(using that, false, qctx).isEmpty

/** Checked cast to a `quoted.Expr[U]` */
def cast[U](using tp: scala.quoted.Type[U])(using qctx: QuoteContext): scala.quoted.Expr[U] = {
val tree = this.unseal
val expectedType = tp.unseal.tpe
def cast[U](using tp: scala.quoted.Type[U])(using qctx: QuoteContext): scala.quoted.Expr[U] = asExprOf[U]

/** Convert to an `quoted.Expr[X]` if this expression is a valid expression of type `X` or throws */
def asExprOf[X](using tp: scala.quoted.Type[X])(using qctx: QuoteContext): scala.quoted.Expr[X] = {
val tree = this.asTerm
val expectedType = tp.asTypeTree.tpe
if (tree.tpe <:< expectedType)
this.asInstanceOf[scala.quoted.Expr[U]]
this.asInstanceOf[scala.quoted.Expr[X]]
else
throw new scala.tasty.reflect.ExprCastError(
s"""Expr: ${tree.show}
Expand All @@ -55,7 +58,10 @@ abstract class Expr[+T] private[scala] {
}

/** View this expression `quoted.Expr[T]` as a `Term` */
def unseal(using qctx: QuoteContext): qctx.tasty.Term
def unseal(using qctx: QuoteContext): qctx.tasty.Term = asTerm

/** View this expression `quoted.Expr[T]` as a `Term` */
def asTerm(using qctx: QuoteContext): qctx.tasty.Term

}

Expand All @@ -67,20 +73,20 @@ object Expr {
* Otherwise returns `expr`.
*/
def betaReduce[T](expr: Expr[T])(using qctx: QuoteContext): Expr[T] =
qctx.tasty.internal.betaReduce(expr.unseal) match
case Some(expr1) => expr1.seal.asInstanceOf[Expr[T]]
qctx.tasty.internal.betaReduce(expr.asTerm) match
case Some(expr1) => expr1.asExpr.asInstanceOf[Expr[T]]
case _ => expr

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

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

/** Returns an expression containing a block with the given statements and ending with the expresion
Expand All @@ -89,7 +95,7 @@ object Expr {
*/
def block[T](statements: List[Expr[Any]], expr: Expr[T])(using qctx: QuoteContext): Expr[T] = {
import qctx.tasty._
Block(statements.map(_.unseal), expr.unseal).seal.asInstanceOf[Expr[T]]
Block(statements.map(_.asTerm), expr.asTerm).asExpr.asInstanceOf[Expr[T]]
}

/** Lift a value into an expression containing the construction of that value */
Expand Down Expand Up @@ -178,7 +184,7 @@ object Expr {
/** 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)(using qctx: QuoteContext): Expr[Tuple.InverseMap[T, Expr]] = {
val elems: Seq[Expr[Any]] = tup.asInstanceOf[Product].productIterator.toSeq.asInstanceOf[Seq[Expr[Any]]]
ofTupleFromSeq(elems).cast[Tuple.InverseMap[T, Expr]]
ofTupleFromSeq(elems).asExprOf[Tuple.InverseMap[T, Expr]]
}

/** Find an implicit of type `T` in the current scope given by `qctx`.
Expand All @@ -191,8 +197,8 @@ object Expr {
*/
def summon[T](using tpe: Type[T])(using qctx: QuoteContext): Option[Expr[T]] = {
import qctx.tasty._
searchImplicit(tpe.unseal.tpe) match {
case iss: ImplicitSearchSuccess => Some(iss.tree.seal.asInstanceOf[Expr[T]])
searchImplicit(tpe.asTypeTree.tpe) match {
case iss: ImplicitSearchSuccess => Some(iss.tree.asExpr.asInstanceOf[Expr[T]])
case isf: ImplicitSearchFailure => None
}
}
Expand Down
6 changes: 3 additions & 3 deletions library/src-bootstrapped/scala/quoted/Lambda.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ object Lambda {
*/
def unapply[F, Args <: Tuple, Res, G](expr: Expr[F])(using qctx: QuoteContext, tf: TupledFunction[F, Args => Res], tg: TupledFunction[G, Tuple.Map[Args, Expr] => Expr[Res]], functionType: Type[F]): Option[/*QuoteContext ?=>*/ G] = {
import qctx.tasty._
val argTypes = functionType.unseal.tpe match
val argTypes = functionType.asTypeTree.tpe match
case AppliedType(_, functionArguments) => functionArguments.init.asInstanceOf[List[Type]]
qctx.tasty.internal.lambdaExtractor(expr.unseal, argTypes).map { fn =>
qctx.tasty.internal.lambdaExtractor(expr.asTerm, argTypes).map { fn =>
def f(args: Tuple.Map[Args, Expr]): Expr[Res] =
fn(args.toArray.toList.map(_.asInstanceOf[Expr[Any]].unseal)).seal.asInstanceOf[Expr[Res]]
fn(args.toArray.toList.map(_.asInstanceOf[Expr[Any]].asTerm)).asExpr.asInstanceOf[Expr[Res]]
tg.untupled(f)
}

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 @@ -33,15 +33,15 @@ object Liftable {
/** Lift a primitive value `n` into `'{ n }` */
def toExpr(x: T) = qctx ?=> {
import qctx.tasty._
Literal(Constant(x)).seal.asInstanceOf[Expr[T]]
Literal(Constant(x)).asExpr.asInstanceOf[Expr[T]]
}
}

given ClassIsLiftable[T] as Liftable[Class[T]] = new Liftable[Class[T]] {
/** Lift a `Class[T]` into `'{ classOf[T] }` */
def toExpr(x: Class[T]) = qctx ?=> {
import qctx.tasty._
Ref(defn.Predef_classOf).appliedToType(Type(x)).seal.asInstanceOf[Expr[Class[T]]]
Ref(defn.Predef_classOf).appliedToType(Type(x)).asExpr.asInstanceOf[Expr[Class[T]]]
}
}

Expand Down
27 changes: 15 additions & 12 deletions library/src-bootstrapped/scala/quoted/Type.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ abstract class Type[X <: AnyKind] private[scala] {

/** Show a source code like representation of this type without syntax highlight */
def show(using qctx: QuoteContext): String =
this.unseal.showWith(SyntaxHighlight.plain)
this.asTypeTree.showWith(SyntaxHighlight.plain)

/** Show a source code like representation of this type */
def showWith(syntaxHighlight: SyntaxHighlight)(using qctx: QuoteContext): String =
this.unseal.showWith(syntaxHighlight)
this.asTypeTree.showWith(syntaxHighlight)

/** View this expression `quoted.Type[T]` as a `TypeTree` */
def unseal(using qctx: QuoteContext): qctx.tasty.TypeTree
def unseal(using qctx: QuoteContext): qctx.tasty.TypeTree = asTypeTree

/** View this expression `quoted.Type[T]` as a `qctx.tasty.TypeTree` */
def asTypeTree(using qctx: QuoteContext): qctx.tasty.TypeTree

}

Expand All @@ -28,30 +31,30 @@ object Type {
given apply[T <: AnyKind] as (QuoteContext ?=> Type[T]) = ???

def UnitTag: QuoteContext ?=> Type[Unit] =
qctx.tasty.defn.UnitType.seal.asInstanceOf[quoted.Type[Unit]]
qctx.tasty.defn.UnitType.asQuotedType.asInstanceOf[quoted.Type[Unit]]

def BooleanTag: QuoteContext ?=> Type[Boolean] =
qctx.tasty.defn.BooleanType.seal.asInstanceOf[quoted.Type[Boolean]]
qctx.tasty.defn.BooleanType.asQuotedType.asInstanceOf[quoted.Type[Boolean]]

def ByteTag: QuoteContext ?=> Type[Byte] =
qctx.tasty.defn.ByteType.seal.asInstanceOf[quoted.Type[Byte]]
qctx.tasty.defn.ByteType.asQuotedType.asInstanceOf[quoted.Type[Byte]]

def CharTag: QuoteContext ?=> Type[Char] =
qctx.tasty.defn.CharType.seal.asInstanceOf[quoted.Type[Char]]
qctx.tasty.defn.CharType.asQuotedType.asInstanceOf[quoted.Type[Char]]

def ShortTag: QuoteContext ?=> Type[Short] =
qctx.tasty.defn.ShortType.seal.asInstanceOf[quoted.Type[Short]]
qctx.tasty.defn.ShortType.asQuotedType.asInstanceOf[quoted.Type[Short]]

def IntTag: QuoteContext ?=> Type[Int] =
qctx.tasty.defn.IntType.seal.asInstanceOf[quoted.Type[Int]]
qctx.tasty.defn.IntType.asQuotedType.asInstanceOf[quoted.Type[Int]]

def LongTag: QuoteContext ?=> Type[Long] =
qctx.tasty.defn.LongType.seal.asInstanceOf[quoted.Type[Long]]
qctx.tasty.defn.LongType.asQuotedType.asInstanceOf[quoted.Type[Long]]

def FloatTag: QuoteContext ?=> Type[Float] =
qctx.tasty.defn.FloatType.seal.asInstanceOf[quoted.Type[Float]]
qctx.tasty.defn.FloatType.asQuotedType.asInstanceOf[quoted.Type[Float]]

def DoubleTag: QuoteContext ?=> Type[Double] =
qctx.tasty.defn.DoubleType.seal.asInstanceOf[quoted.Type[Double]]
qctx.tasty.defn.DoubleType.asQuotedType.asInstanceOf[quoted.Type[Double]]

}
6 changes: 3 additions & 3 deletions library/src-bootstrapped/scala/quoted/Varargs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ object Varargs {
*/
def apply[T](xs: Seq[Expr[T]])(using tp: Type[T], qctx: QuoteContext): Expr[Seq[T]] = {
import qctx.tasty._
Repeated(xs.map[Term](_.unseal).toList, tp.unseal).seal.asInstanceOf[Expr[Seq[T]]]
Repeated(xs.map[Term](_.asTerm).toList, tp.asTypeTree).asExpr.asInstanceOf[Expr[Seq[T]]]
}

/** Matches a literal sequence of expressions and return a sequence of expressions.
Expand All @@ -35,12 +35,12 @@ object Varargs {
def unapply[T](expr: Expr[Seq[T]])(using qctx: QuoteContext): Option[Seq[Expr[T]]] = {
import qctx.tasty._
def rec(tree: Term): Option[Seq[Expr[T]]] = tree match {
case Typed(Repeated(elems, _), _) => Some(elems.map(x => x.seal.asInstanceOf[Expr[T]]))
case Typed(Repeated(elems, _), _) => Some(elems.map(x => x.asExpr.asInstanceOf[Expr[T]]))
case Block(Nil, e) => rec(e)
case Inlined(_, Nil, e) => rec(e)
case _ => None
}
rec(expr.unseal)
rec(expr.asTerm)
}

}
4 changes: 2 additions & 2 deletions library/src-bootstrapped/scala/quoted/report.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ object report:

/** Report an error at the on the position of `expr` */
def error(msg: => String, expr: Expr[Any])(using qctx: QuoteContext): Unit =
qctx.tasty.error(msg, expr.unseal.pos)
qctx.tasty.error(msg, expr.asTerm.pos)

/** Report an error at the position of the macro expansion and throws a StopQuotedContext */
def throwError(msg: => String)(using qctx: QuoteContext): Nothing = {
Expand All @@ -27,7 +27,7 @@ object report:

/** Report a warning at the on the position of `expr` */
def warning(msg: => String, expr: Expr[_])(using qctx: QuoteContext): Unit =
qctx.tasty.warning(msg, expr.unseal.pos)
qctx.tasty.warning(msg, expr.asTerm.pos)

/** Throwable used to stop the expansion of a macro after an error was reported */
class StopQuotedContext extends Throwable
Expand Down
12 changes: 6 additions & 6 deletions library/src-bootstrapped/scala/quoted/unsafe/UnsafeExpr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ object UnsafeExpr {
* change the parameter semantics as by-value parameter could be re-evaluated.
*/
def underlyingArgument[T](expr: Expr[T])(using qctx: QuoteContext): Expr[T] =
expr.unseal.underlyingArgument.seal.asInstanceOf[Expr[T]]
expr.asTerm.underlyingArgument.asExpr.asInstanceOf[Expr[T]]

// TODO generalize for any function arity
/** Allows inspection or transformation of the body of the expression of function.
Expand All @@ -38,23 +38,23 @@ object UnsafeExpr {
*/
def open[T1, R, X](f: Expr[T1 => R])(content: (Expr[R], [t] => Expr[t] => Expr[T1] => Expr[t]) => X)(using qctx: QuoteContext): X = {
val (params, bodyExpr) = paramsAndBody[R](f)
content(bodyExpr, [t] => (e: Expr[t]) => (v: Expr[T1]) => bodyFn[t](e.unseal, params, List(v.unseal)).seal.asInstanceOf[Expr[t]])
content(bodyExpr, [t] => (e: Expr[t]) => (v: Expr[T1]) => bodyFn[t](e.asTerm, params, List(v.asTerm)).asExpr.asInstanceOf[Expr[t]])
}

def open[T1, T2, R, X](f: Expr[(T1, T2) => R])(content: (Expr[R], [t] => Expr[t] => (Expr[T1], Expr[T2]) => Expr[t]) => X)(using qctx: QuoteContext)(using DummyImplicit): X = {
val (params, bodyExpr) = paramsAndBody[R](f)
content(bodyExpr, [t] => (e: Expr[t]) => (v1: Expr[T1], v2: Expr[T2]) => bodyFn[t](e.unseal, params, List(v1.unseal, v2.unseal)).seal.asInstanceOf[Expr[t]])
content(bodyExpr, [t] => (e: Expr[t]) => (v1: Expr[T1], v2: Expr[T2]) => bodyFn[t](e.asTerm, params, List(v1.asTerm, v2.asTerm)).asExpr.asInstanceOf[Expr[t]])
}

def open[T1, T2, T3, R, X](f: Expr[(T1, T2, T3) => R])(content: (Expr[R], [t] => Expr[t] => (Expr[T1], Expr[T2], Expr[T3]) => Expr[t]) => X)(using qctx: QuoteContext)(using DummyImplicit, DummyImplicit): X = {
val (params, bodyExpr) = paramsAndBody[R](f)
content(bodyExpr, [t] => (e: Expr[t]) => (v1: Expr[T1], v2: Expr[T2], v3: Expr[T3]) => bodyFn[t](e.unseal, params, List(v1.unseal, v2.unseal, v3.unseal)).seal.asInstanceOf[Expr[t]])
content(bodyExpr, [t] => (e: Expr[t]) => (v1: Expr[T1], v2: Expr[T2], v3: Expr[T3]) => bodyFn[t](e.asTerm, params, List(v1.asTerm, v2.asTerm, v3.asTerm)).asExpr.asInstanceOf[Expr[t]])
}

private def paramsAndBody[R](using qctx: QuoteContext)(f: Expr[Any]): (List[qctx.tasty.ValDef], Expr[R]) = {
import qctx.tasty._
val Block(List(DefDef("$anonfun", Nil, List(params), _, Some(body))), Closure(Ident("$anonfun"), None)) = f.unseal.etaExpand
(params, body.seal.asInstanceOf[Expr[R]])
val Block(List(DefDef("$anonfun", Nil, List(params), _, Some(body))), Closure(Ident("$anonfun"), None)) = f.asTerm.etaExpand
(params, body.asExpr.asInstanceOf[Expr[R]])
}

private def bodyFn[t](using qctx: QuoteContext)(e: qctx.tasty.Term, params: List[qctx.tasty.ValDef], args: List[qctx.tasty.Term]): qctx.tasty.Term = {
Expand Down
21 changes: 9 additions & 12 deletions library/src-bootstrapped/scala/quoted/util/ExprMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ trait ExprMap {
case AppliedType(TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "<repeated>"), List(tp0: Type)) =>
// TODO rewrite without using quotes
type T
val qtp: quoted.Type[T] = tp0.seal.asInstanceOf[quoted.Type[T]]
val qtp: quoted.Type[T] = tp0.asQuotedType.asInstanceOf[quoted.Type[T]]
given qtp.type = qtp
'[Seq[T]].unseal.tpe
'[Seq[T]].asTypeTree.tpe
case tp => tp
Typed.copy(tree)(transformTerm(expr, tp), transformTypeTree(tpt))
case tree: NamedArg =>
Expand Down Expand Up @@ -107,16 +107,13 @@ trait ExprMap {
tree
case _: Inlined =>
transformTermChildren(tree, tpe)
case _ if tree.isExpr =>
type X
val expr = tree.asExpr.asInstanceOf[Expr[X]]
val t = tpe.asQuotedType.asInstanceOf[quoted.Type[X]]
transform(expr)(using qctx, t).asTerm
case _ =>
tree.tpe.widen match {
case _: MethodType | _: PolyType =>
transformTermChildren(tree, tpe)
case _ =>
type X
val expr = tree.seal.asInstanceOf[Expr[X]]
val t = tpe.seal.asInstanceOf[quoted.Type[X]]
transform(expr)(using qctx, t).unseal
}
transformTermChildren(tree, tpe)
}

def transformTypeTree(tree: TypeTree)(using ctx: Context): TypeTree = tree
Expand Down Expand Up @@ -155,7 +152,7 @@ trait ExprMap {
trees mapConserve (transformTypeCaseDef(_))

}
new MapChildren().transformTermChildren(e.unseal, tpe.unseal.tpe).seal.cast[T] // Cast will only fail if this implementation has a bug
new MapChildren().transformTermChildren(e.asTerm, tpe.asTypeTree.tpe).asExprOf[T]
}

}
Loading