@@ -1151,12 +1151,57 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
1151
1151
case _ => tree1 :: rest1
1152
1152
case nil => nil
1153
1153
recur(trees, 0 )
1154
+
1155
+ /** Transform statements while maintaining import contexts and expression contexts
1156
+ * in the same way as Typer does. The code addresses additional concerns:
1157
+ * - be tail-recursive where possible
1158
+ * - don't re-allocate trees where nothing has changed
1159
+ */
1160
+ inline def mapStatements (exprOwner : Symbol , inline op : Tree => Context ?=> Tree )(using Context ): List [Tree ] =
1161
+ @ tailrec
1162
+ def loop (mapped : mutable.ListBuffer [Tree ] | Null , unchanged : List [Tree ], pending : List [Tree ])(using Context ): List [Tree ] =
1163
+ pending match
1164
+ case stat :: rest =>
1165
+ val statCtx = stat match
1166
+ case _ : DefTree | _ : ImportOrExport => ctx
1167
+ case _ => ctx.exprContext(stat, exprOwner)
1168
+ val stat1 = op(stat)(using statCtx)
1169
+ val restCtx = stat match
1170
+ case stat : Import => ctx.importContext(stat, stat.symbol)
1171
+ case _ => ctx
1172
+ if stat1 eq stat then
1173
+ loop(mapped, unchanged, rest)(using restCtx)
1174
+ else
1175
+ val buf = if mapped == null then new mutable.ListBuffer [Tree ] else mapped
1176
+ var xc = unchanged
1177
+ while xc ne pending do
1178
+ buf += xc.head
1179
+ xc = xc.tail
1180
+ stat1 match
1181
+ case Thicket (stats1) => buf ++= stats1
1182
+ case _ => buf += stat1
1183
+ loop(buf, rest, rest)(using restCtx)
1184
+ case nil =>
1185
+ if mapped == null then unchanged
1186
+ else mapped.prependToList(unchanged)
1187
+
1188
+ loop(null , trees, trees)
1189
+ end mapStatements
1154
1190
end extension
1155
1191
1192
+ /** A treemap that generates the same contexts as the original typer for statements.
1193
+ * This means:
1194
+ * - statements that are not definitions get the exprOwner as owner
1195
+ * - imports are reflected in the contexts of subsequent statements
1196
+ */
1197
+ class TreeMapWithPreciseStatContexts (cpy : TreeCopier = tpd.cpy) extends TreeMap (cpy):
1198
+ override def transformStats (trees : List [Tree ], exprOwner : Symbol )(using Context ): List [Tree ] =
1199
+ trees.mapStatements(exprOwner, transform(_))
1200
+
1156
1201
/** Map Inlined nodes, NamedArgs, Blocks with no statements and local references to underlying arguments.
1157
1202
* Also drops Inline and Block with no statements.
1158
1203
*/
1159
- class MapToUnderlying extends TreeMap {
1204
+ private class MapToUnderlying extends TreeMap {
1160
1205
override def transform (tree : Tree )(using Context ): Tree = tree match {
1161
1206
case tree : Ident if isBinding(tree.symbol) && skipLocal(tree.symbol) =>
1162
1207
tree.symbol.defTree match {
0 commit comments