@@ -28,7 +28,7 @@ import dotty.tools.dotc.typer.Inliner
28
28
import scala .annotation .constructorOnly
29
29
30
30
31
- /** Translates quoted terms and types to `unpickle ` method calls.
31
+ /** Translates quoted terms and types to `unpickleExpr` or `unpickleType ` method calls.
32
32
*
33
33
* Transforms top level quote
34
34
* ```
@@ -42,23 +42,27 @@ import scala.annotation.constructorOnly
42
42
* ```
43
43
* to
44
44
* ```
45
- * unpickle (
46
- * [[ // PICKLED TASTY
45
+ * unpickleExpr (
46
+ * pickled = [[ // PICKLED TASTY
47
47
* ...
48
48
* val x1 = ???
49
49
* val x2 = ???
50
50
* ...
51
- * Hole(0 | x1, x2)
51
+ * Hole(<i> | x1, x2)
52
52
* ...
53
53
* ]],
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> =>
56
61
* val x1$1 = args(0).asInstanceOf[Expr[T]]
57
62
* val x2$1 = args(1).asInstanceOf[Expr[T]] // can be asInstanceOf[Type[T]]
58
- * ...
63
+ * ...
59
64
* { ... '{ ... ${x1$1} ... ${x2$1} ...} ... }
60
- * }
61
- * )
65
+ * },
62
66
* )
63
67
* ```
64
68
* and then performs the same transformation on `'{ ... ${x1$1} ... ${x2$1} ...}`.
@@ -194,7 +198,9 @@ class ReifyQuotes extends MacroTransform {
194
198
* Generate the code
195
199
* ```scala
196
200
* qctx => qctx.asInstanceOf[QuoteContextInternal].<unpickleExpr|unpickleType>[<type>](
197
- * <pickledQuote>
201
+ * <pickledQuote>,
202
+ * <typeHole>,
203
+ * <termHole>,
198
204
* )
199
205
* ```
200
206
* this closure is always applied directly to the actual context and the BetaReduce phase removes it.
@@ -205,38 +211,45 @@ class ReifyQuotes extends MacroTransform {
205
211
case x :: Nil => Literal (Constant (x))
206
212
case xs => liftList(xs.map(x => Literal (Constant (x))), defn.StringType )
207
213
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, _) =>
210
216
splice.tpe match
211
217
case defn.FunctionOf (_, res, _, _) => res.typeSymbol == defn.QuotedTypeClass
212
- case _ => false
213
218
}
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
+ )
240
253
241
254
val quoteClass = if isType then defn.QuotedTypeClass else defn.QuotedExprClass
242
255
val quotedType = quoteClass.typeRef.appliedTo(originalTp)
@@ -246,7 +259,7 @@ class ReifyQuotes extends MacroTransform {
246
259
val unpickleMeth = if isType then defn.QuoteContextInternal_unpickleType else defn.QuoteContextInternal_unpickleExpr
247
260
qctx.select(unpickleMeth).appliedToType(originalTp).appliedTo(pickledQuoteStrings, typeHoles, termHoles)
248
261
}
249
- Block ( List (holes), Lambda (lambdaTpe, callUnpickle) ).withSpan(body.span)
262
+ Lambda (lambdaTpe, callUnpickle).withSpan(body.span)
250
263
}
251
264
252
265
/** Encode quote using Reflection.TypeRepr.typeConstructorOf
0 commit comments