@@ -28,7 +28,7 @@ import dotty.tools.dotc.typer.Inliner
2828import scala .annotation .constructorOnly
2929
3030
31- /** Translates quoted terms and types to `unpickle ` method calls.
31+ /** Translates quoted terms and types to `unpickleExpr` or `unpickleType ` method calls.
3232 *
3333 * Transforms top level quote
3434 * ```
@@ -42,23 +42,27 @@ import scala.annotation.constructorOnly
4242 * ```
4343 * to
4444 * ```
45- * unpickle (
46- * [[ // PICKLED TASTY
45+ * unpickleExpr (
46+ * pickled = [[ // PICKLED TASTY
4747 * ...
4848 * val x1 = ???
4949 * val x2 = ???
5050 * ...
51- * Hole(0 | x1, x2)
51+ * Hole(<i> | x1, x2)
5252 * ...
5353 * ]],
54- * List(
55- * (args: Seq[Any]) => {
54+ * typeHole = (idx: Int, args: List[Any]) => idx match {
55+ * case 0 => ...
56+ * },
57+ * termHole = (idx: Int, args: List[Any], qctx: QuoteContext) => idx match {
58+ * case 0 => ...
59+ * ...
60+ * case <i> =>
5661 * val x1$1 = args(0).asInstanceOf[Expr[T]]
5762 * val x2$1 = args(1).asInstanceOf[Expr[T]] // can be asInstanceOf[Type[T]]
58- * ...
63+ * ...
5964 * { ... '{ ... ${x1$1} ... ${x2$1} ...} ... }
60- * }
61- * )
65+ * },
6266 * )
6367 * ```
6468 * and then performs the same transformation on `'{ ... ${x1$1} ... ${x2$1} ...}`.
@@ -194,7 +198,9 @@ class PickleQuotes extends MacroTransform {
194198 * Generate the code
195199 * ```scala
196200 * qctx => qctx.asInstanceOf[QuoteContextInternal].<unpickleExpr|unpickleType>[<type>](
197- * <pickledQuote>
201+ * <pickledQuote>,
202+ * <typeHole>,
203+ * <termHole>,
198204 * )
199205 * ```
200206 * this closure is always applied directly to the actual context and the BetaReduce phase removes it.
@@ -205,38 +211,45 @@ class PickleQuotes extends MacroTransform {
205211 case x :: Nil => Literal (Constant (x))
206212 case xs => liftList(xs.map(x => Literal (Constant (x))), defn.StringType )
207213
208-
209- val (typeSplices, termSplices) = splices.partition { splice =>
214+ // TODO split holes earlier into types and terms. This all holes in each category can have consecutive indices
215+ val (typeSplices, termSplices) = splices.zipWithIndex. partition { case ( splice, _) =>
210216 splice.tpe match
211217 case defn.FunctionOf (_, res, _, _) => res.typeSymbol == defn.QuotedTypeClass
212- case _ => false
213218 }
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.
218- val splicesList = liftList(splices, defn.FunctionType (1 ).appliedTo(defn.SeqType .appliedTo(defn.AnyType ), defn.AnyType ))
219- val holes = SyntheticValDef (" holes" .toTermName, splicesList)
220-
221- val typeHoles = Lambda (
222- MethodType (List (defn.IntType , defn.SeqType .appliedTo(defn.AnyType )), defn.QuotedTypeClass .typeRef.appliedTo(defn.AnyType )),
223- args =>
224- ref(holes.symbol).asInstance(
225- defn.FunctionType (1 ).appliedTo(defn.IntType ,
226- defn.FunctionType (1 ).appliedTo(defn.SeqType .appliedTo(defn.AnyType ),
227- defn.QuotedTypeClass .typeRef.appliedTo(defn.AnyType ))))
228- .select(nme.apply).appliedTo(args(0 )).select(nme.apply).appliedTo(args(1 ))
229- )
230- val termHoles = Lambda (
231- MethodType (List (defn.IntType , defn.SeqType .appliedTo(defn.AnyType ), defn.QuoteContextClass .typeRef), defn.QuotedExprClass .typeRef.appliedTo(defn.AnyType )),
232- args =>
233- ref(holes.symbol).asInstance(
234- defn.FunctionType (1 ).appliedTo(defn.IntType ,
235- defn.FunctionType (1 ).appliedTo(defn.SeqType .appliedTo(defn.AnyType ),
236- defn.FunctionType (1 ).appliedTo(defn.QuoteContextClass .typeRef,
237- defn.QuotedExprClass .typeRef.appliedTo(defn.AnyType )))))
238- .select(nme.apply).appliedTo(args(0 )).select(nme.apply).appliedTo(args(1 )).select(nme.apply).appliedTo(args(2 ))
239- )
219+
220+ // This and all closures in typeSplices are removed by the BetaReduce phase
221+ val typeHoles = typeSplices match
222+ case Nil => Literal (Constant (null )) // keep pickled quote without splices as small as possible
223+ case _ =>
224+ Lambda (
225+ MethodType (
226+ List (defn.IntType , defn.SeqType .appliedTo(defn.AnyType )),
227+ defn.QuotedTypeClass .typeRef.appliedTo(WildcardType )),
228+ args => {
229+ val cases = typeSplices.map { case (splice, idx) =>
230+ CaseDef (Literal (Constant (idx)), EmptyTree , splice.select(nme.apply).appliedTo(args(1 )))
231+ }
232+ Match (args(0 ).annotated(New (ref(defn.UncheckedAnnot .typeRef))), cases)
233+ }
234+ )
235+
236+ // This and all closures in termSplices are removed by the BetaReduce phase
237+ val termHoles = termSplices match
238+ case Nil => Literal (Constant (null )) // keep pickled quote without splices as small as possible
239+ case (firstSplice, _) :: _ =>
240+ Lambda (
241+ MethodType (
242+ List (defn.IntType , defn.SeqType .appliedTo(defn.AnyType ), defn.QuoteContextClass .typeRef),
243+ defn.QuotedExprClass .typeRef.appliedTo(defn.AnyType )),
244+ args => {
245+ val cases = termSplices.map { case (splice, idx) =>
246+ val defn .FunctionOf (_, defn.FunctionOf (qctxType :: _, _, _, _), _, _) = splice.tpe
247+ val rhs = splice.select(nme.apply).appliedTo(args(1 )).select(nme.apply).appliedTo(args(2 ).asInstance(qctxType))
248+ CaseDef (Literal (Constant (idx)), EmptyTree , rhs)
249+ }
250+ Match (args(0 ).annotated(New (ref(defn.UncheckedAnnot .typeRef))), cases)
251+ }
252+ )
240253
241254 val quoteClass = if isType then defn.QuotedTypeClass else defn.QuotedExprClass
242255 val quotedType = quoteClass.typeRef.appliedTo(originalTp)
@@ -246,7 +259,7 @@ class PickleQuotes extends MacroTransform {
246259 val unpickleMeth = if isType then defn.QuoteContextInternal_unpickleType else defn.QuoteContextInternal_unpickleExpr
247260 qctx.select(unpickleMeth).appliedToType(originalTp).appliedTo(pickledQuoteStrings, typeHoles, termHoles)
248261 }
249- Block ( List (holes), Lambda (lambdaTpe, callUnpickle) ).withSpan(body.span)
262+ Lambda (lambdaTpe, callUnpickle).withSpan(body.span)
250263 }
251264
252265 /** Encode quote using Reflection.TypeRepr.typeConstructorOf
0 commit comments