Skip to content

Commit c3e8087

Browse files
committed
Drop redundant bindings when inlining
1 parent 194ccc6 commit c3e8087

File tree

1 file changed

+78
-3
lines changed

1 file changed

+78
-3
lines changed

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

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import StdNames.nme
1515
import Contexts.Context
1616
import Names.{Name, TermName, EmptyTermName}
1717
import NameOps._
18-
import NameKinds.{ClassifiedNameKind, InlineAccessorName}
18+
import NameKinds.{ClassifiedNameKind, InlineAccessorName, UniqueName}
1919
import ProtoTypes.selectionProto
2020
import SymDenotations.SymDenotation
2121
import Annotations._
@@ -216,7 +216,8 @@ object Inliner {
216216
for (iref <- referenced.implicitRefs.toList) yield {
217217
val localImplicit = iref.symbol.asTerm.copy(
218218
owner = inlineMethod,
219-
flags = Implicit | Method,
219+
name = UniqueName.fresh(iref.symbol.name.asTermName),
220+
flags = Implicit | Method | Stable,
220221
info = iref.symbol.info.ensureMethodic,
221222
coord = inlineMethod.pos).asTerm
222223
polyDefDef(localImplicit, tps => vrefss =>
@@ -530,10 +531,12 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
530531
/** All bindings in `bindingsBuf` except bindings of inlineable closures */
531532
val bindings = bindingsBuf.toList.map(_.withPos(call.pos))
532533

534+
val (finalBindings, finalExpansion) = dropUnusedDefs(bindings, expansion1)
535+
533536
//println(i"bindings buf = ${bindingsBuf.toList}%; %")
534537
//println(i"bindings = ${bindings.toList}%; %")
535538

536-
tpd.Inlined(call, bindings, expansion1)
539+
tpd.Inlined(call, finalBindings, finalExpansion)
537540
}
538541
}
539542

@@ -625,4 +628,76 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
625628

626629
override def newLikeThis: Typer = new InlineTyper
627630
}
631+
632+
/** Drop any side-effect-free bindings that are unused in expansion or other reachable bindings.
633+
* Inline def bindings that are used only once.
634+
*/
635+
def dropUnusedDefs(bindings: List[ValOrDefDef], tree: Tree)(implicit ctx: Context): (List[ValOrDefDef], Tree) = {
636+
val refCount = newMutableSymbolMap[Int]
637+
val bindingOfSym = newMutableSymbolMap[ValOrDefDef]
638+
def isInlineable(binding: ValOrDefDef) = binding match {
639+
case DefDef(_, Nil, Nil, _, _) => true
640+
case vdef @ ValDef(_, _, _) => isPureExpr(vdef.rhs)
641+
case _ => false
642+
}
643+
for (binding <- bindings if isInlineable(binding)) {
644+
refCount(binding.symbol) = 0
645+
bindingOfSym(binding.symbol) = binding
646+
}
647+
val countRefs = new TreeTraverser {
648+
override def traverse(t: Tree)(implicit ctx: Context) = {
649+
t match {
650+
case t: RefTree =>
651+
refCount.get(t.symbol) match {
652+
case Some(x) => refCount(t.symbol) = x + 1
653+
case none =>
654+
}
655+
case _: New | _: TypeTree =>
656+
//println(i"refcount ${t.tpe}")
657+
t.tpe.foreachPart {
658+
case ref: TermRef =>
659+
refCount.get(ref.symbol) match {
660+
case Some(x) => refCount(ref.symbol) = x + 2
661+
case none =>
662+
}
663+
case _ =>
664+
}
665+
case _ =>
666+
}
667+
traverseChildren(t)
668+
}
669+
}
670+
countRefs.traverse(tree)
671+
for (binding <- bindings) countRefs.traverse(binding.rhs)
672+
val inlineBindings = new TreeMap {
673+
override def transform(t: Tree)(implicit ctx: Context) =
674+
super.transform {
675+
t match {
676+
case t: RefTree =>
677+
val sym = t.symbol
678+
refCount.get(sym) match {
679+
case Some(1) if sym.is(Method) =>
680+
bindingOfSym(sym).rhs.changeOwner(sym, ctx.owner)
681+
case none => t
682+
}
683+
case _ => t
684+
}
685+
}
686+
}
687+
def retain(binding: ValOrDefDef) = refCount.get(binding.symbol) match {
688+
case Some(x) => x > 1 || x == 1 && !binding.symbol.is(Method)
689+
case none => true
690+
}
691+
val retained = bindings.filterConserve(retain)
692+
if (retained `eq` bindings) {
693+
//println(i"DONE\n${bindings}%\n% ;;;\n ${tree}")
694+
(bindings, tree)
695+
}
696+
else {
697+
val expanded = inlineBindings.transform(tree)
698+
//println(i"ref counts: ${refCount.toMap map { case (sym, count) => i"$sym -> $count" }}")
699+
//println(i"""MAPPING\n${bindings}%\n% ;;;\n ${tree} \n------->\n${retained}%\n%;;;\n ${expanded} """)
700+
dropUnusedDefs(retained, expanded)
701+
}
702+
}
628703
}

0 commit comments

Comments
 (0)