Skip to content

Commit 7608bb4

Browse files
committed
Use a single "mapStatements" implementation in three places
Use a single "mapStatements" implementation in three TreeMapWithImplicits, MacroTransform, and MegaPhase.
1 parent 9c668f3 commit 7608bb4

File tree

2 files changed

+19
-53
lines changed

2 files changed

+19
-53
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

+18-18
Original file line numberDiff line numberDiff line change
@@ -1151,35 +1151,26 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
11511151
case _ => tree1 :: rest1
11521152
case nil => nil
11531153
recur(trees, 0)
1154-
end extension
1155-
1156-
/** A treemap that generates the same contexts as the original typer for statements.
1157-
* This means:
1158-
* - statements that are not definitions get the exprOwner as owner
1159-
* - imports are reflected in the contexts of subsequent statements
1160-
*/
1161-
class TreeMapWithPreciseStatContexts(cpy: TreeCopier = tpd.cpy) extends TreeMap(cpy):
11621154

1163-
/** Transform statements, while maintaining import contexts and expression contexts
1155+
/** Transform statements while maintaining import contexts and expression contexts
11641156
* in the same way as Typer does. The code addresses additional concerns:
11651157
* - be tail-recursive where possible
11661158
* - don't re-allocate trees where nothing has changed
1167-
* - avoid stack overflows for long statement lists
11681159
*/
1169-
override def transformStats(stats: List[Tree], exprOwner: Symbol)(using Context): List[Tree] =
1160+
inline def mapStatements(exprOwner: Symbol, inline op: Tree => Context ?=> Tree)(using Context): List[Tree] =
11701161
@tailrec
11711162
def loop(mapped: mutable.ListBuffer[Tree] | Null, unchanged: List[Tree], pending: List[Tree])(using Context): List[Tree] =
11721163
pending match
11731164
case stat :: rest =>
1174-
def statCtx = stat match
1165+
val statCtx = stat match
11751166
case _: DefTree | _: ImportOrExport => ctx
11761167
case _ => ctx.exprContext(stat, exprOwner)
1177-
def restCtx = stat match
1168+
val stat1 = op(stat)(using statCtx)
1169+
val restCtx = stat match
11781170
case stat: Import => ctx.importContext(stat, stat.symbol)
11791171
case _ => ctx
1180-
val stat1 = transform(stat)(using statCtx)
11811172
if stat1 eq stat then
1182-
loop(mapped, unchanged, rest)
1173+
loop(mapped, unchanged, rest)(using restCtx)
11831174
else
11841175
val buf = if mapped == null then new mutable.ListBuffer[Tree] else mapped
11851176
var xc = unchanged
@@ -1194,9 +1185,18 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
11941185
if mapped == null then unchanged
11951186
else mapped.prependToList(unchanged)
11961187

1197-
loop(null, stats, stats)
1198-
end transformStats
1199-
end TreeMapWithPreciseStatContexts
1188+
loop(null, trees, trees)
1189+
end mapStatements
1190+
end extension
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(_))
12001200

12011201
/** Map Inlined nodes, NamedArgs, Blocks with no statements and local references to underlying arguments.
12021202
* Also drops Inline and Block with no statements.

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

+1-35
Original file line numberDiff line numberDiff line change
@@ -433,43 +433,9 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase {
433433
transformTree(tree, start).asInstanceOf[T]
434434

435435
def transformStats(trees: List[Tree], exprOwner: Symbol, start: Int)(using Context): List[Tree] =
436-
437-
def transformStat(stat: Tree)(using Context): Tree = stat match {
438-
case _: Import | _: DefTree => transformTree(stat, start)
439-
case Thicket(stats) => cpy.Thicket(stat)(stats.mapConserve(transformStat))
440-
case _ => transformTree(stat, start)(using ctx.exprContext(stat, exprOwner))
441-
}
442-
443-
def restContext(tree: Tree)(using Context): Context = tree match
444-
case imp: Import => ctx.importContext(imp, imp.symbol)
445-
case _ => ctx
446-
447-
// A slower implementation that avoids deep recursions and stack overflows
448-
def transformSlow(trees: List[Tree])(using Context): List[Tree] =
449-
var curCtx = ctx
450-
flatten(trees.mapConserve { tree =>
451-
val tree1 = transformStat(tree)(using curCtx)
452-
curCtx = restContext(tree)(using curCtx)
453-
tree1
454-
})
455-
456-
def recur(trees: List[Tree], count: Int)(using Context): List[Tree] =
457-
if count > MapRecursionLimit then
458-
transformSlow(trees)
459-
else trees match
460-
case tree :: rest =>
461-
val tree1 = transformStat(tree)
462-
val rest1 = recur(rest, count + 1)(using restContext(tree))
463-
if (tree1 eq tree) && (rest1 eq rest) then trees
464-
else tree1 match
465-
case Thicket(elems1) => elems1 ::: rest1
466-
case _ => tree1 :: rest1
467-
case nil => nil
468-
469436
val nestedCtx = prepStats(trees, start)
470-
val trees1 = recur(trees, 0)(using nestedCtx)
437+
val trees1 = trees.mapStatements(exprOwner, transformTree(_, start))(using nestedCtx)
471438
goStats(trees1, start)(using nestedCtx)
472-
end transformStats
473439

474440
def transformUnit(tree: Tree)(using Context): Tree = {
475441
val nestedCtx = prepUnit(tree, 0)

0 commit comments

Comments
 (0)