Skip to content

Commit 9923e29

Browse files
Avoid retraversing parts of the tree that do not contain Quote trees (#17407)
Also, remove an illegal use of `WildcardType`.
2 parents d7c0cb0 + b7cc753 commit 9923e29

File tree

1 file changed

+22
-28
lines changed

1 file changed

+22
-28
lines changed

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

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ import scala.annotation.constructorOnly
3333
* val x1: U1 = ???
3434
* val x2: U2 = ???
3535
* ...
36-
* {{{ 3 | x1 | contents0 | T0 }}} // hole
36+
* {{{ 3 | x1 | holeContents0 | T0 }}} // hole
3737
* ...
38-
* {{{ 4 | x2 | contents1 | T1 }}} // hole
38+
* {{{ 4 | x2 | holeContents1 | T1 }}} // hole
3939
* ...
40-
* {{{ 5 | x1, x2 | contents2 | T2 }}} // hole
40+
* {{{ 5 | x1, x2 | holeContents2 | T2 }}} // hole
4141
* ...
4242
* }
4343
* ```
@@ -59,9 +59,9 @@ import scala.annotation.constructorOnly
5959
* ]],
6060
* typeHole = Seq(a, b),
6161
* termHole = (idx: Int, args: List[Any], quotes: Quotes) => idx match {
62-
* case 3 => content0.apply(args(0).asInstanceOf[Expr[U1]]).apply(quotes) // beta reduced
63-
* case 4 => content1.apply(args(0).asInstanceOf[Expr[U2]]).apply(quotes) // beta reduced
64-
* case 5 => content2.apply(args(0).asInstanceOf[Expr[U1]], args(1).asInstanceOf[Expr[U2]]).apply(quotes) // beta reduced
62+
* case 3 => holeContents0.apply(args(0).asInstanceOf[Expr[U1]]).apply(quotes) // beta reduced
63+
* case 4 => holeContents1.apply(args(0).asInstanceOf[Expr[U2]]).apply(quotes) // beta reduced
64+
* case 5 => holeContents2.apply(args(0).asInstanceOf[Expr[U1]], args(1).asInstanceOf[Expr[U2]]).apply(quotes) // beta reduced
6565
* },
6666
* )
6767
* ```
@@ -93,26 +93,25 @@ class PickleQuotes extends MacroTransform {
9393
override def transform(tree: tpd.Tree)(using Context): tpd.Tree =
9494
tree match
9595
case Apply(Select(quote: Quote, nme.apply), List(quotes)) =>
96-
val (contents, quote1) = makeHoles(quote)
96+
val (holeContents, quote1) = extractHolesContents(quote)
9797
val quote2 = encodeTypeArgs(quote1)
98-
val contents1 = contents ::: quote.tags
99-
val pickled = PickleQuotes.pickle(quote2, quotes, contents1)
100-
transform(pickled) // pickle quotes that are in the contents
98+
val holeContents1 = holeContents.map(transform(_))
99+
PickleQuotes.pickle(quote2, quotes, holeContents1)
101100
case tree: DefDef if !tree.rhs.isEmpty && tree.symbol.isInlineMethod =>
102101
tree
103102
case _ =>
104103
super.transform(tree)
105104
}
106105

107-
private def makeHoles(quote: tpd.Quote)(using Context): (List[Tree], tpd.Quote) =
106+
private def extractHolesContents(quote: tpd.Quote)(using Context): (List[Tree], tpd.Quote) =
108107
class HoleContentExtractor extends Transformer:
109-
private val contents = List.newBuilder[Tree]
108+
private val holeContents = List.newBuilder[Tree]
110109
override def transform(tree: tpd.Tree)(using Context): tpd.Tree =
111110
tree match
112111
case tree @ Hole(isTerm, _, _, content) =>
113112
assert(isTerm)
114113
assert(!content.isEmpty)
115-
contents += content
114+
holeContents += content
116115
val holeType = getTermHoleType(tree.tpe)
117116
val hole = untpd.cpy.Hole(tree)(content = EmptyTree).withType(holeType)
118117
cpy.Inlined(tree)(EmptyTree, Nil, hole)
@@ -148,10 +147,10 @@ class PickleQuotes extends MacroTransform {
148147
mapOver(tp)
149148
}
150149

