Skip to content

Commit 90707d5

Browse files
committed
Optimization: Lift bindings out of inline call
1 parent b6ea4cd commit 90707d5

File tree

1 file changed

+45
-5
lines changed

1 file changed

+45
-5
lines changed

compiler/src/dotty/tools/dotc/typer/Inliner.scala

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,49 @@ object Inliner {
8585
* @return An `Inlined` node that refers to the original call and the inlined bindings
8686
* and body that replace it.
8787
*/
88-
def inlineCall(tree: Tree, pt: Type)(implicit ctx: Context): Tree = tree match {
89-
case Block(stats, expr) =>
90-
cpy.Block(tree)(stats, inlineCall(expr, pt))
91-
case _ if (enclosingInlineds.length < ctx.settings.XmaxInlines.value) =>
88+
def inlineCall(tree: Tree, pt: Type)(implicit ctx: Context): Tree = {
89+
90+
/** Set the position of all trees logically contained in the expansion of
91+
* inlined call `call` to the position of `call`. This transform is necessary
92+
* when lifting bindings from the expansion to the outside of the call.
93+
*/
94+
def liftFromInlined(call: Tree) = new TreeMap {
95+
override def transform(t: Tree)(implicit ctx: Context) = {
96+
t match {
97+
case Inlined(t, Nil, expr) if t.isEmpty => expr
98+
case _ => super.transform(t.withPos(call.pos))
99+
}
100+
}
101+
}
102+
103+
val bindings = new mutable.ListBuffer[Tree]
104+
105+
/** Lift bindings in function or argument of inline call to
106+
* the `bindings` buffer. This is done as an optimization to keep
107+
* inline call expansions smaller.
108+
*/
109+
def liftBindings(tree: Tree, liftPos: Tree => Tree): Tree = tree match {
110+
case Block(stats, expr) =>
111+
bindings ++= stats.map(liftPos)
112+
liftBindings(expr, liftPos)
113+
case Inlined(call, stats, expr) =>
114+
bindings ++= stats.map(liftPos)
115+
val lifter = liftFromInlined(call)
116+
cpy.Inlined(tree)(call, Nil, liftBindings(expr, liftFromInlined(call).transform(_)))
117+
case Apply(fn, args) =>
118+
cpy.Apply(tree)(liftBindings(fn, liftPos), args.map(liftBindings(_, liftPos)))
119+
case TypeApply(fn, args) =>
120+
cpy.TypeApply(tree)(liftBindings(fn, liftPos), args)
121+
case Select(qual, name) =>
122+
cpy.Select(tree)(liftBindings(qual, liftPos), name)
123+
case _ =>
124+
tree
125+
}
126+
127+
val tree1 = liftBindings(tree, identity)
128+
if (bindings.nonEmpty)
129+
cpy.Block(tree)(bindings.toList, inlineCall(tree1, pt))
130+
else if (enclosingInlineds.length < ctx.settings.XmaxInlines.value) {
92131
val body = bodyToInline(tree.symbol) // can typecheck the tree and thereby produce errors
93132
if (ctx.reporter.hasErrors) tree
94133
else {
@@ -97,7 +136,8 @@ object Inliner {
97136
else ctx.fresh.setProperty(InlineBindings, newMutableSymbolMap[Tree])
98137
new Inliner(tree, body)(inlinerCtx).inlined(pt)
99138
}
100-
case _ =>
139+
}
140+
else
101141
errorTree(
102142
tree,
103143
i"""|Maximal number of successive inlines (${ctx.settings.XmaxInlines.value}) exceeded,

0 commit comments

Comments
 (0)