aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/ast/TreeInfo.scala22
-rw-r--r--src/dotty/tools/dotc/typer/Inliner.scala20
-rw-r--r--tests/run/inlinedAssign.scala4
3 files changed, 35 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)
diff --git a/tests/run/inlinedAssign.scala b/tests/run/inlinedAssign.scala
index f405f5073..5b73a6f0c 100644
--- a/tests/run/inlinedAssign.scala
+++ b/tests/run/inlinedAssign.scala
@@ -6,6 +6,8 @@ object Test {
y_=(t)
}
+ inline def f(x: Int => Unit) = x
+
def main(args: Array[String]) = {
var x = 1
var y = 2
@@ -13,5 +15,7 @@ object Test {
inline def setY(z: Int) = y = z
swap(x, setX, y, setY)
assert(x == 2 && y == 1)
+
+ val z = f(setX) // tests case where inline arg is not applied
}
}