@@ -837,7 +837,6 @@ class Simplify extends MiniPhaseTransform with IdentityDenotTransformer {
837837 // invalidates the denotation cache. Because this optimization only
838838 // operates locally, this should be fine.
839839 val denot = app.fun.symbol.denot
840- simplify.println(s " replacing ${app.symbol}" )
841840 if (! denot.info.finalResultType.derivesFrom(defn.UnitClass )) {
842841 val newLabelType = app.symbol.info match {
843842 case mt : MethodType =>
@@ -1113,10 +1112,11 @@ class Simplify extends MiniPhaseTransform with IdentityDenotTransformer {
11131112 val devalify : Optimization = { implicit ctx : Context =>
11141113 val timesUsed = mutable.HashMap [Symbol , Int ]()
11151114 val defined = mutable.HashSet [Symbol ]()
1115+ val usedInInnerClass = mutable.HashMap [Symbol , Int ]()
11161116 // Either a duplicate or a read through series of immutable fields
11171117 val copies = mutable.HashMap [Symbol , Tree ]()
1118- val visitor : Visitor = {
1119- case valdef : ValDef if ! valdef.symbol.is(Param ) &&
1118+ def doVisit ( tree : Tree , used : mutable. HashMap [ Symbol , Int ]) : Unit = tree match {
1119+ case valdef : ValDef if ! valdef.symbol.is(Param ) &&
11201120 ! valdef.symbol.is(Mutable | Module | Lazy ) &&
11211121 valdef.symbol.exists && ! valdef.symbol.owner.isClass =>
11221122 defined += valdef.symbol
@@ -1128,20 +1128,45 @@ class Simplify extends MiniPhaseTransform with IdentityDenotTransformer {
11281128 }
11291129 case t : New =>
11301130 val symIfExists = t.tpt.tpe.normalizedPrefix.termSymbol
1131- val b4 = timesUsed .getOrElseUpdate(symIfExists, 0 )
1132- timesUsed .put(symIfExists, b4 + 1 )
1131+ val b4 = used .getOrElseUpdate(symIfExists, 0 )
1132+ used .put(symIfExists, b4 + 1 )
11331133
11341134 case valdef : ValDef if valdef.symbol.exists && ! valdef.symbol.owner.isClass &&
11351135 ! valdef.symbol.is(Param | Module | Lazy ) =>
11361136 // TODO: handle params after constructors. Start changing public signatures by eliminating unused arguments.
11371137 defined += valdef.symbol
11381138
11391139 case t : RefTree =>
1140- val b4 = timesUsed .getOrElseUpdate(t.symbol, 0 )
1141- timesUsed .put(t.symbol, b4 + 1 )
1140+ val b4 = used .getOrElseUpdate(t.symbol, 0 )
1141+ used .put(t.symbol, b4 + 1 )
11421142 case _ =>
11431143 }
11441144
1145+ val visitor : Visitor = { tree =>
1146+ def crossingClassBoundaries (t : Tree ): Boolean = t match {
1147+ case _ : New => true
1148+ case _ : Template => true
1149+ case _ => false
1150+ }
1151+ // We shouldn't inline `This` nodes, which we approximate by not inlining
1152+ // anything across class boundaries. To do so, we visit every class a
1153+ // second time and record what's used in the usedInInnerClass Set.
1154+ if (crossingClassBoundaries(tree)) {
1155+ // Doing a foreachSubTree(tree) here would work, but would also
1156+ // be exponential for deeply nested classes. Instead we do a short
1157+ // circuit traversal that doesn't visit further nested classes.
1158+ val reVisitClass = new TreeAccumulator [Unit ] {
1159+ def apply (u : Unit , t : Tree )(implicit ctx : Context ): Unit = {
1160+ doVisit(t, usedInInnerClass)
1161+ if (! crossingClassBoundaries(t))
1162+ foldOver((), t)
1163+ }
1164+ }
1165+ reVisitClass.foldOver((), tree)
1166+ }
1167+ doVisit(tree, timesUsed)
1168+ }
1169+
11451170 val transformer : Transformer = () => localCtx => {
11461171 val valsToDrop = defined -- timesUsed.keySet
11471172 val copiesToReplaceAsDuplicates = copies.filter { x =>
@@ -1157,7 +1182,7 @@ class Simplify extends MiniPhaseTransform with IdentityDenotTransformer {
11571182 case None => Nil
11581183 })
11591184
1160- val replacements = copiesToReplaceAsDuplicates ++ copiesToReplaceAsUsedOnce
1185+ val replacements = copiesToReplaceAsDuplicates ++ copiesToReplaceAsUsedOnce -- usedInInnerClass.keySet
11611186
11621187 val deepReplacer = new TreeMap () {
11631188 override def transform (tree : Tree )(implicit ctx : Context ): Tree = {
0 commit comments