Skip to content

Commit 32b6c7e

Browse files
committed
Add QuoteScope
1 parent de75713 commit 32b6c7e

39 files changed

+311
-135
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
@@ -191,6 +191,13 @@ object Splicer {
191191
ctx.error("Macro cannot be implemented with an `inline` method", fn.sourcePos)
192192
args.flatten.foreach(checkIfValidArgument)
193193

194+
case TypeApply(aio @ Select(expr, _), _) if aio.symbol == defn.Any_typeCast =>
195+
checkIfValidStaticCall(expr)
196+
197+
case Apply(Select(Apply(unsafe, _), nme.apply), List(expr))
198+
if unsafe.symbol == defn.QuotedExprModule_unsafeExpr || unsafe.symbol == defn.QuotedTypeModule_unsafeType =>
199+
checkIfValidStaticCall(expr)
200+
194201
case _ =>
195202
ctx.error(
196203
"""Malformed macro.
@@ -233,6 +240,13 @@ object Splicer {
233240
case Apply(Select(TypeApply(fn, quoted :: Nil), _), _) if fn.symbol == defn.InternalQuoted_typeQuote =>
234241
interpretTypeQuote(quoted)
235242

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

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
@@ -55,12 +55,15 @@ abstract class Expr[+T] private[scala] {
5555
}
5656

5757
/** View this expression `quoted.Expr[T]` as a `Term` */
58-
def unseal(using qctx: QuoteContext): qctx.tasty.Term
58+
def unseal(using s: QuoteScope): s.tasty.Term
5959

6060
}
6161

6262
object Expr {
6363

64+
given unsafeExpr[T](using s: QuoteScope) as Conversion[scala.quoted.Expr[T], s.Expr[T]] = _.asInstanceOf
65+
66+
6467
/** Converts a tuple `(T1, ..., Tn)` to `(Expr[T1], ..., Expr[Tn])` */
6568
type TupleOfExpr[Tup <: Tuple] = Tuple.Map[Tup, [X] =>> QuoteContext ?=> Expr[X]]
6669

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

8992
/** Returns a null expresssion equivalent to `'{null}` */
90-
def nullExpr: QuoteContext ?=> Expr[Null] = qctx ?=> {
93+
def nullExpr: (s: QuoteScope) ?=> s.Expr[Null] = {
9194
import qctx.tasty._
92-
Literal(Constant(null)).seal.asInstanceOf[Expr[Null]]
95+
Literal(Constant(null)).seal.asInstanceOf[qctx.Expr[Null]]
9396
}
9497

9598
/** Returns a unit expresssion equivalent to `'{}` or `'{()}` */
96-
def unitExpr: QuoteContext ?=> Expr[Unit] = qctx ?=> {
99+
def unitExpr: (s: QuoteScope) ?=> s.Expr[Unit] = {
97100
import qctx.tasty._
98-
Literal(Constant(())).seal.asInstanceOf[Expr[Unit]]
101+
Literal(Constant(())).seal.asInstanceOf[qctx.Expr[Unit]]
99102
}
100103

101104
/** Returns an expression containing a block with the given statements and ending with the expresion
102105
* Given list of statements `s1 :: s2 :: ... :: Nil` and an expression `e` the resulting expression
103106
* will be equivalent to `'{ $s1; $s2; ...; $e }`.
104107
*/
105-
def block[T](statements: List[Expr[Any]], expr: Expr[T])(using qctx: QuoteContext): Expr[T] = {
106-
import qctx.tasty._
107-
Block(statements.map(_.unseal), expr.unseal).seal.asInstanceOf[Expr[T]]
108+
def block[T](using s: QuoteScope)(statements: List[s.Expr[Any]], expr: s.Expr[T]): s.Expr[T] = {
109+
import s.tasty._
110+
Block(statements.map(_.unseal), expr.unseal).seal.asInstanceOf[s.Expr[T]]
108111
}
109112

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

113116
/** Lifts this sequence of expressions into an expression of a sequence
114117
*
@@ -191,9 +194,9 @@ object Expr {
191194
}
192195

193196
/** Given a tuple of the form `(Expr[A1], ..., Expr[An])`, outputs a tuple `Expr[(A1, ..., An)]`. */
194-
def ofTuple[T <: Tuple: Tuple.IsMappedBy[Expr]: Type](tup: T)(using qctx: QuoteContext): Expr[Tuple.InverseMap[T, Expr]] = {
195-
val elems: Seq[Expr[Any]] = tup.asInstanceOf[Product].productIterator.toSeq.asInstanceOf[Seq[Expr[Any]]]
196-
ofTupleFromSeq(elems).cast[Tuple.InverseMap[T, Expr]]
197+
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]] = {
198+
val elems: Seq[s.Expr[Any]] = tup.asInstanceOf[Product].productIterator.toSeq.asInstanceOf[Seq[s.Expr[Any]]]
199+
ofTupleFromSeq(elems).asInstanceOf[s.Expr[Tuple.InverseMap[T, s.Expr]]]
197200
}
198201

199202
/** Find an implicit of type `T` in the current scope given by `qctx`.
@@ -204,10 +207,10 @@ object Expr {
204207
* @param tpe quoted type of the implicit parameter
205208
* @param qctx current context
206209
*/
207-
def summon[T](using tpe: Type[T])(using qctx: QuoteContext): Option[Expr[T]] = {
208-
import qctx.tasty._
210+
def summon[T](using s: QuoteScope)(using tpe: s.Type[T]): Option[s.Expr[T]] = {
211+
import s.tasty._
209212
searchImplicit(tpe.unseal.tpe) match {
210-
case iss: ImplicitSearchSuccess => Some(iss.tree.seal.asInstanceOf[Expr[T]])
213+
case iss: ImplicitSearchSuccess => Some(iss.tree.seal.asInstanceOf[s.Expr[T]])
211214
case isf: ImplicitSearchFailure => None
212215
}
213216
}

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)