@@ -93,8 +93,9 @@ class PickleQuotes extends MacroTransform {
93
93
override def transform (tree : tpd.Tree )(using Context ): tpd.Tree =
94
94
tree match
95
95
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)
98
99
val holeContents1 = holeContents.map(transform(_))
99
100
PickleQuotes .pickle(quote2, quotes, holeContents1)
100
101
case tree : DefDef if ! tree.rhs.isEmpty && tree.symbol.isInlineMethod =>
@@ -103,7 +104,7 @@ class PickleQuotes extends MacroTransform {
103
104
super .transform(tree)
104
105
}
105
106
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 ) =
107
108
class HoleContentExtractor extends Transformer :
108
109
private val holeContents = List .newBuilder[Tree ]
109
110
override def transform (tree : tpd.Tree )(using Context ): tpd.Tree =
@@ -112,7 +113,7 @@ class PickleQuotes extends MacroTransform {
112
113
assert(isTerm)
113
114
assert(! content.isEmpty)
114
115
holeContents += content
115
- val holeType = getTermHoleType (tree.tpe)
116
+ val holeType = getPicklableHoleType (tree.tpe, stagedClasses )
116
117
val hole = untpd.cpy.Hole (tree)(content = EmptyTree ).withType(holeType)
117
118
cpy.Inlined (tree)(EmptyTree , Nil , hole)
118
119
case tree : DefTree =>
@@ -134,19 +135,6 @@ class PickleQuotes extends MacroTransform {
134
135
}
135
136
}
136
137
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
-
150
138
/** Get the holeContents of the transformed tree */
151
139
def getContents () =
152
140
val res = holeContents.result
@@ -175,10 +163,10 @@ class PickleQuotes extends MacroTransform {
175
163
* }
176
164
* ```
177
165
*/
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 =
179
167
if quote.tags.isEmpty then quote
180
168
else
181
- val tdefs = quote.tags.zipWithIndex.map(mkTagSymbolAndAssignType)
169
+ val tdefs = quote.tags.zipWithIndex.map((tag, idx) => mkTagSymbolAndAssignType(tag, idx, stagedClasses) )
182
170
val typeMapping = quote.tags.map(_.tpe).zip(tdefs.map(_.symbol.typeRef)).toMap
183
171
val typeMap = new TypeMap {
184
172
override def apply (tp : Type ): Type = tp match
@@ -195,12 +183,12 @@ class PickleQuotes extends MacroTransform {
195
183
val body1 = new TreeTypeMap (typeMap, treeMap).transform(quote.body)
196
184
cpy.Quote (quote)(Block (tdefs, body1), quote.tags)
197
185
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 )
200
188
val hole = untpd.cpy.Hole (typeArg)(isTerm = false , idx, Nil , EmptyTree ).withType(holeType)
201
189
val local = newSymbol(
202
190
owner = ctx.owner,
203
- name = UniqueName .fresh(hole.tpe.dealias.typeSymbol .name.toTypeName),
191
+ name = UniqueName .fresh(typeArg.symbol .name.toTypeName),
204
192
flags = Synthetic ,
205
193
info = TypeAlias (typeArg.tpe.select(tpnme.Underlying )),
206
194
coord = typeArg.span
@@ -209,25 +197,21 @@ class PickleQuotes extends MacroTransform {
209
197
ctx.typeAssigner.assignType(untpd.TypeDef (local.name, hole), local).withSpan(typeArg.span)
210
198
}
211
199
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)
231
215
}
232
216
233
217
object PickleQuotes {
0 commit comments