@@ -837,7 +837,6 @@ class Simplify extends MiniPhaseTransform with IdentityDenotTransformer {
837
837
// invalidates the denotation cache. Because this optimization only
838
838
// operates locally, this should be fine.
839
839
val denot = app.fun.symbol.denot
840
- simplify.println(s " replacing ${app.symbol}" )
841
840
if (! denot.info.finalResultType.derivesFrom(defn.UnitClass )) {
842
841
val newLabelType = app.symbol.info match {
843
842
case mt : MethodType =>
@@ -1113,10 +1112,11 @@ class Simplify extends MiniPhaseTransform with IdentityDenotTransformer {
1113
1112
val devalify : Optimization = { implicit ctx : Context =>
1114
1113
val timesUsed = mutable.HashMap [Symbol , Int ]()
1115
1114
val defined = mutable.HashSet [Symbol ]()
1115
+ val usedInInnerClass = mutable.HashMap [Symbol , Int ]()
1116
1116
// Either a duplicate or a read through series of immutable fields
1117
1117
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 ) &&
1120
1120
! valdef.symbol.is(Mutable | Module | Lazy ) &&
1121
1121
valdef.symbol.exists && ! valdef.symbol.owner.isClass =>
1122
1122
defined += valdef.symbol
@@ -1128,20 +1128,45 @@ class Simplify extends MiniPhaseTransform with IdentityDenotTransformer {
1128
1128
}
1129
1129
case t : New =>
1130
1130
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 )
1133
1133
1134
1134
case valdef : ValDef if valdef.symbol.exists && ! valdef.symbol.owner.isClass &&
1135
1135
! valdef.symbol.is(Param | Module | Lazy ) =>
1136
1136
// TODO: handle params after constructors. Start changing public signatures by eliminating unused arguments.
1137
1137
defined += valdef.symbol
1138
1138
1139
1139
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 )
1142
1142
case _ =>
1143
1143
}
1144
1144
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
+
1145
1170
val transformer : Transformer = () => localCtx => {
1146
1171
val valsToDrop = defined -- timesUsed.keySet
1147
1172
val copiesToReplaceAsDuplicates = copies.filter { x =>
@@ -1157,7 +1182,7 @@ class Simplify extends MiniPhaseTransform with IdentityDenotTransformer {
1157
1182
case None => Nil
1158
1183
})
1159
1184
1160
- val replacements = copiesToReplaceAsDuplicates ++ copiesToReplaceAsUsedOnce
1185
+ val replacements = copiesToReplaceAsDuplicates ++ copiesToReplaceAsUsedOnce -- usedInInnerClass.keySet
1161
1186
1162
1187
val deepReplacer = new TreeMap () {
1163
1188
override def transform (tree : Tree )(implicit ctx : Context ): Tree = {
0 commit comments