diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index cf3b1359cfe6..d12a85150f6f 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -574,8 +574,9 @@ object Trees { /** A tree representing inlined code. * - * @param call Info about the original call that was inlined - * Until PostTyper, this is the full call, afterwards only + * @param call Tree representing the original call that was inlined. + * If EmptyTree: this represents an argument actual tree. + * Otherwise: Until PostTyper, this is the full call, afterwards only * 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. @@ -587,6 +588,8 @@ object Trees { * The reason to keep `bindings` separate is because they are typed in a * different context: `bindings` represent the arguments to the inlined * call, whereas `expansion` represents the body of the inlined function. + * Call argument trees (whether kept in `bindings` or inlined in the body) + * are typed in the caller's context. */ case class Inlined[-T >: Untyped] private[ast] (call: tpd.Tree, bindings: List[MemberDef[T]], expansion: Tree[T]) extends Tree[T] { diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index f4f4535931c4..169d9e67c440 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -1079,15 +1079,24 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { } } + //inlineContext, enclosingInlineds, sourceFile and Decorators.sourcePos work closely together. + /** A key to be used in a context property that tracks enclosing inlined calls */ private val InlinedCalls = new Property.Key[List[Tree]] - /** 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. + /** Record an enclosing inlined call in enclosingInlineds, and produces the context for visiting + * Inlined(call, ...). + * + * Invariants: + * - enclosingInlineds never contains EmptyTree nodes. + * - if enclosingInlineds.nonEmpty, the current tree comes from the file *defining* enclosingInlineds.head.symbol; + * this is exploited in e.g. Decorators.sourcePos. + * + * Arguments of inlined calls (enclosed in Inlined(EmptyTree, ...)) come instead from the call-site, so + * inlineContext(EmptyTree) pops the enclosing call. */ override def inlineContext(call: Tree)(implicit ctx: Context): Context = { - // We assume enclosingInlineds is already normalized, and only process the new call with the head. + // enclosingInlineds is already normalized, so we only process the new call with the head. val oldIC = enclosingInlineds val newIC = (call, oldIC) match { case (t, t1 :: ts2) if t.isEmpty => @@ -1106,7 +1115,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { /** The source file where the symbol of the `inline` method referred to by `call` * is defined */ - def sourceFile(call: Tree)(implicit ctx: Context) = { + def sourceFile(call: Tree)(implicit ctx: Context): SourceFile = { val file = call.symbol.sourceFile val encoding = ctx.settings.encoding.value if (file != null && file.exists) new SourceFile(file, Codec(encoding)) else NoSource diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 7ae4192c7bd6..41f97ab21a6f 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -385,8 +385,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case SeqLiteral(elems, elemtpt) => "[" ~ toTextGlobal(elems, ",") ~ " : " ~ toText(elemtpt) ~ "]" case tree @ Inlined(call, bindings, body) => - (("/* inlined from " ~ toText(call) ~ " */ ") `provided` - !call.isEmpty && !homogenizedView && !ctx.settings.YshowNoInline.value) ~ + ((if (!call.isEmpty) "/* inlined from " ~ toText(call) ~ " */ " else "/* inline arg */ ": Text) `provided` + !homogenizedView && !ctx.settings.YshowNoInline.value) ~ blockText(bindings :+ body) case tpt: untpd.DerivedTypeTree => ""