Skip to content

Commit 05d409f

Browse files
authored
Merge pull request scala#6060 from retronym/faster/virtual-transform-minimal
Spread transform/traverse/mapOver into virtual methods of Tree/Type
2 parents 9303e82 + 02537a1 commit 05d409f

26 files changed

+654
-556
lines changed

src/compiler/scala/tools/nsc/ast/Trees.scala

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ import java.lang.System.{lineSeparator => EOL}
1212
trait Trees extends scala.reflect.internal.Trees { self: Global =>
1313
// --- additional cases --------------------------------------------------------
1414
/** Only used during parsing */
15-
case class Parens(args: List[Tree]) extends Tree
15+
case class Parens(args: List[Tree]) extends Tree {
16+
override def traverse(traverser: Traverser): Unit = {
17+
traverser.traverseTrees(args)
18+
}
19+
}
1620

1721
/** Documented definition, eliminated by analyzer */
1822
case class DocDef(comment: DocComment, definition: Tree)
@@ -22,22 +26,46 @@ trait Trees extends scala.reflect.internal.Trees { self: Global =>
2226
override def isDef = definition.isDef
2327
override def isTerm = definition.isTerm
2428
override def isType = definition.isType
29+
override def transform(transformer: ApiTransformer): Tree =
30+
transformer.treeCopy.DocDef(this, comment, transformer.transform(definition))
31+
override def traverse(traverser: Traverser): Unit = {
32+
traverser.traverse(definition)
33+
}
2534
}
2635

2736
/** Array selection `<qualifier> . <name>` only used during erasure */
2837
case class SelectFromArray(qualifier: Tree, name: Name, erasure: Type)
29-
extends RefTree with TermTree
38+
extends RefTree with TermTree {
39+
override def transform(transformer: ApiTransformer): Tree =
40+
transformer.treeCopy.SelectFromArray(
41+
this, transformer.transform(qualifier), name, erasure)
42+
override def traverse(traverser: Traverser): Unit = {
43+
traverser.traverse(qualifier)
44+
}
45+
}
3046

3147
/** Derived value class injection (equivalent to: `new C(arg)` after erasure); only used during erasure.
3248
* The class `C` is stored as a tree attachment.
3349
*/
3450
case class InjectDerivedValue(arg: Tree)
35-
extends SymTree with TermTree
51+
extends SymTree with TermTree {
52+
override def transform(transformer: ApiTransformer): Tree =
53+
transformer.treeCopy.InjectDerivedValue(this, transformer.transform(arg))
54+
override def traverse(traverser: Traverser): Unit = {
55+
traverser.traverse(arg)
56+
}
57+
}
3658

3759
class PostfixSelect(qual: Tree, name: Name) extends Select(qual, name)
3860

3961
/** emitted by typer, eliminated by refchecks */
40-
case class TypeTreeWithDeferredRefCheck()(val check: () => TypeTree) extends TypTree
62+
case class TypeTreeWithDeferredRefCheck()(val check: () => TypeTree) extends TypTree {
63+
override def transform(transformer: ApiTransformer): Tree =
64+
transformer.treeCopy.TypeTreeWithDeferredRefCheck(this)
65+
override def traverse(traverser: Traverser): Unit = {
66+
// (and rewrap the result? how to update the deferred check? would need to store wrapped tree instead of returning it from check)
67+
}
68+
}
4169

4270
// --- factory methods ----------------------------------------------------------
4371

@@ -76,20 +104,6 @@ trait Trees extends scala.reflect.internal.Trees { self: Global =>
76104

77105
// --- additional cases in operations ----------------------------------
78106

79-
override protected def xtraverse(traverser: Traverser, tree: Tree): Unit = tree match {
80-
case Parens(ts) =>
81-
traverser.traverseTrees(ts)
82-
case DocDef(comment, definition) =>
83-
traverser.traverse(definition)
84-
case SelectFromArray(qualifier, selector, erasure) =>
85-
traverser.traverse(qualifier)
86-
case InjectDerivedValue(arg) =>
87-
traverser.traverse(arg)
88-
case TypeTreeWithDeferredRefCheck() =>
89-
// (and rewrap the result? how to update the deferred check? would need to store wrapped tree instead of returning it from check)
90-
case _ => super.xtraverse(traverser, tree)
91-
}
92-
93107
trait TreeCopier extends super.InternalTreeCopierOps {
94108
def DocDef(tree: Tree, comment: DocComment, definition: Tree): DocDef
95109
def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type): SelectFromArray
@@ -135,7 +149,8 @@ trait Trees extends scala.reflect.internal.Trees { self: Global =>
135149
}
136150
}
137151

138-
class Transformer extends super.Transformer {
152+
type ApiTransformer = super.Transformer
153+
class Transformer extends InternalTransformer {
139154
def transformUnit(unit: CompilationUnit) {
140155
try unit.body = transform(unit.body)
141156
catch {
@@ -151,19 +166,6 @@ trait Trees extends scala.reflect.internal.Trees { self: Global =>
151166
override def transformUnit(unit: CompilationUnit): Unit = {}
152167
}
153168

154-
override protected def xtransform(transformer: super.Transformer, tree: Tree): Tree = tree match {
155-
case DocDef(comment, definition) =>
156-
transformer.treeCopy.DocDef(tree, comment, transformer.transform(definition))
157-
case SelectFromArray(qualifier, selector, erasure) =>
158-
transformer.treeCopy.SelectFromArray(
159-
tree, transformer.transform(qualifier), selector, erasure)
160-
case InjectDerivedValue(arg) =>
161-
transformer.treeCopy.InjectDerivedValue(
162-
tree, transformer.transform(arg))
163-
case TypeTreeWithDeferredRefCheck() =>
164-
transformer.treeCopy.TypeTreeWithDeferredRefCheck(tree)
165-
}
166-
167169
object resetPos extends Traverser {
168170
override def traverse(t: Tree) {
169171
if (t != EmptyTree) t.setPos(NoPosition)
@@ -224,7 +226,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global =>
224226
}
225227
}
226228

227-
class MarkLocals extends self.Traverser {
229+
class MarkLocals extends self.InternalTraverser {
228230
def markLocal(tree: Tree) {
229231
if (tree.symbol != null && tree.symbol != NoSymbol) {
230232
val sym = tree.symbol
@@ -249,16 +251,16 @@ trait Trees extends scala.reflect.internal.Trees { self: Global =>
249251
tree
250252
}
251253

252-
super.traverse(tree)
254+
tree.traverse(this)
253255
}
254256
}
255257

256258
class Transformer extends self.Transformer {
257259
override def transform(tree: Tree): Tree = {
258260
if (leaveAlone != null && leaveAlone(tree))
259261
tree
260-
else
261-
super.transform {
262+
else {
263+
val tree1 = {
262264
tree match {
263265
case tree if !tree.canHaveAttrs =>
264266
tree
@@ -310,6 +312,8 @@ trait Trees extends scala.reflect.internal.Trees { self: Global =>
310312
dupl.clearType()
311313
}
312314
}
315+
tree1.transform(this)
316+
}
313317
}
314318
}
315319

src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ abstract class BCodeIdiomatic {
629629
* The entry-value for a LabelDef entry-key always contains the entry-key.
630630
*
631631
*/
632-
class LabelDefsFinder(rhs: Tree) extends Traverser {
632+
class LabelDefsFinder(rhs: Tree) extends InternalTraverser {
633633
val result = mutable.AnyRefMap.empty[Tree, List[LabelDef]]
634634
var acc: List[LabelDef] = Nil
635635
var directResult: List[LabelDef] = Nil
@@ -643,7 +643,7 @@ abstract class BCodeIdiomatic {
643643
override def traverse(tree: Tree) {
644644
val saved = acc
645645
acc = Nil
646-
super.traverse(tree)
646+
tree.traverse(this)
647647
// acc contains all LabelDefs found under (but not at) `tree`
648648
tree match {
649649
case lblDf: LabelDef => acc ::= lblDf

src/compiler/scala/tools/nsc/transform/CleanUp.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL {
374374
// collecting symbols for entry points here (as opposed to GenBCode where they are used)
375375
// has the advantage of saving an additional pass over all ClassDefs.
376376
entryPoints += tree.symbol
377-
super.transform(tree)
377+
tree.transform(this)
378378

379379
/* Transforms dynamic calls (i.e. calls to methods that are undefined
380380
* in the erased type space) to -- dynamically -- unsafe calls using
@@ -454,23 +454,23 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL {
454454
case Apply(fn @ Select(qual, _), (arg @ Literal(Constant(symname: String))) :: Nil)
455455
if treeInfo.isQualifierSafeToElide(qual) && fn.symbol == Symbol_apply && !currentClass.isTrait =>
456456

457-
super.transform(treeCopy.ApplyDynamic(tree, atPos(fn.pos)(Ident(SymbolLiteral_dummy).setType(SymbolLiteral_dummy.info)), LIT(SymbolLiteral_bootstrap) :: arg :: Nil))
457+
treeCopy.ApplyDynamic(tree, atPos(fn.pos)(Ident(SymbolLiteral_dummy).setType(SymbolLiteral_dummy.info)), LIT(SymbolLiteral_bootstrap) :: arg :: Nil).transform(this)
458458

459459
// Drop the TypeApply, which was used in Erasure to make `synchronized { ... } ` erase like `...`
460460
// (and to avoid boxing the argument to the polymorphic `synchronized` method).
461461
case app@Apply(TypeApply(fun, _), args) if fun.symbol == Object_synchronized =>
462-
super.transform(treeCopy.Apply(app, fun, args))
462+
treeCopy.Apply(app, fun, args).transform(this)
463463

464464
// Replaces `Array(Predef.wrapArray(ArrayValue(...).$asInstanceOf[...]), <tag>)`
465465
// with just `ArrayValue(...).$asInstanceOf[...]`
466466
//
467467
// See scala/bug#6611; we must *only* do this for literal vararg arrays.
468468
case Apply(appMeth, List(Apply(wrapRefArrayMeth, List(arg @ StripCast(ArrayValue(_, _)))), _))
469469
if wrapRefArrayMeth.symbol == currentRun.runDefinitions.Predef_wrapRefArray && appMeth.symbol == ArrayModule_genericApply =>
470-
super.transform(arg)
470+
arg.transform(this)
471471
case Apply(appMeth, List(elem0, Apply(wrapArrayMeth, List(rest @ ArrayValue(elemtpt, _)))))
472472
if wrapArrayMeth.symbol == Predef_wrapArray(elemtpt.tpe) && appMeth.symbol == ArrayModule_apply(elemtpt.tpe) =>
473-
super.transform(treeCopy.ArrayValue(rest, rest.elemtpt, elem0 :: rest.elems))
473+
treeCopy.ArrayValue(rest, rest.elemtpt, elem0 :: rest.elems).transform(this)
474474

475475
case _ =>
476476
super.transform(tree)

src/compiler/scala/tools/nsc/transform/Constructors.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ abstract class Constructors extends Statics with Transform with TypingTransforme
169169
val omittables = mutable.Set.empty[Symbol] ++ (decls filter (sym => omittableParamAcc(sym) || omittableOuterAcc(sym))) // the closure only captures isEffectivelyFinal
170170

171171
// no point traversing further once omittables is empty, all candidates ruled out already.
172-
object detectUsages extends Traverser {
172+
object detectUsages extends InternalTraverser {
173173
lazy val bodyOfOuterAccessor = defs.collect{ case dd: DefDef if omittableOuterAcc(dd.symbol) => dd.symbol -> dd.rhs }.toMap
174174

175175
override def traverse(tree: Tree): Unit =
@@ -179,8 +179,8 @@ abstract class Constructors extends Statics with Transform with TypingTransforme
179179
case _: DefDef if (sym.owner eq clazz) && omittableOuterAcc(sym) => // don't mark as "needed" the field supporting this outer-accessor (not just yet)
180180
case _: Select if omittables(sym) => omittables -= sym // mark usage
181181
bodyOfOuterAccessor get sym foreach traverse // recurse to mark as needed the field supporting the outer-accessor-method
182-
super.traverse(tree)
183-
case _ => super.traverse(tree)
182+
tree.traverse(this)
183+
case _ => tree.traverse(this)
184184
}
185185
}
186186
}

src/compiler/scala/tools/nsc/transform/Delambdafy.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
300300
// A traverser that finds symbols used but not defined in the given Tree
301301
// TODO freeVarTraverser in LambdaLift does a very similar task. With some
302302
// analysis this could probably be unified with it
303-
class FreeVarTraverser extends Traverser {
303+
class FreeVarTraverser extends InternalTraverser {
304304
val freeVars = mutable.LinkedHashSet[Symbol]()
305305
val declared = mutable.LinkedHashSet[Symbol]()
306306

@@ -317,7 +317,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
317317
if ((sym != NoSymbol) && sym.isLocalToBlock && sym.isTerm && !sym.isMethod && !declared.contains(sym)) freeVars += sym
318318
case _ =>
319319
}
320-
super.traverse(tree)
320+
tree.traverse(this)
321321
}
322322
}
323323

@@ -330,7 +330,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
330330
}
331331

332332
// finds all methods that reference 'this'
333-
class ThisReferringMethodsTraverser extends Traverser {
333+
class ThisReferringMethodsTraverser extends InternalTraverser {
334334
// the set of methods that refer to this
335335
private val thisReferringMethods = mutable.Set[Symbol]()
336336

@@ -371,7 +371,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
371371
// we don't expect defs within defs. At this phase trees should be very flat
372372
if (currentMethod.exists) devWarning("Found a def within a def at a phase where defs are expected to be flattened out.")
373373
currentMethod = tree.symbol
374-
super.traverse(tree)
374+
tree.traverse(this)
375375
currentMethod = NoSymbol
376376
case fun@Function(_, _) =>
377377
// we don't drill into functions because at the beginning of this phase they will always refer to 'this'.
@@ -382,7 +382,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
382382
if (currentMethod.exists) liftedMethodReferences(currentMethod) += sel.symbol
383383
super.traverseTrees(args)
384384
case Apply(fun, outer :: rest) if shouldElideOuterArg(fun.symbol, outer) =>
385-
super.traverse(fun)
385+
fun.traverse(this)
386386
super.traverseTrees(rest)
387387
case This(_) =>
388388
if (currentMethod.exists && tree.symbol == currentMethod.enclClass) {
@@ -392,7 +392,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
392392
case _: ClassDef if !tree.symbol.isTopLevel =>
393393
case _: DefDef =>
394394
case _ =>
395-
super.traverse(tree)
395+
tree.traverse(this)
396396
}
397397
}
398398
}

src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ abstract class ExplicitOuter extends InfoTransform
202202
* values for outer parameters of constructors.
203203
* The class provides methods for referencing via outer.
204204
*/
205-
abstract class OuterPathTransformer(unit: CompilationUnit) extends TypingTransformer(unit) with UnderConstructionTransformer {
205+
abstract class OuterPathTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
206206
/** The directly enclosing outer parameter, if we are in a constructor */
207207
protected var outerParam: Symbol = NoSymbol
208208

@@ -267,6 +267,13 @@ abstract class ExplicitOuter extends InfoTransform
267267
else outerPath(outerSelect(base), from.outerClass, to)
268268
}
269269

270+
271+
/** The stack of class symbols in which a call to this() or to the super
272+
* constructor, or early definition is active
273+
*/
274+
protected def isUnderConstruction(clazz: Symbol) = selfOrSuperCalls contains clazz
275+
protected val selfOrSuperCalls = collection.mutable.Stack[Symbol]()
276+
270277
override def transform(tree: Tree): Tree = {
271278
def sym = tree.symbol
272279
val savedOuterParam = outerParam
@@ -279,7 +286,13 @@ abstract class ExplicitOuter extends InfoTransform
279286
assert(outerParam.name startsWith nme.OUTER, outerParam.name)
280287
case _ =>
281288
}
282-
super.transform(tree)
289+
if ((treeInfo isSelfOrSuperConstrCall tree) || (treeInfo isEarlyDef tree)) {
290+
selfOrSuperCalls push currentOwner.owner
291+
val transformed = super.transform(tree)
292+
selfOrSuperCalls.pop()
293+
transformed
294+
} else
295+
super.transform(tree)
283296
}
284297
finally outerParam = savedOuterParam
285298
}

src/compiler/scala/tools/nsc/transform/Flatten.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,10 @@ abstract class Flatten extends InfoTransform {
118118
tree match {
119119
case PackageDef(_, _) =>
120120
liftedDefs(tree.symbol.moduleClass) = new ListBuffer
121-
super.transform(tree)
121+
tree.transform(this)
122122
case Template(_, _, _) if tree.symbol.isDefinedInPackage =>
123123
liftedDefs(tree.symbol.owner) = new ListBuffer
124-
super.transform(tree)
124+
tree.transform(this)
125125
case ClassDef(_, _, _, _) if tree.symbol.isNestedClass =>
126126
// scala/bug#5508 Ordering important. In `object O { trait A { trait B } }`, we want `B` to appear after `A` in
127127
// the sequence of lifted trees in the enclosing package. Why does this matter? Currently, mixin
@@ -134,12 +134,12 @@ abstract class Flatten extends InfoTransform {
134134
// - move the accessor creation to the Mixin info transformer
135135
val liftedBuffer = liftedDefs(tree.symbol.enclosingTopLevelClass.owner)
136136
val index = liftedBuffer.length
137-
liftedBuffer.insert(index, super.transform(tree))
137+
liftedBuffer.insert(index, tree.transform(this))
138138
if (tree.symbol.sourceModule.isStaticModule)
139139
removeSymbolInCurrentScope(tree.symbol.sourceModule)
140140
EmptyTree
141141
case _ =>
142-
super.transform(tree)
142+
tree.transform(this)
143143
}
144144
}
145145

src/compiler/scala/tools/nsc/transform/LambdaLift.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ abstract class LambdaLift extends InfoTransform {
186186
}
187187

188188
/** The traverse function */
189-
private val freeVarTraverser = new Traverser {
189+
private val freeVarTraverser = new InternalTraverser {
190190
override def traverse(tree: Tree) {
191191
// try { //debug
192192
val sym = tree.symbol
@@ -217,7 +217,7 @@ abstract class LambdaLift extends InfoTransform {
217217
markCalled(sym, logicallyEnclosingMember(currentOwner))
218218
case _ =>
219219
}
220-
super.traverse(tree)
220+
tree.traverse(this)
221221
// } catch {//debug
222222
// case ex: Throwable =>
223223
// Console.println(s"$ex while traversing $tree")

src/compiler/scala/tools/nsc/transform/Mixin.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL with AccessorSynthes
430430
val singleUseFields: Map[Symbol, List[Symbol]] = {
431431
val usedIn = mutable.HashMap[Symbol, List[Symbol]]() withDefaultValue Nil
432432

433-
object SingleUseTraverser extends Traverser {
433+
object SingleUseTraverser extends InternalTraverser {
434434
override def traverse(tree: Tree) {
435435
tree match {
436436
// assignment targets don't count as a dereference -- only check the rhs
@@ -445,8 +445,8 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL with AccessorSynthes
445445
// println("added use in: " + currentOwner + " -- " + tree)
446446
usedIn(sym) ::= currentOwner
447447
}
448-
super.traverse(tree)
449-
case _ => super.traverse(tree)
448+
tree.traverse(this)
449+
case _ => tree.traverse(this)
450450
}
451451
}
452452
}
@@ -595,7 +595,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL with AccessorSynthes
595595
*/
596596
override def transform(tree: Tree): Tree = {
597597
val saved = localTyper
598-
val tree1 = super.transform(preTransform(tree))
598+
val tree1 = preTransform(tree).transform(this)
599599
// localTyper needed when not flattening inner classes. parts after an
600600
// inner class will otherwise be typechecked with a wrong scope
601601
try exitingMixin(postTransform(tree1))

0 commit comments

Comments
 (0)