From 245095d57d37b52cc8f5faefebd68a2b61ad5a82 Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Wed, 22 Aug 2018 19:40:04 +0200 Subject: [PATCH 1/2] Optimize enclosingInlineds inlineContext already normalized most of InlinedCalls, normalize all of it instead. The new code isn't much more complex, the only tricky bit is assuming we don't need to normalize the pre-normalized list. In fact, this can be simplified further! --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 27 ++++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index e81817d8db55..06965c445eeb 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -1082,21 +1082,24 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { /** A key to be used in a context property that tracks enclosing inlined calls */ private val InlinedCalls = new Property.Key[List[Tree]] - override def inlineContext(call: Tree)(implicit ctx: Context): Context = - ctx.fresh.setProperty(InlinedCalls, call :: enclosingInlineds) - - /** All enclosing calls that are currently inlined, from innermost to outermost. - * EmptyTree calls cancel the next-enclosing non-empty call in the list - */ - def enclosingInlineds(implicit ctx: Context): List[Tree] = { - def normalize(ts: List[Tree]): List[Tree] = ts match { - case t :: (ts1 @ (t1 :: ts2)) if t.isEmpty => normalize(if (t1.isEmpty) ts1 else ts2) - case t :: ts1 => t :: normalize(ts1) - case Nil => Nil + /** Record an enclosing inlined call. + * EmptyTree calls (for parameters) cancel the next-enclosing non-empty call in the list + */ + override def inlineContext(call: Tree)(implicit ctx: Context): Context = { + // We assume enclosingInlineds is already normalized, and only process the new call with the head. + val oldIC = enclosingInlineds + val newIC = (call, oldIC) match { + case (t, ts1 @ (t1 :: ts2)) if t.isEmpty => if (t1.isEmpty) ts1 else ts2 + case _ => call :: oldIC } - normalize(ctx.property(InlinedCalls).getOrElse(Nil)) + ctx.fresh.setProperty(InlinedCalls, newIC) } + /** All enclosing calls that are currently inlined, from innermost to outermost. + */ + def enclosingInlineds(implicit ctx: Context): List[Tree] = + ctx.property(InlinedCalls).getOrElse(Nil) + /** The source file where the symbol of the `inline` method referred to by `call` * is defined */ From b5abba680d6e2ede470b1ccb5fc8b12d704ceb3a Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Wed, 22 Aug 2018 19:55:23 +0200 Subject: [PATCH 2/2] inlineContext: assume we never nest empty calls --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 06965c445eeb..f4f4535931c4 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -1083,13 +1083,16 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { private val InlinedCalls = new Property.Key[List[Tree]] /** Record an enclosing inlined call. - * EmptyTree calls (for parameters) cancel the next-enclosing non-empty call in the list + * EmptyTree calls (for parameters) cancel the next-enclosing call in the list instead of being added to it. + * We assume parameters are never nested inside parameters. */ override def inlineContext(call: Tree)(implicit ctx: Context): Context = { // We assume enclosingInlineds is already normalized, and only process the new call with the head. val oldIC = enclosingInlineds val newIC = (call, oldIC) match { - case (t, ts1 @ (t1 :: ts2)) if t.isEmpty => if (t1.isEmpty) ts1 else ts2 + case (t, t1 :: ts2) if t.isEmpty => + assert(!t1.isEmpty) + ts2 case _ => call :: oldIC } ctx.fresh.setProperty(InlinedCalls, newIC)