Skip to content

Commit 2303264

Browse files
committed
Refactoring: Introduce LocalScope{Transfomer,Traverser}.
In several places, we transform or traverse (part of) a method body in a way that is dependent on the local scope. In those situations, we must stop at `Closure` boundaries. We now introduce dedicated subclasses that handle this particular behavior. This factors out the correct handling of `Closure`s, and at the same time makes the intent clearer. One use of `Traverser` in `OptimizerCore` did not handle `Closure`s in a special way, but it should also be about the local scope.
1 parent 98e0875 commit 2303264

File tree

4 files changed

+33
-16
lines changed

4 files changed

+33
-16
lines changed

compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,16 +1108,10 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
11081108
}
11091109

11101110
// After the super call, substitute `selfRef` for `this`
1111-
val afterSuper = new ir.Transformers.Transformer {
1111+
val afterSuper = new ir.Transformers.LocalScopeTransformer {
11121112
override def transform(tree: js.Tree): js.Tree = tree match {
11131113
case js.This() =>
11141114
selfRef(tree.pos)
1115-
1116-
// Don't traverse closure boundaries
1117-
case closure: js.Closure =>
1118-
val newCaptureValues = transformTrees(closure.captureValues)
1119-
closure.copy(captureValues = newCaptureValues)(closure.pos)
1120-
11211115
case tree =>
11221116
super.transform(tree)
11231117
}
@@ -2171,14 +2165,11 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
21712165
} yield {
21722166
js.ParamDef(name, originalName, ptpe, newMutable(name.name, mutable))(p.pos)
21732167
}
2174-
val transformer = new ir.Transformers.Transformer {
2168+
val transformer = new ir.Transformers.LocalScopeTransformer {
21752169
override def transform(tree: js.Tree): js.Tree = tree match {
21762170
case js.VarDef(name, originalName, vtpe, mutable, rhs) =>
21772171
super.transform(js.VarDef(name, originalName, vtpe,
21782172
newMutable(name.name, mutable), rhs)(tree.pos))
2179-
case js.Closure(arrow, captureParams, params, restParam, body, captureValues) =>
2180-
js.Closure(arrow, captureParams, params, restParam, body,
2181-
transformTrees(captureValues))(tree.pos)
21822173
case _ =>
21832174
super.transform(tree)
21842175
}
@@ -2207,13 +2198,10 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
22072198
} yield {
22082199
js.ParamDef(name, originalName, newType(name.name, ptpe), mutable)(p.pos)
22092200
}
2210-
val transformer = new ir.Transformers.Transformer {
2201+
val transformer = new ir.Transformers.LocalScopeTransformer {
22112202
override def transform(tree: js.Tree): js.Tree = tree match {
22122203
case tree @ js.VarRef(name) =>
22132204
js.VarRef(name)(newType(name, tree.tpe))(tree.pos)
2214-
case js.Closure(arrow, captureParams, params, restParam, body, captureValues) =>
2215-
js.Closure(arrow, captureParams, params, restParam, body,
2216-
transformTrees(captureValues))(tree.pos)
22172205
case _ =>
22182206
super.transform(tree)
22192207
}

ir/shared/src/main/scala/org/scalajs/ir/Transformers.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,4 +277,19 @@ object Transformers {
277277
}
278278
}
279279

280+
/** Transformer that only transforms in the local scope.
281+
*
282+
* In practice, this means stopping at `Closure` boundaries: their
283+
* `captureValues` are transformed, but not their other members.
284+
*/
285+
abstract class LocalScopeTransformer extends Transformer {
286+
override def transform(tree: Tree): Tree = tree match {
287+
case Closure(arrow, captureParams, params, restParam, body, captureValues) =>
288+
Closure(arrow, captureParams, params, restParam, body,
289+
transformTrees(captureValues))(tree.pos)
290+
case _ =>
291+
super.transform(tree)
292+
}
293+
}
294+
280295
}

ir/shared/src/main/scala/org/scalajs/ir/Traversers.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,4 +245,18 @@ object Traversers {
245245
}
246246
}
247247

248+
/** Traverser that only traverses the local scope.
249+
*
250+
* In practice, this means stopping at `Closure` boundaries: their
251+
* `captureValues` are traversed, but not their other members.
252+
*/
253+
abstract class LocalScopeTraverser extends Traverser {
254+
override def traverse(tree: Tree): Unit = tree match {
255+
case Closure(_, _, _, _, _, captureValues) =>
256+
captureValues.foreach(traverse(_))
257+
case _ =>
258+
super.traverse(tree)
259+
}
260+
}
261+
248262
}

linker/shared/src/main/scala/org/scalajs/linker/frontend/optimizer/OptimizerCore.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1713,7 +1713,7 @@ private[optimizer] abstract class OptimizerCore(
17131713
private def tryInsertAtFirstEvalContext(valName: LocalName, valTree: Tree, body: Tree): Option[Tree] = {
17141714
import EvalContextInsertion._
17151715

1716-
object valTreeInfo extends Traversers.Traverser {
1716+
object valTreeInfo extends Traversers.LocalScopeTraverser {
17171717
val mutatedLocalVars = mutable.Set.empty[LocalName]
17181718

17191719
traverse(valTree)

0 commit comments

Comments
 (0)