diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index b273bbf01e95..08151243ca20 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -673,6 +673,9 @@ object Trees { */ case class Inlined[+T <: Untyped] private[ast] (call: tpd.Tree, bindings: List[MemberDef[T]], expansion: Tree[T])(implicit @constructorOnly src: SourceFile) extends Tree[T] { + + def inlinedFromOuterScope: Boolean = call.isEmpty + type ThisTree[+T <: Untyped] = Inlined[T] override def isTerm = expansion.isTerm override def isType = expansion.isType @@ -1479,7 +1482,7 @@ object Trees { * innermost enclosing call for which the inlined version is currently * processed. */ - protected def inlineContext(call: tpd.Tree)(using Context): Context = ctx + protected def inlineContext(tree: Inlined)(using Context): Context = ctx /** The context to use when mapping or accumulating over a tree */ def localCtx(tree: Tree)(using Context): Context @@ -1549,8 +1552,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) => @@ -1693,8 +1696,8 @@ object Trees { this(this(this(x, block), handler), finalizer) case SeqLiteral(elems, elemtpt) => this(this(x, elems), elemtpt) - case Inlined(call, bindings, expansion) => - this(this(x, bindings), expansion)(using inlineContext(call)) + case tree @ Inlined(call, bindings, expansion) => + 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 0d3085f13f1e..eac7c98f2199 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -1392,17 +1392,17 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { * 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 = { + override def inlineContext(tree: Inlined)(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 + if tree.inlinedFromOuterScope then oldIC match case t1 :: ts2 => ts2 case _ => oldIC else - call :: oldIC + tree.call :: oldIC val ctx1 = ctx.fresh.setProperty(InlinedCalls, newIC) if oldIC.isEmpty then ctx1.setProperty(InlinedTrees, new Counter) else ctx1 diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 499dc88a955a..93d15eca265d 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -528,12 +528,12 @@ class TreePickler(pickler: TastyPickler) { case SeqLiteral(elems, elemtpt) => writeByte(REPEATED) withLength { pickleTree(elemtpt); elems.foreach(pickleTree) } - case Inlined(call, bindings, expansion) => + case tree @ Inlined(call, bindings, expansion) => writeByte(INLINED) bindings.foreach(preRegister) withLength { pickleTree(expansion) - if (!call.isEmpty) pickleTree(call) + if (!tree.inlinedFromOuterScope) pickleTree(call) bindings.foreach { b => assert(b.isInstanceOf[DefDef] || b.isInstanceOf[ValDef]) pickleTree(b) diff --git a/compiler/src/dotty/tools/dotc/inlines/InlineReducer.scala b/compiler/src/dotty/tools/dotc/inlines/InlineReducer.scala index ebb76e9e9bf9..2dbfd9117f48 100644 --- a/compiler/src/dotty/tools/dotc/inlines/InlineReducer.scala +++ b/compiler/src/dotty/tools/dotc/inlines/InlineReducer.scala @@ -342,8 +342,8 @@ class InlineReducer(inliner: Inliner)(using Context): } case Alternative(pats) => pats.exists(reducePattern(caseBindingMap, scrut, _)) - case Inlined(EmptyTree, Nil, ipat) => - reducePattern(caseBindingMap, scrut, ipat) + case tree: Inlined if tree.inlinedFromOuterScope => + reducePattern(caseBindingMap, scrut, tree.expansion) case _ => false } } diff --git a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala index 87ef7cb93e76..608ac311a410 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala @@ -129,7 +129,7 @@ object Inliner: new InlinerMap(typeMap, treeMap, oldOwners, newOwners, substFrom, substTo) override def transformInlined(tree: Inlined)(using Context) = - if tree.call.isEmpty then + if tree.inlinedFromOuterScope then tree.expansion match case expansion: TypeTree => expansion case _ => tree @@ -549,7 +549,7 @@ class Inliner(val call: tpd.Tree)(using Context): val inlineTyper = new InlineTyper(ctx.reporter.errorCount) - val inlineCtx = inlineContext(call).fresh.setTyper(inlineTyper).setNewScope + val inlineCtx = inlineContext(Inlined(call, Nil, ref(defn.Predef_undefined))).fresh.setTyper(inlineTyper).setNewScope def inlinedFromOutside(tree: Tree)(span: Span): Tree = Inlined(EmptyTree, Nil, tree)(using ctx.withSource(inlinedMethod.topLevelClass.source)).withSpan(span) @@ -1049,7 +1049,7 @@ class Inliner(val call: tpd.Tree)(using Context): } val inlinedNormalizer = new TreeMap { override def transform(tree: tpd.Tree)(using Context): tpd.Tree = tree match { - case Inlined(EmptyTree, Nil, expr) if enclosingInlineds.isEmpty => transform(expr) + case tree @ Inlined(_, Nil, expr) if tree.inlinedFromOuterScope && enclosingInlineds.isEmpty => transform(expr) case _ => super.transform(tree) } } diff --git a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala index bcc10ffa6db8..6c9e387b5c8c 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala @@ -101,7 +101,7 @@ object Inlines: override def transform(t: Tree)(using Context) = if call.span.exists then t match - case Inlined(t, Nil, expr) if t.isEmpty => expr + case t @ Inlined(_, Nil, expr) if t.inlinedFromOuterScope => expr case _ if t.isEmpty => t case _ => super.transform(t.withSpan(call.span)) else t diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index b2fce4c793dc..ff09a6084136 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -535,7 +535,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case tree @ Inlined(call, bindings, body) => val bodyText = if bindings.isEmpty then toText(body) else blockText(bindings :+ body) if homogenizedView || !ctx.settings.XprintInline.value then bodyText - else if call.isEmpty then stringText("{{") ~ stringText("/* inlined from outside */") ~ bodyText ~ stringText("}}") + else if tree.inlinedFromOuterScope then stringText("{{") ~ stringText("/* inlined from outside */") ~ bodyText ~ stringText("}}") else keywordText("{{") ~ keywordText("/* inlined from ") ~ toText(call) ~ keywordText(" */") ~ bodyText ~ keywordText("}}") case tpt: untpd.DerivedTypeTree => "" 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/sbt/ExtractDependencies.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala index 5e7bedba5e4b..15af7ee1ed18 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala @@ -388,10 +388,10 @@ private class ExtractDependenciesCollector extends tpd.TreeTraverser { thisTreeT } tree match { - case Inlined(call, _, _) if !call.isEmpty => + case tree: Inlined if !tree.inlinedFromOuterScope => // The inlined call is normally ignored by TreeTraverser but we need to // record it as a dependency - traverse(call) + traverse(tree.call) case vd: ValDef if vd.symbol.is(ModuleVal) => // Don't visit module val case t: Template if t.symbol.owner.is(ModuleClass) => diff --git a/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala b/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala index ed3532213ad0..58c3cd7c65ed 100644 --- a/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala +++ b/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala @@ -396,7 +396,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: Quote => diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 1d9493e6b1f7..b2294564dc1d 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -363,12 +363,12 @@ 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)) val callTrace = Inlines.inlineCallTrace(call.symbol, pos)(using ctx.withSource(pos.source)) - cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(using inlineContext(call))) + cpy.Inlined(tree)(callTrace, 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/Recheck.scala b/compiler/src/dotty/tools/dotc/transform/Recheck.scala index 7ebb8dd17045..0904a8772a52 100644 --- a/compiler/src/dotty/tools/dotc/transform/Recheck.scala +++ b/compiler/src/dotty/tools/dotc/transform/Recheck.scala @@ -322,7 +322,7 @@ abstract class Recheck extends Phase, SymTransformer: recheckBlock(tree.stats, tree.expr, pt) def recheckInlined(tree: Inlined, pt: Type)(using Context): Type = - recheckBlock(tree.bindings, tree.expansion, pt)(using inlineContext(tree.call)) + recheckBlock(tree.bindings, tree.expansion, pt)(using inlineContext(tree)) def recheckIf(tree: If, pt: Type)(using Context): Type = recheck(tree.cond, defn.BooleanType) diff --git a/compiler/src/dotty/tools/dotc/transform/Splicer.scala b/compiler/src/dotty/tools/dotc/transform/Splicer.scala index 741c770e2c77..c870336995f0 100644 --- a/compiler/src/dotty/tools/dotc/transform/Splicer.scala +++ b/compiler/src/dotty/tools/dotc/transform/Splicer.scala @@ -245,7 +245,7 @@ object Splicer { case expr: Ident if expr.symbol.isAllOf(InlineByNameProxy) => // inline proxy for by-name parameter expr.symbol.defTree.asInstanceOf[DefDef].rhs - case Inlined(EmptyTree, _, body1) => body1 + case tree: Inlined if tree.inlinedFromOuterScope => tree.expansion case _ => body } new ExprImpl(Inlined(EmptyTree, Nil, QuoteUtils.changeOwnerOfTree(body1, ctx.owner)).withSpan(body1.span), SpliceScope.getCurrent) diff --git a/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala b/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala index 8080a7c911b3..3cf74ee3fdb3 100644 --- a/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala +++ b/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala @@ -38,17 +38,17 @@ class YCheckPositions extends Phase { // Recursivlely check children while keeping track of current source reporting.trace(i"check pos ${tree.getClass} ${tree.source} ${sources.head} $tree") { tree match { - case Inlined(EmptyTree, bindings, expansion) => + case tree @ Inlined(_, bindings, expansion) if tree.inlinedFromOuterScope => assert(bindings.isEmpty) val old = sources sources = old.tail - traverse(expansion)(using inlineContext(EmptyTree).withSource(sources.head)) + traverse(expansion)(using inlineContext(tree).withSource(sources.head)) sources = old - case Inlined(call, bindings, expansion) => + case tree @ Inlined(call, bindings, expansion) => // bindings.foreach(traverse(_)) // TODO check inline proxies (see tests/tun/lst) 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)) + traverse(expansion)(using inlineContext(tree).withSource(sources.head)) sources = sources.tail case _ => traverseChildren(tree) } diff --git a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala index a1f599847114..b8caea58614a 100644 --- a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala +++ b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala @@ -95,6 +95,13 @@ class ReTyper(nestingLevel: Int = 0) extends Typer(nestingLevel) with ReChecking override def typedUnApply(tree: untpd.Apply, selType: Type)(using Context): Tree = typedApply(tree, selType) + override def typedInlined(tree: untpd.Inlined, pt: Type)(using Context): Tree = { + val (bindings1, exprCtx) = typedBlockStats(tree.bindings) + val expansion1 = typed(tree.expansion, pt)(using inlineContext(promote(tree))(using exprCtx)) + untpd.cpy.Inlined(tree)(tree.call, bindings1.asInstanceOf[List[MemberDef]], expansion1) + .withType(avoidingType(expansion1, bindings1)) + } + override def typedQuote(tree: untpd.Quote, pt: Type)(using Context): Tree = assertTyped(tree) val body1 = typed(tree.body, promote(tree).bodyType)(using quoteContext) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index c57de66f5bea..47dadf29a2af 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2092,12 +2092,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) 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)) - assignType(cpy.Inlined(tree)(tree.call, bindings1.asInstanceOf[List[MemberDef]], expansion1), - bindings1, expansion1) - } + def typedInlined(tree: untpd.Inlined, pt: Type)(using Context): Tree = + throw new UnsupportedOperationException("cannot type check a Inlined node") def completeTypeTree(tree: untpd.TypeTree, pt: Type, original: untpd.Tree)(using Context): TypeTree = tree.withSpan(original.span).withAttachmentsFrom(original)