Skip to content

Commit cc15d9c

Browse files
committed
Split type/term splices and type them
1 parent a2477ea commit cc15d9c

File tree

4 files changed

+40
-18
lines changed

4 files changed

+40
-18
lines changed

compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,23 +51,23 @@ object PickledQuotes {
5151
}
5252

5353
/** Unpickle the tree contained in the TastyExpr */
54-
def unpickleTerm(pickled: String | List[String], fillHole: Int => Seq[Any] => Any)(using Context): Tree = {
54+
def unpickleTerm(pickled: String | List[String], typeHole: Int => Seq[Any] => scala.quoted.Type[?], termHole: Int => Seq[Any] => scala.quoted.QuoteContext => scala.quoted.Expr[?])(using Context): Tree = {
5555
val unpickled = withMode(Mode.ReadPositions)(unpickle(pickled, isType = false))
5656
val Inlined(call, Nil, expnasion) = unpickled
5757
val inlineCtx = inlineContext(call)
58-
val expansion1 = spliceTypes(expnasion, fillHole)(using inlineCtx)
59-
val expansion2 = spliceTerms(expansion1, fillHole)(using inlineCtx)
58+
val expansion1 = spliceTypes(expnasion, typeHole, termHole)(using inlineCtx)
59+
val expansion2 = spliceTerms(expansion1, typeHole, termHole)(using inlineCtx)
6060
cpy.Inlined(unpickled)(call, Nil, expansion2)
6161
}
6262

6363
/** Unpickle the tree contained in the TastyType */
64-
def unpickleTypeTree(pickled: String | List[String], fillHole: Int => Seq[Any] => Any)(using Context): Tree = {
64+
def unpickleTypeTree(pickled: String | List[String], typeHole: Int => Seq[Any] => scala.quoted.Type[?], termHole: Int => Seq[Any] => scala.quoted.QuoteContext => scala.quoted.Expr[?])(using Context): Tree = {
6565
val unpickled = withMode(Mode.ReadPositions)(unpickle(pickled, isType = true))
66-
spliceTypes(unpickled, fillHole)
66+
spliceTypes(unpickled, typeHole, termHole)
6767
}
6868

6969
/** Replace all term holes with the spliced terms */
70-
private def spliceTerms(tree: Tree, fillHole: Int => Seq[Any] => Any)(using Context): Tree = {
70+
private def spliceTerms(tree: Tree, typeHole: Int => Seq[Any] => scala.quoted.Type[?], termHole: Int => Seq[Any] => scala.quoted.QuoteContext => scala.quoted.Expr[?])(using Context): Tree = {
7171
val evaluateHoles = new TreeMap {
7272
override def transform(tree: tpd.Tree)(using Context): tpd.Tree = tree match {
7373
case Hole(isTerm, idx, args) =>
@@ -76,7 +76,7 @@ object PickledQuotes {
7676
else new scala.internal.quoted.Type(arg, QuoteContextImpl.scopeId)
7777
}
7878
if isTerm then
79-
val quotedExpr = fillHole(idx)(reifiedArgs).asInstanceOf[QuoteContext => scala.quoted.Expr[Any]](dotty.tools.dotc.quoted.QuoteContextImpl())
79+
val quotedExpr = termHole(idx)(reifiedArgs)(dotty.tools.dotc.quoted.QuoteContextImpl())
8080
val filled = PickledQuotes.quotedExprToTree(quotedExpr)
8181

8282
// We need to make sure a hole is created with the source file of the surrounding context, even if
@@ -86,7 +86,7 @@ object PickledQuotes {
8686
else
8787
// Replaces type holes generated by ReifyQuotes (non-spliced types).
8888
// These are types defined in a quote and used at the same level in a nested quote.
89-
val quotedType = fillHole(idx)(reifiedArgs).asInstanceOf[scala.quoted.Type[?]]
89+
val quotedType = typeHole(idx)(reifiedArgs)
9090
PickledQuotes.quotedTypeToTree(quotedType)
9191
case tree: Select =>
9292
// Retain selected members
@@ -121,15 +121,15 @@ object PickledQuotes {
121121
}
122122

123123
/** Replace all type holes generated with the spliced types */
124-
private def spliceTypes(tree: Tree, fillHole: Int => Seq[Any] => Any)(using Context): Tree = {
124+
private def spliceTypes(tree: Tree, typeHole: Int => Seq[Any] => scala.quoted.Type[?], termHole: Int => Seq[Any] => Any)(using Context): Tree = {
125125
tree match
126126
case Block(stat :: rest, expr1) if stat.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot) =>
127127
val typeSpliceMap = (stat :: rest).iterator.map {
128128
case tdef: TypeDef =>
129129
assert(tdef.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot))
130130
val tree = tdef.rhs match
131131
case TypeBoundsTree(_, Hole(_, idx, args), _) =>
132-
val quotedType = fillHole(idx)(args).asInstanceOf[scala.quoted.Type[?]]
132+
val quotedType = typeHole(idx)(args)
133133
PickledQuotes.quotedTypeToTree(quotedType)
134134
case TypeBoundsTree(_, tpt, _) =>
135135
tpt

compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2630,12 +2630,12 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, scala.intern
26302630

26312631
end reflect
26322632

2633-
def unpickleExpr[T](pickled: String | List[String], fillHole: Int => Seq[Any] => Any): scala.quoted.Expr[T] =
2634-
val tree = PickledQuotes.unpickleTerm(pickled, fillHole)(using reflect.rootContext)
2633+
def unpickleExpr[T](pickled: String | List[String], typeHole: Int => Seq[Any] => scala.quoted.Type[?], termHole: Int => Seq[Any] => scala.quoted.QuoteContext => scala.quoted.Expr[?]): scala.quoted.Expr[T] =
2634+
val tree = PickledQuotes.unpickleTerm(pickled, typeHole, termHole)(using reflect.rootContext)
26352635
new scala.internal.quoted.Expr(tree, hash).asInstanceOf[scala.quoted.Expr[T]]
26362636

2637-
def unpickleType[T <: AnyKind](pickled: String | List[String], fillHole: Int => Seq[Any] => Any): scala.quoted.Type[T] =
2638-
val tree = PickledQuotes.unpickleTypeTree(pickled, fillHole)(using reflect.rootContext)
2637+
def unpickleType[T <: AnyKind](pickled: String | List[String], typeHole: Int => Seq[Any] => scala.quoted.Type[?], termHole: Int => Seq[Any] => scala.quoted.QuoteContext => scala.quoted.Expr[?]): scala.quoted.Type[T] =
2638+
val tree = PickledQuotes.unpickleTypeTree(pickled, typeHole, termHole)(using reflect.rootContext)
26392639
new scala.internal.quoted.Type(tree, hash).asInstanceOf[scala.quoted.Type[T]]
26402640

26412641
object ExprMatch extends ExprMatchModule:

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

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,16 +204,38 @@ class ReifyQuotes extends MacroTransform {
204204
val pickledQuoteStrings = pickleQuote match
205205
case x :: Nil => Literal(Constant(x))
206206
case xs => liftList(xs.map(x => Literal(Constant(x))), defn.StringType)
207+
208+
209+
val (typeSplices, termSplices) = splices.partition { splice =>
210+
splice.tpe match
211+
case defn.FunctionOf(_, res, _, _) => res.typeSymbol == defn.QuotedTypeClass
212+
case _ => false
213+
}
214+
// TODO encode this in a more efficient way.
215+
// - Create one function that takes the index, the args, and the context directly.
216+
// - Take advantage of beta reduction to avoid the creation of the inner closures.
217+
// - Remove typeHoles/termHoles casts.
207218
val splicesList = liftList(splices, defn.FunctionType(1).appliedTo(defn.SeqType.appliedTo(defn.AnyType), defn.AnyType))
219+
val holes = SyntheticValDef("holes".toTermName, splicesList)
220+
val typeHoles = ref(holes.symbol).asInstance(
221+
defn.FunctionType(1).appliedTo(defn.IntType,
222+
defn.FunctionType(1).appliedTo(defn.SeqType.appliedTo(defn.AnyType),
223+
defn.QuotedTypeClass.typeRef.appliedTo(defn.AnyType))))
224+
val termHoles = ref(holes.symbol).asInstance(
225+
defn.FunctionType(1).appliedTo(defn.IntType,
226+
defn.FunctionType(1).appliedTo(defn.SeqType.appliedTo(defn.AnyType),
227+
defn.FunctionType(1).appliedTo(defn.QuoteContextClass.typeRef,
228+
defn.QuotedExprClass.typeRef.appliedTo(defn.AnyType)))))
229+
208230
val quoteClass = if isType then defn.QuotedTypeClass else defn.QuotedExprClass
209231
val quotedType = quoteClass.typeRef.appliedTo(originalTp)
210232
val lambdaTpe = MethodType(defn.QuoteContextClass.typeRef :: Nil, quotedType)
211233
def callUnpickle(ts: List[Tree]) = {
212234
val qctx = ts.head.asInstance(defn.QuoteContextInternalClass.typeRef)
213235
val unpickleMeth = if isType then defn.QuoteContextInternal_unpickleType else defn.QuoteContextInternal_unpickleExpr
214-
qctx.select(unpickleMeth).appliedToType(originalTp).appliedTo(pickledQuoteStrings, splicesList)
236+
qctx.select(unpickleMeth).appliedToType(originalTp).appliedTo(pickledQuoteStrings, typeHoles, termHoles)
215237
}
216-
Lambda(lambdaTpe, callUnpickle).withSpan(body.span)
238+
Block(List(holes), Lambda(lambdaTpe, callUnpickle)).withSpan(body.span)
217239
}
218240

219241
/** Encode quote using Reflection.TypeRepr.typeConstructorOf

library/src/scala/internal/quoted/QuoteContextInternal.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ trait QuoteContextInternal { self: QuoteContext =>
99
/** Unpickle `repr` which represents a pickled `Expr` tree,
1010
* replacing splice nodes with `holes`
1111
*/
12-
def unpickleExpr[T](pickled: String | List[String], fillHole: Int => Seq[Any] => Any): scala.quoted.Expr[T]
12+
def unpickleExpr[T](pickled: String | List[String], typeHole: Int => Seq[Any] => Type[?], termHole: Int => Seq[Any] => QuoteContext => Expr[?]): scala.quoted.Expr[T]
1313

1414
/** Unpickle `repr` which represents a pickled `Type` tree,
1515
* replacing splice nodes with `holes`
1616
*/
17-
def unpickleType[T <: AnyKind](pickled: String | List[String], fillHole: Int => Seq[Any] => Any): scala.quoted.Type[T]
17+
def unpickleType[T <: AnyKind](pickled: String | List[String], typeHole: Int => Seq[Any] => Type[?], termHole: Int => Seq[Any] => QuoteContext => Expr[?]): scala.quoted.Type[T]
1818

1919
val ExprMatch: ExprMatchModule
2020

0 commit comments

Comments
 (0)