aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-09-13 12:24:42 +0200
committerMartin Odersky <odersky@gmail.com>2016-10-02 16:12:28 +0200
commit65551d19b5d928f231426c016e561051d68d9c97 (patch)
tree2715d259ee41f6cf3ad6e9a8271d2626cfe3e51b /src
parent4de907a313e9b85058cd9611116a1cbcf2bd3a4f (diff)
downloaddotty-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.scala22
-rw-r--r--src/dotty/tools/dotc/typer/Inliner.scala20
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)