151-
/** Get the contents of the transformed tree */
150+
/** Get the holeContents of the transformed tree */
152151
def getContents() =
153-
val res = contents.result
154-
contents.clear()
152+
val res = holeContents.result
153+
holeContents.clear()
155154
res
156155
end HoleContentExtractor
157156

@@ -160,7 +159,7 @@ class PickleQuotes extends MacroTransform {
160159
val quote1 = cpy.Quote(quote)(body1, quote.tags)
161160

162161
(holeMaker.getContents(), quote1)
163-
end makeHoles
162+
end extractHolesContents
164163

165164
/** Encode quote tags as holes in the quote body.
166165
*
@@ -237,7 +236,7 @@ object PickleQuotes {
237236
val name: String = "pickleQuotes"
238237
val description: String = "turn quoted trees into explicit run-time data structures"
239238

240-
def pickle(quote: Quote, quotes: Tree, contents: List[Tree])(using Context) = {
239+
def pickle(quote: Quote, quotes: Tree, holeContents: List[Tree])(using Context) = {
241240
val body = quote.body
242241
val bodyType = quote.bodyType
243242

@@ -335,27 +334,22 @@ object PickleQuotes {
335334
case x :: Nil => Literal(Constant(x))
336335
case xs => tpd.mkList(xs.map(x => Literal(Constant(x))), TypeTree(defn.StringType))
337336

338-
// TODO split holes earlier into types and terms. This all holes in each category can have consecutive indices
339-
val (typeSplices, termSplices) = contents.zipWithIndex.partition {
340-
_._1.tpe.derivesFrom(defn.QuotedTypeClass)
341-
}
342-
343337
// This and all closures in typeSplices are removed by the BetaReduce phase
344338
val types =
345-
if typeSplices.isEmpty then Literal(Constant(null)) // keep pickled quote without contents as small as possible
346-
else SeqLiteral(typeSplices.map(_._1), TypeTree(defn.QuotedTypeClass.typeRef.appliedTo(WildcardType)))
339+
if quote.tags.isEmpty then Literal(Constant(null)) // keep pickled quote without holeContents as small as possible
340+
else SeqLiteral(quote.tags, TypeTree(defn.QuotedTypeClass.typeRef.appliedTo(TypeBounds.emptyPolyKind)))
347341

348342
// This and all closures in termSplices are removed by the BetaReduce phase
349343
val termHoles =
350-
if termSplices.isEmpty then Literal(Constant(null)) // keep pickled quote without contents as small as possible
344+
if holeContents.isEmpty then Literal(Constant(null)) // keep pickled quote without holeContents as small as possible
351345
else
352346
Lambda(
353347
MethodType(
354348
List(nme.idx, nme.contents, nme.quotes).map(name => UniqueName.fresh(name).toTermName),
355349
List(defn.IntType, defn.SeqType.appliedTo(defn.AnyType), defn.QuotesClass.typeRef),
356350
defn.QuotedExprClass.typeRef.appliedTo(defn.AnyType)),
357351
args =>
358-
val cases = termSplices.map { case (splice, idx) =>
352+
val cases = holeContents.zipWithIndex.map { case (splice, idx) =>
359353
val defn.FunctionOf(argTypes, defn.FunctionOf(quotesType :: _, _, _), _) = splice.tpe: @unchecked
360354
val rhs = {
361355
val spliceArgs = argTypes.zipWithIndex.map { (argType, i) =>
@@ -414,7 +408,7 @@ object PickleQuotes {
414408
case _ => None
415409

416410
if body.isType then
417-
if contents.isEmpty && body.symbol.isPrimitiveValueClass then taggedType()
411+
if holeContents.isEmpty && body.symbol.isPrimitiveValueClass then taggedType()
418412
else pickleAsTasty()
419413
else
420414
getLiteral(body) match

0 commit comments

Comments
 (0)