diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 8345416a7386..4ec41b95a90b 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -661,8 +661,7 @@ object Trees { * * @param call Info about the original call that was inlined * Until PostTyper, this is the full call, afterwards only - * a reference to the method or the top-level class from - * which the call was inlined. + * a reference to the toplevel class from which the call was inlined. * @param bindings Bindings for proxies to be used in the inlined code * @param expansion The inlined tree, minus bindings. * diff --git a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala index c040c15f5d60..4860913bdc63 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala @@ -299,6 +299,20 @@ object Inlines: (new Reposition).transform(tree) end reposition + /** Leave only a call trace consisting of + * - a reference to the top-level class from which the call was inlined, + * - the call's position + * in the call field of an Inlined node. + * The trace has enough info to completely reconstruct positions. + * Note: For macros it returns a Select and for other inline methods it returns an Ident (this distinction is only temporary to be able to run YCheckPositions) + */ + def inlineCallTrace(callSym: Symbol, pos: SourcePosition)(using Context): Tree = { + assert(ctx.source == pos.source) + val topLevelCls = callSym.topLevelClass + if (callSym.is(Macro)) ref(topLevelCls.owner).select(topLevelCls.name)(using ctx.withOwner(topLevelCls.owner)).withSpan(pos.span) + else Ident(topLevelCls.typeRef).withSpan(pos.span) + } + private object Intrinsics: import dotty.tools.dotc.reporting.Diagnostic.Error private enum ErrorKind: diff --git a/compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala b/compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala index 1f51f17ab91e..624ec9628d87 100644 --- a/compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala @@ -304,7 +304,7 @@ object PickleQuotes { def pickleAsTasty() = { val body1 = if body.isType then body - else Inlined(ref(ctx.owner.topLevelClass.typeRef).withSpan(quote.span), Nil, body) + else Inlined(Inlines.inlineCallTrace(ctx.owner, quote.sourcePos), Nil, body) val pickleQuote = PickledQuotes.pickleQuote(body1) val pickledQuoteStrings = pickleQuote match case x :: Nil => Literal(Constant(x)) diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 3b6c3f9bff96..effbc1dba69a 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -367,7 +367,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => val pos = call.sourcePos CrossVersionChecks.checkExperimentalRef(call.symbol, pos) withMode(Mode.NoInline)(transform(call)) - val callTrace = ref(call.symbol)(using ctx.withSource(pos.source)).withSpan(pos.span) + val callTrace = Inlines.inlineCallTrace(call.symbol, pos)(using ctx.withSource(pos.source)) cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(using inlineContext(tree))) case templ: Template => Checking.checkPolyFunctionExtension(templ) diff --git a/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala b/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala index 88d3e384213c..222f3fec24dc 100644 --- a/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala +++ b/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala @@ -46,8 +46,10 @@ class YCheckPositions extends Phase { sources = old case tree @ Inlined(call, bindings, expansion) => // bindings.foreach(traverse(_)) // TODO check inline proxies (see tests/tun/lst) - sources = call.symbol.source :: sources - if (!isMacro(call)) // FIXME macro implementations can drop Inlined nodes. We should reinsert them after macro expansion based on the positions of the trees + sources = call.symbol.topLevelClass.source :: sources + if !isMacro(call) // FIXME macro implementations can drop Inlined nodes. We should reinsert them after macro expansion based on the positions of the trees + && !isBootstrappedPredefWithPatchedMethods(call) // FIXME The patched symbol has a different source as the definition of Predef. Solution: define them directly in `Predef`s TASTy and do not patch (see #19231). + then traverse(expansion)(using inlineContext(tree).withSource(sources.head)) sources = sources.tail case _ => traverseChildren(tree) @@ -59,12 +61,17 @@ class YCheckPositions extends Phase { case _ => } + private def isBootstrappedPredefWithPatchedMethods(call: Tree)(using Context) = + val sym = call.symbol + (sym.is(Inline) && sym.owner == defn.ScalaPredefModuleClass && sym.owner.is(Scala2Tasty)) + || (sym == defn.ScalaPredefModuleClass && sym.is(Scala2Tasty)) + private def isMacro(call: Tree)(using Context) = call.symbol.is(Macro) || - (call.symbol.isClass && call.tpe.derivesFrom(defn.MacroAnnotationClass)) || - // In 3.0-3.3, the call of a macro after typer is encoded as a Select while other inlines are Ident. - // In those versions we kept the reference to the top-level class instead of the methods. - (!(ctx.phase <= postTyperPhase) && call.symbol.isClass && call.isInstanceOf[Select]) + (call.symbol.isClass && call.tpe.derivesFrom(defn.MacroAnnotationClass)) || + // The call of a macro after typer is encoded as a Select while other inlines are Ident + // TODO remove this distinction once Inline nodes of expanded macros can be trusted (also in Inliner.inlineCallTrace) + (!(ctx.phase <= postTyperPhase) && call.isInstanceOf[Select]) }