Skip to content

Commit 8c3178b

Browse files
committed
Create optimized reprentation of typeHole and termHole functions
1 parent d1ba0aa commit 8c3178b

File tree

1 file changed

+53
-40
lines changed

1 file changed

+53
-40
lines changed

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

Lines changed: 53 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import dotty.tools.dotc.typer.Inliner
2828
import 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 ReifyQuotes 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 ReifyQuotes 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 ReifyQuotes 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

Comments
 (0)