Skip to content

Commit 77f4c68

Browse files
committed
Add QuoteScope
1 parent a8c27ee commit 77f4c68

33 files changed

+291
-120
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,8 +675,10 @@ class Definitions {
675675
@tu lazy val QuotedExprModule: Symbol = QuotedExprClass.companionModule
676676
@tu lazy val QuotedExprModule_nullExpr: Symbol = QuotedExprModule.requiredMethod(nme.nullExpr)
677677
@tu lazy val QuotedExprModule_unitExpr: Symbol = QuotedExprModule.requiredMethod(nme.unitExpr)
678+
@tu lazy val QuotedExprModule_unsafeExpr: Symbol = QuotedExprModule.requiredMethod("unsafeExpr")
678679

679680
@tu lazy val QuoteContextClass: ClassSymbol = ctx.requiredClass("scala.quoted.QuoteContext")
681+
@tu lazy val QuoteScopeClass: ClassSymbol = ctx.requiredClass("scala.quoted.QuoteScope")
680682

681683
@tu lazy val LiftableModule: Symbol = ctx.requiredModule("scala.quoted.Liftable")
682684
@tu lazy val LiftableModule_BooleanIsLiftable: Symbol = LiftableModule.requiredMethod("BooleanIsLiftable")
@@ -713,6 +715,7 @@ class Definitions {
713715
@tu lazy val QuotedType_splice: Symbol = QuotedTypeClass.requiredType(tpnme.splice)
714716

715717
@tu lazy val QuotedTypeModule: Symbol = QuotedTypeClass.companionModule
718+
@tu lazy val QuotedTypeModule_unsafeType: Symbol = QuotedTypeModule.requiredMethod("unsafeType")
716719

717720
@tu lazy val TastyReflectionClass: ClassSymbol = ctx.requiredClass("scala.tasty.Reflection")
718721

compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ class ReifyQuotes extends MacroTransform {
248248
assert(tpw.isInstanceOf[ValueType])
249249
val argTpe =
250250
if (tree.isType) defn.QuotedTypeClass.typeRef.appliedTo(tpw)
251-
else defn.FunctionType(1, isContextual = true).appliedTo(defn.QuoteContextClass.typeRef, defn.QuotedExprClass.typeRef.appliedTo(tpw))
251+
else defn.FunctionType(1, isContextual = true).appliedTo(defn.QuoteScopeClass.typeRef, defn.QuotedExprClass.typeRef.appliedTo(tpw))
252252
val selectArg = arg.select(nme.apply).appliedTo(Literal(Constant(i))).cast(argTpe)
253253
val capturedArg = SyntheticValDef(UniqueName.fresh(tree.symbol.name.toTermName).toTermName, selectArg)
254254
i += 1

compiler/src/dotty/tools/dotc/transform/Splicer.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,13 @@ object Splicer {
189189
ctx.error("Macro cannot be implemented with an `inline` method", fn.sourcePos)
190190
args.flatten.foreach(checkIfValidArgument)
191191

192+
case TypeApply(aio @ Select(expr, _), _) if aio.symbol == defn.Any_typeCast =>
193+
checkIfValidStaticCall(expr)
194+
195+
case Apply(Select(Apply(unsafe, _), nme.apply), List(expr))
196+
if unsafe.symbol == defn.QuotedExprModule_unsafeExpr || unsafe.symbol == defn.QuotedTypeModule_unsafeType =>
197+
checkIfValidStaticCall(expr)
198+
192199
case _ =>
193200
ctx.error(
194201
"""Malformed macro.
@@ -231,6 +238,13 @@ object Splicer {
231238
case Apply(Select(TypeApply(fn, quoted :: Nil), _), _) if fn.symbol == defn.InternalQuoted_typeQuote =>
232239
interpretTypeQuote(quoted)
233240

241+
case Apply(Select(Apply(unsafe, _), nme.apply), List(expr))
242+
if unsafe.symbol == defn.QuotedExprModule_unsafeExpr || unsafe.symbol == defn.QuotedTypeModule_unsafeType =>
243+
interpretTree(expr)
244+
245+
case TypeApply(aio @ Select(expr, _), _) if aio.symbol == defn.Any_typeCast =>
246+
interpretTree(expr)
247+
234248
case Literal(Constant(value)) =>
235249
interpretLiteral(value)
236250

compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ trait QuotesAndSplices {
4646
ctx.warning("Canceled splice directly inside a quote. '[ ${ XYZ } ] is equivalent to XYZ.", tree.sourcePos)
4747
case _ =>
4848
}
49-
val qctx = inferImplicitArg(defn.QuoteContextClass.typeRef, tree.span)
49+
val qctx = inferImplicitArg(defn.QuoteScopeClass.typeRef, tree.span)
5050

5151
if qctx.tpe.isInstanceOf[SearchFailureType] then
52-
ctx.error(missingArgMsg(qctx, defn.QuoteContextClass.typeRef, ""), ctx.source.atSpan(tree.span))
52+
ctx.error(missingArgMsg(qctx, defn.QuoteScopeClass.typeRef, ""), ctx.source.atSpan(tree.span))
5353
else if !qctx.tpe.isStable then
5454
ctx.error(em"Quotes require stable QuoteContext, but found non stable $qctx", qctx.sourcePos)
5555

compiler/src/dotty/tools/dotc/typer/Synthesizer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
5555
def quotedType(t: Type) =
5656
if StagingContext.level == 0 then
5757
ctx.compilationUnit.needsStaging = true // We will need to run ReifyQuotes
58-
val qctx = ctx.typer.inferImplicitArg(defn.QuoteContextClass.typeRef, span)
58+
val qctx = ctx.typer.inferImplicitArg(defn.QuoteScopeClass.typeRef, span)
5959
qctx.tpe match
6060
case tpe: Implicits.SearchFailureType => ctx.error(tpe.msg, ctx.source.atSpan(span))
6161
case _ =>

library/src-bootstrapped/scala/internal/quoted/CompileTime.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,21 @@ object CompileTime {
88

99
/** A term quote is desugared by the compiler into a call to this method */
1010
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.exprQuote`")
11-
def exprQuote[T](x: T): QuoteContext ?=> Expr[T] = ???
11+
def exprQuote[T](x: T): (s: QuoteScope) ?=> s.Expr[T] = ???
1212

1313
/** A term splice is desugared by the compiler into a call to this method */
1414
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.exprSplice`")
15-
def exprSplice[T](x: QuoteContext ?=> Expr[T]): T = ???
15+
def exprSplice[T](x: (s: QuoteScope) ?=> s.Expr[T]): T = ???
1616

1717
/** A term splice nested within a quote is desugared by the compiler into a call to this method.
18-
* `ctx` is the `QuoteContext` that the quote of this splice uses.
18+
* `ctx` is the `QuoteScope` that the quote of this splice uses.
1919
*/
2020
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.exprNestedSplice`")
21-
def exprNestedSplice[T](ctx: QuoteContext)(x: ctx.Nested ?=> Expr[T]): T = ???
21+
def exprNestedSplice[T](s0: QuoteScope)(x: (s: s0.Nested) ?=> s.Expr[T]): T = ???
2222

2323
/** A type quote is desugared by the compiler into a call to this method */
2424
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.typeQuote`")
25-
def typeQuote[T <: AnyKind]: QuoteContext ?=> Type[T] = ???
25+
def typeQuote[T <: AnyKind]: (s: QuoteScope) ?=> s.Type[T] = ???
2626

2727
/** Artifact of pickled type splices
2828
*
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package scala.internal.quoted
2+
3+
import scala.quoted.{Expr, QuoteScope, Type}
4+
5+
/** Provides methods to unpickle `Expr` and `Type` trees. */
6+
object Unpickler {
7+
8+
type PickledQuote = List[String]
9+
type PickledArgs = Seq[Seq[Any] => Any/*(([QCtx <: QuoteContext] =>> QCtx ?=> Expr[Any]) | Type[_])*/]
10+
11+
/** Unpickle `repr` which represents a pickled `Expr` tree,
12+
* replacing splice nodes with `args`
13+
*/
14+
def unpickleExpr[T](repr: PickledQuote, args: PickledArgs): (s: QuoteScope) ?=> s.Expr[T] = (using s) =>
15+
val tree = s.tasty.internal.unpickleExpr(repr, args)
16+
new scala.internal.quoted.Expr(tree, s.tasty.internal.compilerId).asInstanceOf[s.Expr[T]]
17+
18+
/** Unpickle `repr` which represents a pickled `Type` tree,
19+
* replacing splice nodes with `args`
20+
*/
21+
def unpickleType[T](repr: PickledQuote, args: PickledArgs): (s: QuoteScope) ?=> s.Type[T] = (using s) =>
22+
val tree = s.tasty.internal.unpickleType(repr, args)
23+
new scala.internal.quoted.Type(tree, s.tasty.internal.compilerId).asInstanceOf[s.Type[T]]
24+
25+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ object Const {
1414
* }
1515
* ```
1616
*/
17-
def unapply[T](expr: Expr[T])(using qctx: QuoteContext): Option[T] = {
17+
def unapply[T](using s: QuoteScope)(expr: s.Expr[T]): Option[T] = {
1818
import qctx.tasty._
1919
def rec(tree: Term): Option[T] = tree match {
2020
case Literal(c) => Some(c.value.asInstanceOf[T])

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ object Consts {
1515
* }
1616
* ```
1717
*/
18-
def unapply[T](exprs: Seq[Expr[T]])(using qctx: QuoteContext): Option[Seq[T]] =
18+
def unapply[T](using s: QuoteScope)(exprs: Seq[s.Expr[T]]): Option[Seq[T]] =
1919
exprs.foldRight(Option(List.empty[T])) { (elem, acc) =>
2020
(elem, acc) match {
2121
case (Const(value), Some(lst)) => Some(value :: lst)

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

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,16 @@ class Expr[+T] private[scala] {
4545
qctx.tasty.internal.QuotedExpr_cast[U](this)(using tp, qctx.tasty.rootContext)
4646

4747
/** View this expression `quoted.Expr[T]` as a `Term` */
48-
def unseal(using qctx: QuoteContext): qctx.tasty.Term =
48+
def unseal(using qctx: QuoteScope): qctx.tasty.Term =
4949
qctx.tasty.internal.QuotedExpr_unseal(this)(using qctx.tasty.rootContext)
5050

5151
}
5252

5353
object Expr {
5454

55+
given unsafeExpr[T](using s: QuoteScope) as Conversion[scala.quoted.Expr[T], s.Expr[T]] = _.asInstanceOf
56+
57+
5558
/** Converts a tuple `(T1, ..., Tn)` to `(Expr[T1], ..., Expr[Tn])` */
5659
type TupleOfExpr[Tup <: Tuple] = Tuple.Map[Tup, [X] =>> QuoteContext ?=> Expr[X]]
5760

@@ -78,28 +81,28 @@ object Expr {
7881
tg.untupled(args => qctx.tasty.internal.betaReduce(f.unseal, args.toArray.toList.map(_.asInstanceOf[QuoteContext => Expr[Any]](qctx).unseal)).seal.asInstanceOf[Expr[R]])
7982

8083
/** Returns a null expresssion equivalent to `'{null}` */
81-
def nullExpr: QuoteContext ?=> Expr[Null] = qctx ?=> {
84+
def nullExpr: (s: QuoteScope) ?=> s.Expr[Null] = {
8285
import qctx.tasty._
83-
Literal(Constant(null)).seal.asInstanceOf[Expr[Null]]
86+
Literal(Constant(null)).seal.asInstanceOf[qctx.Expr[Null]]
8487
}
8588

8689
/** Returns a unit expresssion equivalent to `'{}` or `'{()}` */
87-
def unitExpr: QuoteContext ?=> Expr[Unit] = qctx ?=> {
90+
def unitExpr: (s: QuoteScope) ?=> s.Expr[Unit] = {
8891
import qctx.tasty._
89-
Literal(Constant(())).seal.asInstanceOf[Expr[Unit]]
92+
Literal(Constant(())).seal.asInstanceOf[qctx.Expr[Unit]]
9093
}
9194

9295
/** Returns an expression containing a block with the given statements and ending with the expresion
9396
* Given list of statements `s1 :: s2 :: ... :: Nil` and an expression `e` the resulting expression
9497
* will be equivalent to `'{ $s1; $s2; ...; $e }`.
9598
*/
96-
def block[T](statements: List[Expr[Any]], expr: Expr[T])(using qctx: QuoteContext): Expr[T] = {
97-
import qctx.tasty._
98-
Block(statements.map(_.unseal), expr.unseal).seal.asInstanceOf[Expr[T]]
99+
def block[T](using s: QuoteScope)(statements: List[s.Expr[Any]], expr: s.Expr[T]): s.Expr[T] = {
100+
import s.tasty._
101+
Block(statements.map(_.unseal), expr.unseal).seal.asInstanceOf[s.Expr[T]]
99102
}
100103

101104
/** Lift a value into an expression containing the construction of that value */
102-
def apply[T](x: T)(using qctx: QuoteContext, lift: Liftable[T]): Expr[T] = lift.toExpr(x)
105+
def apply[T](x: T)(using s: QuoteScope, lift: Liftable[T]): s.Expr[T] = lift.toExpr(x)
103106

104107
/** Lifts this sequence of expressions into an expression of a sequence
105108
*
@@ -182,9 +185,9 @@ object Expr {
182185
}
183186

184187
/** Given a tuple of the form `(Expr[A1], ..., Expr[An])`, outputs a tuple `Expr[(A1, ..., An)]`. */
185-
def ofTuple[T <: Tuple: Tuple.IsMappedBy[Expr]: Type](tup: T)(using qctx: QuoteContext): Expr[Tuple.InverseMap[T, Expr]] = {
186-
val elems: Seq[Expr[Any]] = tup.asInstanceOf[Product].productIterator.toSeq.asInstanceOf[Seq[Expr[Any]]]
187-
ofTupleFromSeq(elems).cast[Tuple.InverseMap[T, Expr]]
188+
def ofTuple[T <: Tuple](tup: T)(using s: QuoteScope)(using s.Type[T], Tuple.IsMappedBy[s.Expr][T]): s.Expr[Tuple.InverseMap[T, s.Expr]] = {
189+
val elems: Seq[s.Expr[Any]] = tup.asInstanceOf[Product].productIterator.toSeq.asInstanceOf[Seq[s.Expr[Any]]]
190+
ofTupleFromSeq(elems).asInstanceOf[s.Expr[Tuple.InverseMap[T, s.Expr]]]
188191
}
189192

190193
/** Find an implicit of type `T` in the current scope given by `qctx`.
@@ -195,10 +198,10 @@ object Expr {
195198
* @param tpe quoted type of the implicit parameter
196199
* @param qctx current context
197200
*/
198-
def summon[T](using tpe: Type[T])(using qctx: QuoteContext): Option[Expr[T]] = {
199-
import qctx.tasty._
201+
def summon[T](using s: QuoteScope)(using tpe: s.Type[T]): Option[s.Expr[T]] = {
202+
import s.tasty._
200203
searchImplicit(tpe.unseal.tpe) match {
201-
case iss: ImplicitSearchSuccess => Some(iss.tree.seal.asInstanceOf[Expr[T]])
204+
case iss: ImplicitSearchSuccess => Some(iss.tree.seal.asInstanceOf[s.Expr[T]])
202205
case isf: ImplicitSearchFailure => None
203206
}
204207
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ object Lambda {
1515
* body('{3}) // returns '{ println(3) }
1616
* ```
1717
*/
18-
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] = {
18+
def unapply[F, Args <: Tuple, Res, G](using s: QuoteScope)(expr: s.Expr[F])(using tf: TupledFunction[F, Args => Res], tg: TupledFunction[G, Tuple.Map[Args, s.Expr] => Expr[Res]], functionType: Type[F]): Option[/*QuoteContext ?=>*/ G] = {
1919
import qctx.tasty._
2020
val argTypes = functionType.unseal.tpe match
2121
case AppliedType(_, functionArguments) => functionArguments.init.asInstanceOf[List[Type]]
2222
qctx.tasty.internal.lambdaExtractor(expr.unseal, argTypes).map { fn =>
23-
def f(args: Tuple.Map[Args, Expr]): Expr[Res] =
24-
fn(args.toArray.toList.map(_.asInstanceOf[Expr[Any]].unseal)).seal.asInstanceOf[Expr[Res]]
23+
def f(args: Tuple.Map[Args, s.Expr]): s.Expr[Res] =
24+
fn(args.toArray.toList.map(_.asInstanceOf[s.Expr[Any]].unseal)).seal.asInstanceOf[s.Expr[Res]]
2525
tg.untupled(f)
2626
}
2727

0 commit comments

Comments
 (0)