diff options
author | Martin Odersky <odersky@gmail.com> | 2016-09-13 12:24:42 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2016-10-02 16:12:28 +0200 |
commit | 65551d19b5d928f231426c016e561051d68d9c97 (patch) | |
tree | 2715d259ee41f6cf3ad6e9a8271d2626cfe3e51b /src | |
parent | 4de907a313e9b85058cd9611116a1cbcf2bd3a4f (diff) | |
download | dotty-65551d19b5d928f231426c016e561051d68d9c97.tar.gz dotty-65551d19b5d928f231426c016e561051d68d9c97.tar.bz2 dotty-65551d19b5d928f231426c016e561051d68d9c97.zip |
Don't drop inline closure bindings that are referred in the body
The body might still refer to an inline closure argument without
fully applying it. In that case the binding may not be dropped.
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/ast/TreeInfo.scala | 22 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Inliner.scala | 20 |
2 files changed, 31 insertions, 11 deletions
diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index 0d7ebc5e1..421ff5919 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -88,12 +88,6 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => case mp => mp } - /** If tree is a closure, it's body, otherwise tree itself */ - def closureBody(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match { - case Block((meth @ DefDef(nme.ANON_FUN, _, _, _, _)) :: Nil, Closure(_, _, _)) => meth.rhs - case _ => tree - } - /** If this is an application, its function part, stripping all * Apply nodes (but leaving TypeApply nodes in). Otherwise the tree itself. */ @@ -449,6 +443,22 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => (tree, Nil, Nil) } + /** An extractor for closures, either contained in a block or standalone. + */ + object closure { + def unapply(tree: Tree): Option[(List[Tree], Tree, Tree)] = tree match { + case Block(_, Closure(env, meth, tpt)) => Some(env, meth, tpt) + case Closure(env, meth, tpt) => Some(env, meth, tpt) + case _ => None + } + } + + /** If tree is a closure, it's body, otherwise tree itself */ + def closureBody(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match { + case Block((meth @ DefDef(nme.ANON_FUN, _, _, _, _)) :: Nil, Closure(_, _, _)) => meth.rhs + case _ => tree + } + /** The variables defined by a pattern, in reverse order of their appearance. */ def patVars(tree: Tree)(implicit ctx: Context): List[Symbol] = { val acc = new TreeAccumulator[List[Symbol]] { diff --git a/src/dotty/tools/dotc/typer/Inliner.scala b/src/dotty/tools/dotc/typer/Inliner.scala index 44946c37b..a78d1c029 100644 --- a/src/dotty/tools/dotc/typer/Inliner.scala +++ b/src/dotty/tools/dotc/typer/Inliner.scala @@ -505,13 +505,13 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { val expansion1 = InlineTyper.typed(expansion, pt)(inlineContext(call)) /** Does given definition bind a closure that will be inlined? */ - def bindsInlineableClosure(defn: ValOrDefDef) = Ident(defn.symbol.termRef) match { - case InlineableClosure(_) => true + def bindsDeadClosure(defn: ValOrDefDef) = Ident(defn.symbol.termRef) match { + case InlineableClosure(_) => !InlineTyper.retainedClosures.contains(defn.symbol) case _ => false } /** All bindings in `bindingsBuf` except bindings of inlineable closures */ - val bindings = bindingsBuf.toList.filterNot(bindsInlineableClosure).map(_.withPos(call.pos)) + val bindings = bindingsBuf.toList.filterNot(bindsDeadClosure).map(_.withPos(call.pos)) val result = tpd.Inlined(call, bindings, expansion1) inlining.println(i"inlined $call\n --> \n$result") @@ -524,8 +524,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { def unapply(tree: Ident)(implicit ctx: Context): Option[Tree] = if (paramProxies.contains(tree.tpe)) { bindingsBuf.find(_.name == tree.name).map(_.rhs) match { - case Some(Closure(_, meth, _)) if meth.symbol.isInlineMethod => Some(meth) - case Some(Block(_, Closure(_, meth, _))) if meth.symbol.isInlineMethod => Some(meth) + case Some(closure(_, meth, _)) if meth.symbol.isInlineMethod => Some(meth) case _ => None } } else None @@ -540,6 +539,17 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { */ private object InlineTyper extends ReTyper { + var retainedClosures = Set[Symbol]() + + override def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context) = { + val tree1 = super.typedIdent(tree, pt) + tree1 match { + case InlineableClosure(_) => retainedClosures += tree.symbol + case _ => + } + tree1 + } + override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = { val res = super.typedSelect(tree, pt) ensureAccessible(res.tpe, tree.qualifier.isInstanceOf[untpd.Super], tree.pos) |