Skip to content

Commit cb61947

Browse files
committed
Simplify avoidance of non-picklable types of Hole
1 parent ca7c29f commit cb61947

File tree

1 file changed

+25
-41
lines changed

1 file changed

+25
-41
lines changed

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

Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,9 @@ 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 (holeContents, quote1) = extractHolesContents(quote)
97-
val quote2 = encodeTypeArgs(quote1)
96+
val stagedClasses = getStagedClasses(quote)
97+
val (holeContents, quote1) = extractHolesContents(quote, stagedClasses)
98+
val quote2 = encodeTypeArgs(quote1, stagedClasses)
9899
val holeContents1 = holeContents.map(transform(_))
99100
PickleQuotes.pickle(quote2, quotes, holeContents1)
100101
case tree: DefDef if !tree.rhs.isEmpty && tree.symbol.isInlineMethod =>
@@ -103,7 +104,7 @@ class PickleQuotes extends MacroTransform {
103104
super.transform(tree)
104105
}
105106

106-
private def extractHolesContents(quote: tpd.Quote)(using Context): (List[Tree], tpd.Quote) =
107+
private def extractHolesContents(quote: tpd.Quote, stagedClasses: Set[Symbol])(using Context): (List[Tree], tpd.Quote) =
107108
class HoleContentExtractor extends Transformer:
108109
private val holeContents = List.newBuilder[Tree]
109110
override def transform(tree: tpd.Tree)(using Context): tpd.Tree =
@@ -112,7 +113,7 @@ class PickleQuotes extends MacroTransform {
112113
assert(isTerm)
113114
assert(!content.isEmpty)
114115
holeContents += content
115-
val holeType = getTermHoleType(tree.tpe)
116+
val holeType = getPicklableHoleType(tree.tpe, stagedClasses)
116117
val hole = untpd.cpy.Hole(tree)(content = EmptyTree).withType(holeType)
117118
cpy.Inlined(tree)(EmptyTree, Nil, hole)
118119
case tree: DefTree =>
@@ -134,19 +135,6 @@ class PickleQuotes extends MacroTransform {
134135
}
135136
}
136137

137-
/** Remove references to local types that will not be defined in this quote */
138-
private def getTermHoleType(using Context) = new TypeMap() {
139-
override def apply(tp: Type): Type = tp match
140-
case tp @ TypeRef(NoPrefix, _) =>
141-
// reference to term with a type defined in outer quote
142-
getTypeHoleType(tp)
143-
case tp @ TermRef(NoPrefix, _) =>
144-
// widen term refs to terms defined in outer quote
145-
apply(tp.widenTermRefExpr)
146-
case tp =>
147-
mapOver(tp)
148-
}
149-
150138
/** Get the holeContents of the transformed tree */
151139
def getContents() =
152140
val res = holeContents.result
@@ -175,10 +163,10 @@ class PickleQuotes extends MacroTransform {
175163
* }
176164
* ```
177165
*/
178-
private def encodeTypeArgs(quote: tpd.Quote)(using Context): tpd.Quote =
166+
private def encodeTypeArgs(quote: tpd.Quote, stagedClasses: Set[Symbol])(using Context): tpd.Quote =
179167
if quote.tags.isEmpty then quote
180168
else
181-
val tdefs = quote.tags.zipWithIndex.map(mkTagSymbolAndAssignType)
169+
val tdefs = quote.tags.zipWithIndex.map((tag, idx) => mkTagSymbolAndAssignType(tag, idx, stagedClasses))
182170
val typeMapping = quote.tags.map(_.tpe).zip(tdefs.map(_.symbol.typeRef)).toMap
183171
val typeMap = new TypeMap {
184172
override def apply(tp: Type): Type = tp match
@@ -195,12 +183,12 @@ class PickleQuotes extends MacroTransform {
195183
val body1 = new TreeTypeMap(typeMap, treeMap).transform(quote.body)
196184
cpy.Quote(quote)(Block(tdefs, body1), quote.tags)
197185

198-
private def mkTagSymbolAndAssignType(typeArg: Tree, idx: Int)(using Context): TypeDef = {
199-
val holeType = getTypeHoleType(typeArg.tpe.select(tpnme.Underlying))
186+
private def mkTagSymbolAndAssignType(typeArg: Tree, idx: Int, stagedClasses: Set[Symbol])(using Context): TypeDef = {
187+
val holeType = getPicklableHoleType(typeArg.tpe.select(tpnme.Underlying), stagedClasses)
200188
val hole = untpd.cpy.Hole(typeArg)(isTerm = false, idx, Nil, EmptyTree).withType(holeType)
201189
val local = newSymbol(
202190
owner = ctx.owner,
203-
name = UniqueName.fresh(hole.tpe.dealias.typeSymbol.name.toTypeName),
191+
name = UniqueName.fresh(typeArg.symbol.name.toTypeName),
204192
flags = Synthetic,
205193
info = TypeAlias(typeArg.tpe.select(tpnme.Underlying)),
206194
coord = typeArg.span
@@ -209,25 +197,21 @@ class PickleQuotes extends MacroTransform {
209197
ctx.typeAssigner.assignType(untpd.TypeDef(local.name, hole), local).withSpan(typeArg.span)
210198
}
211199

212-
/** Remove references to local types that will not be defined in this quote */
213-
private def getTypeHoleType(using Context) = new TypeMap() {
214-
override def apply(tp: Type): Type = tp match
215-
case tp: TypeRef if tp.typeSymbol.isTypeSplice =>
216-
apply(tp.dealias)
217-
case tp @ TypeRef(pre, _) if isLocalPath(pre) =>
218-
val hiBound = tp.typeSymbol.info match
219-
case info: ClassInfo => info.parents.reduce(_ & _)
220-
case info => info.hiBound
221-
apply(hiBound)
222-
case tp =>
223-
mapOver(tp)
224-
225-
private def isLocalPath(tp: Type): Boolean = tp match
226-
case NoPrefix => true
227-
case tp: TermRef if !tp.symbol.is(Package) => isLocalPath(tp.prefix)
228-
case tp => false
229-
}
230-
200+
/** Set of classes defined in this quote */
201+
private def getStagedClasses(tree: Quote)(using Context): Set[Symbol] =
202+
new TreeAccumulator[Set[Symbol]] {
203+
def apply(x: Set[Symbol], tree: Tree)(using Context): Set[Symbol] =
204+
tree match
205+
case tree: TypeDef if tree.symbol.isClass => foldOver(x + tree.symbol, tree)
206+
case _: Hole => x
207+
case _ => foldOver(x, tree)
208+
}.apply(Set.empty, tree.body)
209+
210+
/** Avoid all non-static types except those defined in the quote. */
211+
private def getPicklableHoleType(tpe: Type, stagedClasses: Set[Symbol])(using Context) =
212+
new TypeOps.AvoidMap {
213+
def toAvoid(tp: NamedType) = !stagedClasses(tp.typeSymbol) && !isStaticPrefix(tp)
214+
}.apply(tpe)
231215
}
232216

233217
object PickleQuotes {

0 commit comments

Comments
 (0)