diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index 11d72d1d2993..952ccf2e6b7e 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -37,7 +37,6 @@ class Compiler { /** Phases dealing with the frontend up to trees ready for TASTY pickling */ protected def frontendPhases: List[List[Phase]] = List(new FrontEnd) :: // Compiler frontend: scanner, parser, namer, typer - List(new YCheckPositions) :: // YCheck positions List(new sbt.ExtractDependencies) :: // Sends information on classes' dependencies to sbt via callbacks List(new semanticdb.ExtractSemanticDB) :: // Extract info into .semanticdb files List(new PostTyper) :: // Additional checks and cleanups after type checking diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 53b072fdeec8..dbb03e44121c 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -1242,11 +1242,9 @@ object Trees { protected def skipTransform(tree: Tree)(using Context): Boolean = false /** For untyped trees, this is just the identity. - * For typed trees, a context derived form `ctx` that records `call` as the - * innermost enclosing call for which the inlined version is currently - * processed. + * For typed trees, this records the position of an enclosing inlined position */ - protected def inlineContext(call: Tree)(using Context): Context = ctx + protected def inlineContext(pos: SrcPos)(using Context): Context = ctx abstract class TreeMap(val cpy: TreeCopier = inst.cpy) { self => def transform(tree: Tree)(using Context): Tree = { @@ -1304,7 +1302,7 @@ object Trees { 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))) + cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)(using inlineContext(tree))) case TypeTree() => tree case SingletonTypeTree(ref) => @@ -1442,7 +1440,7 @@ object Trees { case SeqLiteral(elems, elemtpt) => this(this(x, elems), elemtpt) case Inlined(call, bindings, expansion) => - this(this(x, bindings), expansion)(using inlineContext(call)) + this(this(x, bindings), expansion)(using inlineContext(tree)) case TypeTree() => x case SingletonTypeTree(ref) => diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index d7e0871dc087..f53389f24541 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -7,7 +7,7 @@ import typer.ProtoTypes import transform.SymUtils._ import transform.TypeUtils._ import core._ -import util.Spans._, Types._, Contexts._, Constants._, Names._, Flags._, NameOps._ +import util.Spans._, util.SrcPos, Types._, Contexts._, Constants._, Names._, Flags._, NameOps._ import Symbols._, StdNames._, Annotations._, Trees._, Symbols._ import Decorators._, DenotTransformers._ import collection.{immutable, mutable} @@ -1232,7 +1232,7 @@ 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 = Property.Key[List[Tree]]() + private val InlinedCalls = Property.Key[List[SrcPos]]() /** A key to be used in a context property that tracks the number of inlined trees */ private val InlinedTrees = Property.Key[Counter]() @@ -1240,21 +1240,11 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { var count: Int = 0 } - /** Record an enclosing inlined call. - * 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)(using Context): Context = { + /** Record an enclosing inlined positions. */ + override def inlineContext(pos: SrcPos)(using Context): Context = { // We assume enclosingInlineds is already normalized, and only process the new call with the head. val oldIC = enclosingInlineds - - val newIC = - if call.isEmpty then - oldIC match - case t1 :: ts2 => ts2 - case _ => oldIC - else - call :: oldIC + val newIC = pos :: oldIC val ctx1 = ctx.fresh.setProperty(InlinedCalls, newIC) if oldIC.isEmpty then ctx1.setProperty(InlinedTrees, new Counter) else ctx1 @@ -1262,7 +1252,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { /** All enclosing calls that are currently inlined, from innermost to outermost. */ - def enclosingInlineds(using Context): List[Tree] = + def enclosingInlineds(using Context): List[SrcPos] = ctx.property(InlinedCalls).getOrElse(Nil) /** Record inlined trees */ diff --git a/compiler/src/dotty/tools/dotc/quoted/MacroExpansion.scala b/compiler/src/dotty/tools/dotc/quoted/MacroExpansion.scala index 90a208814f2a..e4ac17adf3d1 100644 --- a/compiler/src/dotty/tools/dotc/quoted/MacroExpansion.scala +++ b/compiler/src/dotty/tools/dotc/quoted/MacroExpansion.scala @@ -13,7 +13,7 @@ object MacroExpansion { def position(using Context): Option[SourcePosition] = ctx.property(MacroExpansionPosition) - def context(inlinedFrom: tpd.Tree)(using Context): Context = - ctx.fresh.setProperty(MacroExpansionPosition, SourcePosition(inlinedFrom.source, inlinedFrom.span)).setTypeAssigner(new Typer).withSource(inlinedFrom.source) + def context(inlinedFrom: SourcePosition)(using Context): Context = + ctx.fresh.setProperty(MacroExpansionPosition, inlinedFrom).setTypeAssigner(new Typer).withSource(inlinedFrom.source) } diff --git a/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala b/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala index a6aeb0d6326d..059c1d080cdb 100644 --- a/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala +++ b/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala @@ -32,7 +32,8 @@ object PickledQuotes { def pickleQuote(tree: Tree)(using Context): PickledQuote = if (ctx.reporter.hasErrors) Nil else { - assert(!tree.isInstanceOf[Hole]) // Should not be pickled as it represents `'{$x}` which should be optimized to `x` + // FIXME handle new optimization opportunities. Previousliy we got some `Inlined(EmptyTree, Nil, Hole(...))` that did not get optimized + // assert(!tree.isInstanceOf[Hole]) // Should not be pickled as it represents `'{$x}` which should be optimized to `x` val pickled = pickle(tree) TastyString.pickle(pickled) } @@ -56,11 +57,9 @@ object PickledQuotes { val tastyBytes = TastyString.unpickle(tasty) val unpickled = withMode(Mode.ReadPositions)( unpickle(tastyBytes, splices, isType = false)) - val Inlined(call, Nil, expnasion) = unpickled - val inlineCtx = inlineContext(call) - val expansion1 = spliceTypes(expnasion, splices)(using inlineCtx) - val expansion2 = spliceTerms(expansion1, splices)(using inlineCtx) - cpy.Inlined(unpickled)(call, Nil, expansion2) + val expansion1 = spliceTypes(unpickled, splices) + val expansion2 = spliceTerms(expansion1, splices) + cpy.Inlined(unpickled)(EmptyTree, Nil, expansion2) } /** Unpickle the tree contained in the TastyType */ diff --git a/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala b/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala index 490950b06ba5..2f28f4e22866 100644 --- a/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala +++ b/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala @@ -26,7 +26,7 @@ object QuoteContextImpl { new QuoteContextImpl(ctx) def showTree(tree: tpd.Tree)(using Context): String = { - val qctx = QuoteContextImpl()(using MacroExpansion.context(tree)) + val qctx = QuoteContextImpl()(using MacroExpansion.context(tree.sourcePos)) val syntaxHighlight = if (ctx.settings.color.value == "always") SyntaxHighlight.ANSI else SyntaxHighlight.plain diff --git a/compiler/src/dotty/tools/dotc/report.scala b/compiler/src/dotty/tools/dotc/report.scala index 61e5dde75ad6..3923178f1061 100644 --- a/compiler/src/dotty/tools/dotc/report.scala +++ b/compiler/src/dotty/tools/dotc/report.scala @@ -115,8 +115,8 @@ object report: if (ctx.settings.Ydebug.value) warning(msg, pos) private def addInlineds(pos: SrcPos)(using Context): SourcePosition = - def recur(pos: SourcePosition, inlineds: List[Trees.Tree[?]]): SourcePosition = inlineds match - case inlined :: inlineds1 => pos.withOuter(recur(inlined.sourcePos, inlineds1)) + def recur(pos: SourcePosition, inlineds: List[SrcPos]): SourcePosition = inlineds match + case inlined :: inlineds1 => pos.sourcePos.withOuter(recur(inlined.sourcePos, inlineds1)) case Nil => pos recur(pos.sourcePos, tpd.enclosingInlineds) diff --git a/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala b/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala index 385d02638b9f..f18a73c3394f 100644 --- a/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala +++ b/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala @@ -394,7 +394,7 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase { case tree: Inlined => inContext(prepInlined(tree, start)(using outerCtx)) { val bindings = transformSpecificTrees(tree.bindings, start) - val expansion = transformTree(tree.expansion, start)(using inlineContext(tree.call)) + val expansion = transformTree(tree.expansion, start)(using inlineContext(tree)) goInlined(cpy.Inlined(tree)(tree.call, bindings, expansion), start) } case tree: Return => diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 5ed99adaff37..8189acb06101 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -289,9 +289,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase super.transform(tree1) } case Inlined(call, bindings, expansion) if !call.isEmpty => - val pos = call.sourcePos - val callTrace = Inliner.inlineCallTrace(call.symbol, pos)(using ctx.withSource(pos.source)) - cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(using inlineContext(call))) + cpy.Inlined(tree)(EmptyTree, transformSub(bindings), transform(expansion)(using inlineContext(tree))) case templ: Template => withNoCheckNews(templ.parents.flatMap(newPart)) { forwardParamAccessors(templ) diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index 7ba7130d62cf..ec902fe64c92 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -132,14 +132,8 @@ class ReifyQuotes extends MacroTransform { } else { val (body1, splices) = nested(isQuote = true).splitQuote(body)(using quoteContext) - if (level == 0) { - val body2 = - if (body1.isType) body1 - else Inlined(Inliner.inlineCallTrace(ctx.owner, quote.sourcePos), Nil, body1) - pickledQuote(body2, splices, body.tpe, isType).withSpan(quote.span) - } - else - body + if level == 0 then pickledQuote(body1, splices, body.tpe, isType).withSpan(quote.span) + else body } } diff --git a/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala b/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala deleted file mode 100644 index 3f5da6bab7e7..000000000000 --- a/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala +++ /dev/null @@ -1,62 +0,0 @@ -package dotty.tools.dotc -package transform - -import dotty.tools.dotc.ast.Trees._ -import dotty.tools.dotc.ast.{tpd, untpd} -import dotty.tools.dotc.core.Contexts._ -import dotty.tools.dotc.core.Decorators._ -import dotty.tools.dotc.core.Flags._ -import dotty.tools.dotc.core.Phases.{Phase, postTyperPhase} -import dotty.tools.dotc.core.Symbols._ -import dotty.tools.dotc.util.SourceFile - -/** Ycheck inlined positions */ -class YCheckPositions extends Phase { - import tpd._ - - def phaseName: String = "inlinedPositions" - - override def run(using Context): Unit = () // YCheck only - - override def checkPostCondition(tree: Tree)(using Context): Unit = - tree match { - case PackageDef(pid, _) if tree.symbol.owner == defn.RootClass => - new TreeTraverser { - private var sources: List[SourceFile] = ctx.source :: Nil - def traverse(tree: tpd.Tree)(using Context): Unit = { - - // Check current context is correct - assert(ctx.source == sources.head) - if (!tree.isEmpty && !tree.isInstanceOf[untpd.TypedSplice] && ctx.typerState.isGlobalCommittable) - if (!tree.isType) { // TODO also check types, currently we do not add Inlined(EmptyTree, _, _) for types. We should. - val currentSource = sources.head - assert(tree.source == currentSource, i"wrong source set for $tree # ${tree.uniqueId} of ${tree.getClass}, set to ${tree.source} but context had $currentSource") - } - - // Recursivlely check children while keeping track of current source - tree match { - case Inlined(EmptyTree, bindings, expansion) => - assert(bindings.isEmpty) - val old = sources - sources = old.tail - traverse(expansion)(using inlineContext(EmptyTree).withSource(sources.head)) - sources = old - case Inlined(call, bindings, expansion) => - bindings.foreach(traverse(_)) - 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 - traverse(expansion)(using inlineContext(call).withSource(sources.head)) - sources = sources.tail - case _ => traverseChildren(tree) - } - } - }.traverse(tree) - case _ => - } - - private def isMacro(call: Tree)(using Context) = - if (ctx.phase <= postTyperPhase) call.symbol.is(Macro) - else call.isInstanceOf[Select] // 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) -} - diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index c8ce76db64d9..5ea02d6d8773 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -132,7 +132,7 @@ object Inliner { i"""|Maximal number of $reason (${setting.value}) exceeded, |Maybe this is caused by a recursive inline method? |You can use ${setting.name} to change the limit.""", - (tree :: enclosingInlineds).last.srcPos + (tree :: enclosingInlineds).last ) tree2 } @@ -258,19 +258,6 @@ object Inliner { (new Reposition).transform(tree) } - /** 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) - if (callSym.is(Macro)) ref(callSym.topLevelClass.owner).select(callSym.topLevelClass.name).withSpan(pos.span) - else Ident(callSym.topLevelClass.typeRef).withSpan(pos.span) - } - object Intrinsics { import dotty.tools.dotc.reporting.Diagnostic.Error private enum ErrorKind: @@ -724,7 +711,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { val callToReport = if (enclosingInlineds.nonEmpty) enclosingInlineds.last else call val ctxToReport = ctx.outersIterator.dropWhile(enclosingInlineds(using _).nonEmpty).next inContext(ctxToReport) { - report.error(message, callToReport.srcPos) + report.error(message, callToReport) } case _ => } @@ -1431,8 +1418,8 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { if suspendable then ctx.compilationUnit.suspend() // this throws a SuspendException - val evaluatedSplice = inContext(quoted.MacroExpansion.context(inlinedFrom)) { - Splicer.splice(body, inlinedFrom.srcPos, MacroClassLoader.fromContext) + val evaluatedSplice = inContext(quoted.MacroExpansion.context(inlinedFrom.sourcePos)) { + Splicer.splice(body, inlinedFrom, MacroClassLoader.fromContext) } val inlinedNormailizer = new TreeMap { override def transform(tree: tpd.Tree)(using Context): tpd.Tree = tree match { diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 93453c22226b..da63fc9f8c5d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1627,7 +1627,7 @@ class Typer extends Namer def typedInlined(tree: untpd.Inlined, pt: Type)(using Context): Tree = { val (bindings1, exprCtx) = typedBlockStats(tree.bindings) - val expansion1 = typed(tree.expansion, pt)(using inlineContext(tree.call)(using exprCtx)) + val expansion1 = typed(tree.expansion, pt)(using inlineContext(tree)(using exprCtx)) assignType(cpy.Inlined(tree)(tree.call, bindings1.asInstanceOf[List[MemberDef]], expansion1), bindings1, expansion1) } diff --git a/tests/run/i4947b.check b/tests/run/i4947b.check index 183c31bdfc5d..3b564d273eca 100644 --- a/tests/run/i4947b.check +++ b/tests/run/i4947b.check @@ -4,8 +4,8 @@ main1: Test$.main(Test_2.scala:4) main2: Test$.main(Test_2.scala:5) track: Test$.main(Test_2.scala:7) track: Test$.main(Test_2.scala:7) -track: Test$.main(Test_2.scala:8) -track: Test$.main(Test_2.scala:8) +track: Test$.main(Test_2.scala:7) +track: Test$.main(Test_2.scala:7) main3: Test$.main(Test_2.scala:9) main4: Test$.main(Test_2.scala:10) track (i = 0): Test$.main(Test_2.scala:13) @@ -15,22 +15,22 @@ track: Test$.main(Test_2.scala:13) fact: Test$.main(Test_2.scala:13) track (i = 2): Test$.main(Test_2.scala:14) track (i = 2): Test$.main(Test_2.scala:14) -track: Test$.main(Test_2.scala:14) -track: Test$.main(Test_2.scala:14) -fact: Test$.main(Test_2.scala:14) +track: Test$.main(Test_2.scala:13) +track: Test$.main(Test_2.scala:13) +fact: Test$.main(Test_2.scala:13) main1 (i = -1): Test$.main(Test_2.scala:15) main2 (i = -1): Test$.main(Test_2.scala:16) -track (i = 1): Test$.main(Test_2.scala:14) -track (i = 1): Test$.main(Test_2.scala:14) -track: Test$.main(Test_2.scala:14) -track: Test$.main(Test_2.scala:14) -fact: Test$.main(Test_2.scala:14) +track (i = 1): Test$.main(Test_2.scala:13) +track (i = 1): Test$.main(Test_2.scala:13) +track: Test$.main(Test_2.scala:13) +track: Test$.main(Test_2.scala:13) +fact: Test$.main(Test_2.scala:13) main1 (i = -1): Test$.main(Test_2.scala:15) main2 (i = -1): Test$.main(Test_2.scala:16) -track (i = 0): Test$.main(Test_2.scala:14) -track (i = 0): Test$.main(Test_2.scala:14) -track: Test$.main(Test_2.scala:14) -track: Test$.main(Test_2.scala:14) -fact: Test$.main(Test_2.scala:14) +track (i = 0): Test$.main(Test_2.scala:13) +track (i = 0): Test$.main(Test_2.scala:13) +track: Test$.main(Test_2.scala:13) +track: Test$.main(Test_2.scala:13) +fact: Test$.main(Test_2.scala:13) main1 (i = -1): Test$.main(Test_2.scala:15) main2 (i = -1): Test$.main(Test_2.scala:16)