From bf02a040a6176f891dd85511a5a5bd131bdeb3ba Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 1 Apr 2020 18:31:59 +0200 Subject: [PATCH 1/4] Properly inline the closure --- library/src/scala/internal/quoted/Matcher.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/scala/internal/quoted/Matcher.scala b/library/src/scala/internal/quoted/Matcher.scala index b59382f12a82..ea16027cae93 100644 --- a/library/src/scala/internal/quoted/Matcher.scala +++ b/library/src/scala/internal/quoted/Matcher.scala @@ -24,7 +24,7 @@ private[quoted] object Matcher { */ private type Env = Map[Symbol, Symbol] - inline private def withEnv[T](env: Env)(body: => Env ?=> T): T = body(using env) + inline private def withEnv[T](env: Env)(inline body: Env ?=> T): T = body(using env) class SymBinding(val sym: Symbol, val fromAbove: Boolean) From 83e28e3f3560d4511c7703138e93c46fdbe82556 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 1 Apr 2020 18:26:51 +0200 Subject: [PATCH 2/4] Cleanup implementation of Reposition Trees now have sources that can be used directly without the need of `enclosingInlineds` to track the current source. This new implemetation simply uses the tree positions directly and does not need to keep the context in sync with the `enclosingInlineds`. --- .../src/dotty/tools/dotc/typer/Inliner.scala | 48 ++++++++----------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index fe21741080cd..19a9f911e1a4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -155,7 +155,7 @@ object Inliner { if (enclosingInlineds.nonEmpty) inlined // Remove in the outer most inlined call else reposition(inlined, inlined.call.span) - def reposition(tree: Tree, span: Span)(implicit ctx: Context): Tree = { + def reposition(tree: Tree, callSpan: Span)(implicit ctx: Context): Tree = { val curSource = ctx.compilationUnit.source // Tree copier that changes the source of all trees to `curSource` @@ -169,39 +169,33 @@ object Inliner { /** Removes all Inlined trees, replacing them with blocks. * Repositions all trees directly inside an inlined expansion of a non empty call to the position of the call. * Any tree directly inside an empty call (inlined in the inlined code) retains their position. + * + * Until we implement JSR-45, we cannot represent in output positions in other source files. + * So, reposition inlined code from other files with the call position. */ class Reposition extends TreeMap(cpyWithNewSource) { - def finalize(tree: Tree, copied: untpd.Tree) = - copied.withSpan(tree.span).withAttachmentsFrom(tree).withTypeUnchecked(tree.tpe) - - def reposition(tree: Tree)(implicit ctx: Context): Tree = enclosingInlineds match { - case call :: _ if call.symbol.source != curSource => - tree match { - case _: EmptyTree[?] | _: EmptyValDef[?] => tree - case _ => - // Until we implement JSR-45, we cannot represent in output positions in other source files. - // So, reposition inlined code from other files with the call position: - tree.withSpan(span) - } - case _ => tree - } override def transform(tree: Tree)(implicit ctx: Context): Tree = { - val transformed = reposition(tree match { + def finalize(copied: untpd.Tree) = + val span = if tree.source == curSource then tree.span else callSpan + copied.withSpan(span).withAttachmentsFrom(tree).withTypeUnchecked(tree.tpe) + + given as Context = ctx.withSource(curSource) + + tree match { case tree: Inlined => - tpd.seq(transformSub(tree.bindings), transform(tree.expansion)(inlineContext(tree.call)))(ctx.withSource(curSource)) : Tree - case tree: Ident => finalize(tree, untpd.Ident(tree.name)(curSource)) - case tree: Literal => finalize(tree, untpd.Literal(tree.const)(curSource)) - case tree: This => finalize(tree, untpd.This(tree.qual)(curSource)) - case tree: JavaSeqLiteral => finalize(tree, untpd.JavaSeqLiteral(transform(tree.elems), transform(tree.elemtpt))(curSource)) - case tree: SeqLiteral => finalize(tree, untpd.SeqLiteral(transform(tree.elems), transform(tree.elemtpt))(curSource)) - case tree: TypeTree => tpd.TypeTree(tree.tpe)(ctx.withSource(curSource)).withSpan(tree.span) - case tree: Bind => finalize(tree, untpd.Bind(tree.name, transform(tree.body))(curSource)) + if tree.bindings.isEmpty then transform(tree.expansion) + else transform(cpy.Block(tree)(tree.bindings, tree.expansion)) + case tree: Ident => finalize(untpd.Ident(tree.name)(curSource)) + case tree: Literal => finalize(untpd.Literal(tree.const)(curSource)) + case tree: This => finalize(untpd.This(tree.qual)(curSource)) + case tree: JavaSeqLiteral => finalize(untpd.JavaSeqLiteral(transform(tree.elems), transform(tree.elemtpt))(curSource)) + case tree: SeqLiteral => finalize(untpd.SeqLiteral(transform(tree.elems), transform(tree.elemtpt))(curSource)) + case tree: Bind => finalize(untpd.Bind(tree.name, transform(tree.body))(curSource)) + case tree: TypeTree => finalize(tpd.TypeTree(tree.tpe)) case tree: DefTree => super.transform(tree).setDefTree case _ => super.transform(tree) - }) - assert(transformed.isInstanceOf[EmptyTree[?]] || transformed.isInstanceOf[EmptyValDef[?]] || transformed.source == curSource) - transformed + } } } From cf995b56e356b9e042b9f1c981eb74f63cd87db6 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 2 Apr 2020 07:59:50 +0200 Subject: [PATCH 3/4] Properly set positions of inlined implicits --- compiler/src/dotty/tools/dotc/typer/Implicits.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 69bdf0a89877..2e4d927b11e0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -1957,7 +1957,7 @@ final class SearchRoot extends SearchHistory { // Substitute dictionary references into dictionary entry RHSs val rhsMap = new TreeTypeMap(treeMap = { case id: Ident if vsymMap.contains(id.symbol) => - tpd.ref(vsymMap(id.symbol)) + tpd.ref(vsymMap(id.symbol))(ctx.withSource(id.source)).withSpan(id.span) case tree => tree }) val nrhss = rhss.map(rhsMap(_)) @@ -1981,7 +1981,7 @@ final class SearchRoot extends SearchHistory { val res = resMap(tree) - val blk = Inliner.reposition(Block(classDef :: inst :: Nil, res), span) + val blk = Block(classDef :: inst :: Nil, res).withSpan(span) success.copy(tree = blk)(success.tstate, success.gstate) } From e1b34c7060c9ce70a64467bf7b4ad5bf871046e8 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 2 Apr 2020 08:17:34 +0200 Subject: [PATCH 4/4] Make reposition Inlined agnostic --- compiler/src/dotty/tools/dotc/typer/Inliner.scala | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 19a9f911e1a4..9a621f0c0177 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -152,10 +152,15 @@ object Inliner { /** Replace `Inlined` node by a block that contains its bindings and expansion */ def dropInlined(inlined: Inlined)(implicit ctx: Context): Tree = - if (enclosingInlineds.nonEmpty) inlined // Remove in the outer most inlined call - else reposition(inlined, inlined.call.span) + val tree1 = + if inlined.bindings.isEmpty then inlined.expansion + else cpy.Block(inlined)(inlined.bindings, inlined.expansion) + // Reposition in the outer most inlined call + if (enclosingInlineds.nonEmpty) tree1 else reposition(tree1, inlined.span) def reposition(tree: Tree, callSpan: Span)(implicit ctx: Context): Tree = { + // Reference test tests/run/i4947b + val curSource = ctx.compilationUnit.source // Tree copier that changes the source of all trees to `curSource` @@ -183,9 +188,6 @@ object Inliner { given as Context = ctx.withSource(curSource) tree match { - case tree: Inlined => - if tree.bindings.isEmpty then transform(tree.expansion) - else transform(cpy.Block(tree)(tree.bindings, tree.expansion)) case tree: Ident => finalize(untpd.Ident(tree.name)(curSource)) case tree: Literal => finalize(untpd.Literal(tree.const)(curSource)) case tree: This => finalize(untpd.This(tree.qual)(curSource))