diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index b273bbf01e95..56cc0822a961 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -1341,10 +1341,17 @@ object Trees { case tree: SeqLiteral if (elems eq tree.elems) && (elemtpt eq tree.elemtpt) => tree case _ => finalize(tree, untpd.SeqLiteral(elems, elemtpt)(sourceFile(tree))) } - def Inlined(tree: Tree)(call: tpd.Tree, bindings: List[MemberDef], expansion: Tree)(using Context): Inlined = tree match { - case tree: Inlined if (call eq tree.call) && (bindings eq tree.bindings) && (expansion eq tree.expansion) => tree - case _ => finalize(tree, untpd.Inlined(call, bindings, expansion)(sourceFile(tree))) - } + // Positions of trees are automatically pushed down except when we reach an Inlined tree. Therefore, we + // make sure the new expansion has a position by copying the one of the original Inlined tree. + def Inlined(tree: Inlined)(call: tpd.Tree, bindings: List[MemberDef], expansion: Tree)(using Context): Inlined = + if (call eq tree.call) && (bindings eq tree.bindings) && (expansion eq tree.expansion) then tree + else + // Copy the span from the original Inlined tree if the new expansion doesn't have a span. + val expansionWithSpan = + if expansion.span.exists then expansion + else expansion.withSpan(tree.expansion.span) + finalize(tree, untpd.Inlined(call, bindings, expansionWithSpan)(sourceFile(tree))) + def Quote(tree: Tree)(body: Tree, tags: List[Tree])(using Context): Quote = tree match { case tree: Quote if (body eq tree.body) && (tags eq tree.tags) => tree case _ => finalize(tree, untpd.Quote(body, tags)(sourceFile(tree))) @@ -1549,8 +1556,8 @@ object Trees { cpy.Try(tree)(transform(block), transformSub(cases), transform(finalizer)) case SeqLiteral(elems, elemtpt) => cpy.SeqLiteral(tree)(transform(elems), transform(elemtpt)) - case Inlined(call, bindings, expansion) => - cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)(using inlineContext(call))) + case tree @ Inlined(call, bindings, expansion) => + cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)(using inlineContext(tree))) case TypeTree() => tree case SingletonTypeTree(ref) => diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 0d3085f13f1e..d3760e553767 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -748,7 +748,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { } } - override def Inlined(tree: Tree)(call: Tree, bindings: List[MemberDef], expansion: Tree)(using Context): Inlined = { + override def Inlined(tree: Inlined)(call: Tree, bindings: List[MemberDef], expansion: Tree)(using Context): Inlined = { val tree1 = untpdCpy.Inlined(tree)(call, bindings, expansion) tree match { case tree: Inlined if sameTypes(bindings, tree.bindings) && (expansion.tpe eq tree.expansion.tpe) => diff --git a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala index bcc10ffa6db8..d0ef66880388 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala @@ -117,7 +117,7 @@ object Inlines: case Block(stats, expr) => bindings ++= stats.map(liftPos) liftBindings(expr, liftPos) - case Inlined(call, stats, expr) => + case tree @ Inlined(call, stats, expr) => bindings ++= stats.map(liftPos) val lifter = liftFromInlined(call) cpy.Inlined(tree)(call, Nil, liftBindings(expr, liftFromInlined(call).transform(_))) diff --git a/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala b/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala index 7596549fe401..a25f80da2786 100644 --- a/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala +++ b/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala @@ -81,12 +81,12 @@ object PickledQuotes { /** Unpickle the tree contained in the TastyExpr */ def unpickleTerm(pickled: String | List[String], typeHole: TypeHole, termHole: ExprHole)(using Context): Tree = { - val unpickled = withMode(Mode.ReadPositions)(unpickle(pickled, isType = false)) - val Inlined(call, Nil, expansion) = unpickled: @unchecked - val inlineCtx = inlineContext(call) - val expansion1 = spliceTypes(expansion, typeHole)(using inlineCtx) - val expansion2 = spliceTerms(expansion1, typeHole, termHole)(using inlineCtx) - cpy.Inlined(unpickled)(call, Nil, expansion2) + withMode(Mode.ReadPositions)(unpickle(pickled, isType = false)) match + case tree @ Inlined(call, Nil, expansion) => + val inlineCtx = inlineContext(tree) + val expansion1 = spliceTypes(expansion, typeHole)(using inlineCtx) + val expansion2 = spliceTerms(expansion1, typeHole, termHole)(using inlineCtx) + cpy.Inlined(tree)(call, Nil, expansion2) } diff --git a/compiler/src/dotty/tools/dotc/transform/BetaReduce.scala b/compiler/src/dotty/tools/dotc/transform/BetaReduce.scala index aafb64b33444..ad36544cdec0 100644 --- a/compiler/src/dotty/tools/dotc/transform/BetaReduce.scala +++ b/compiler/src/dotty/tools/dotc/transform/BetaReduce.scala @@ -82,7 +82,7 @@ object BetaReduce: case _ => None case Block(stats, expr) if stats.forall(isPureBinding) => recur(expr, argss).map(cpy.Block(fn)(stats, _)) - case Inlined(call, bindings, expr) if bindings.forall(isPureBinding) => + case fn @ Inlined(call, bindings, expr) if bindings.forall(isPureBinding) => recur(expr, argss).map(cpy.Inlined(fn)(call, bindings, _)) case Typed(expr, tpt) => recur(expr, argss) diff --git a/compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala b/compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala index 8b58f18bca52..b368e47bf0b3 100644 --- a/compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala @@ -115,7 +115,7 @@ class PickleQuotes extends MacroTransform { holeContents += content val holeType = getPicklableHoleType(tree.tpe, stagedClasses) val hole = untpd.cpy.Hole(tree)(content = EmptyTree).withType(holeType) - cpy.Inlined(tree)(EmptyTree, Nil, hole) + Inlined(EmptyTree, Nil, hole).withSpan(tree.span) case tree: DefTree => if tree.symbol.isClass then stagedClasses += tree.symbol diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 1d9493e6b1f7..fd272be42735 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -250,7 +250,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => private object dropInlines extends TreeMap { override def transform(tree: Tree)(using Context): Tree = tree match { - case Inlined(call, _, expansion) => + case tree @ Inlined(call, _, expansion) => val newExpansion = PruneErasedDefs.trivialErasedTree(tree) cpy.Inlined(tree)(call, Nil, newExpansion) case _ => super.transform(tree) @@ -363,7 +363,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => case _ => super.transform(tree1) } - case Inlined(call, bindings, expansion) if !call.isEmpty => + case tree @ Inlined(call, bindings, expansion) if !tree.inlinedFromOuterScope => val pos = call.sourcePos CrossVersionChecks.checkExperimentalRef(call.symbol, pos) withMode(Mode.InlinedCall)(transform(call)) diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 7df98d57b5ff..c014b27a58c0 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -1005,7 +1005,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler def apply(call: Option[Tree], bindings: List[Definition], expansion: Term): Inlined = withDefaultPos(tpd.Inlined(call.getOrElse(tpd.EmptyTree), bindings.map { case b: tpd.MemberDef => b }, xCheckMacroValidExpr(expansion))) def copy(original: Tree)(call: Option[Tree], bindings: List[Definition], expansion: Term): Inlined = - tpd.cpy.Inlined(original)(call.getOrElse(tpd.EmptyTree), bindings.asInstanceOf[List[tpd.MemberDef]], xCheckMacroValidExpr(expansion)) + tpd.Inlined(call.getOrElse(tpd.EmptyTree), bindings.asInstanceOf[List[tpd.MemberDef]], xCheckMacroValidExpr(expansion)).withSpan(original.span).withType(original.tpe) def unapply(x: Inlined): (Option[Tree /* Term | TypeTree */], List[Definition], Term) = (optional(x.call), x.bindings, x.body) end Inlined