From 5a46d19dde76b739f6672c9b6f57355cfd38159a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 15 Sep 2016 15:39:57 +0200 Subject: Handle inlining in inlining arguments We got unbound symbols before because a TreeTypeMap would copy a tree of an inline DefDef but would not adapt the inline body stored in the @inline annotation of the DefDef to point to the updated tree. --- src/dotty/tools/dotc/ast/TreeTypeMap.scala | 9 ++++- src/dotty/tools/dotc/ast/untpd.scala | 4 +- src/dotty/tools/dotc/core/tasty/TreePickler.scala | 2 +- src/dotty/tools/dotc/typer/Inliner.scala | 47 +++++++++++++++-------- src/dotty/tools/dotc/typer/Typer.scala | 5 +-- 5 files changed, 44 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/dotty/tools/dotc/ast/TreeTypeMap.scala b/src/dotty/tools/dotc/ast/TreeTypeMap.scala index 0593e8159..6d0c7d8e3 100644 --- a/src/dotty/tools/dotc/ast/TreeTypeMap.scala +++ b/src/dotty/tools/dotc/ast/TreeTypeMap.scala @@ -6,6 +6,8 @@ import core._ import Types._, Contexts._, Constants._, Names._, Flags._ import SymDenotations._, Symbols._, Annotations._, Trees._, Symbols._ import Denotations._, Decorators._ +import typer.Inliner +import config.Printers.inlining import dotty.tools.dotc.transform.SymUtils._ /** A map that applies three functions and a substitution together to a tree and @@ -92,7 +94,12 @@ final class TreeTypeMap( case ddef @ DefDef(name, tparams, vparamss, tpt, _) => val (tmap1, tparams1) = transformDefs(ddef.tparams) val (tmap2, vparamss1) = tmap1.transformVParamss(vparamss) - cpy.DefDef(ddef)(name, tparams1, vparamss1, tmap2.transform(tpt), tmap2.transform(ddef.rhs)) + val res = cpy.DefDef(ddef)(name, tparams1, vparamss1, tmap2.transform(tpt), tmap2.transform(ddef.rhs)) + if (Inliner.hasBodyToInline(res.symbol)) { + inlining.println(i"update inline body ${res.symbol}") + Inliner.updateInlineBody(res.symbol, res.rhs) + } + res case blk @ Block(stats, expr) => val (tmap1, stats1) = transformDefs(stats) val expr1 = tmap1.transform(expr) diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala index a0a353c13..cc7cefbac 100644 --- a/src/dotty/tools/dotc/ast/untpd.scala +++ b/src/dotty/tools/dotc/ast/untpd.scala @@ -20,7 +20,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { override def isType = op.isTypeName } - /** A typed subtree of an untyped tree needs to be wrapped in a TypedSlice */ + /** A typed subtree of an untyped tree needs to be wrapped in a TypedSlice + * @param owner The current owner at the time the tree was defined + */ abstract case class TypedSplice(tree: tpd.Tree)(val owner: Symbol) extends ProxyTree { def forwardTo = tree } diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 12ab050f6..99a3ff85c 100644 --- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -572,7 +572,7 @@ class TreePickler(pickler: TastyPickler) { def pickle(trees: List[Tree])(implicit ctx: Context) = { trees.foreach(tree => if (!tree.isEmpty) pickleTree(tree)) - assert(forwardSymRefs.isEmpty, i"unresolved symbols: ${forwardSymRefs.keySet.toList}%, % when pickling $trees%\n %") + assert(forwardSymRefs.isEmpty, i"unresolved symbols: ${forwardSymRefs.keySet.toList}%, % when pickling ${ctx.source}") } def compactify() = { diff --git a/src/dotty/tools/dotc/typer/Inliner.scala b/src/dotty/tools/dotc/typer/Inliner.scala index e9c054ff2..ef67384ff 100644 --- a/src/dotty/tools/dotc/typer/Inliner.scala +++ b/src/dotty/tools/dotc/typer/Inliner.scala @@ -214,17 +214,18 @@ object Inliner { /** The accessor defs to non-public members which need to be defined * together with the inline method */ - def removeAccessors(implicit ctx: Context): List[MemberDef] = { + def accessors(implicit ctx: Context): List[MemberDef] = { ensureEvaluated() - val res = myAccessors.toList - myAccessors.clear() - res + myAccessors.toList } } /** A key to be used in an attachment for `@inline` annotations */ private val InlineInfo = new Property.Key[InlineInfo] + /** A key to be used in an attachment for `@inline` annotations */ + private val InlineBody = new Property.Key[Tree] + /** A key to be used in a context property that tracks enclosing inlined calls */ private val InlinedCalls = new Property.Key[List[Tree]] // to be used in context @@ -239,37 +240,51 @@ object Inliner { */ def registerInlineInfo( sym: SymDenotation, treeExpr: Context => Tree, inlineCtxFn: Context => Context)(implicit ctx: Context): Unit = { + val inlineAnnotTree = sym.unforcedAnnotation(defn.InlineAnnot).get.tree + if (inlineAnnotTree.getAttachment(InlineBody).isEmpty) + inlineAnnotTree.getAttachment(InlineInfo) match { + case Some(inlineInfo) if inlineInfo.isEvaluated => // keep existing attachment + case _ => + if (!ctx.isAfterTyper) + inlineAnnotTree.putAttachment(InlineInfo, new InlineInfo(treeExpr, inlineCtxFn)) + } + } + + /** Register an evaluated inline body for `sym` */ + def updateInlineBody(sym: SymDenotation, body: Tree)(implicit ctx: Context): Unit = { val inlineAnnot = sym.unforcedAnnotation(defn.InlineAnnot).get - inlineAnnot.tree.getAttachment(InlineInfo) match { - case Some(inlineInfo) if inlineInfo.isEvaluated => // keep existing attachment - case _ => - if (!ctx.isAfterTyper) - inlineAnnot.tree.putAttachment(InlineInfo, new InlineInfo(treeExpr, inlineCtxFn)) - } + assert(inlineAnnot.tree.putAttachment(InlineBody, body).isDefined) } /** Optionally, the inline info attached to the `@inline` annotation of `sym`. */ private def inlineInfo(sym: SymDenotation)(implicit ctx: Context): Option[InlineInfo] = sym.getAnnotation(defn.InlineAnnot).get.tree.getAttachment(InlineInfo) - /** Definition is an inline method with a known body to inline (note: definitions coming + /** Optionally, the inline body attached to the `@inline` annotation of `sym`. */ + private def inlineBody(sym: SymDenotation)(implicit ctx: Context): Option[Tree] = + sym.getAnnotation(defn.InlineAnnot).get.tree.getAttachment(InlineBody) + + /** Definition is an inline method with a known body to inline (note: definitions coming * from Scala2x class files might be `@inline`, but still lack that body. */ def hasBodyToInline(sym: SymDenotation)(implicit ctx: Context): Boolean = - sym.isInlineMethod && inlineInfo(sym).isDefined + sym.isInlineMethod && (inlineInfo(sym).isDefined || inlineBody(sym).isDefined) /** The body to inline for method `sym`. * @pre hasBodyToInline(sym) */ def bodyToInline(sym: SymDenotation)(implicit ctx: Context): Tree = - inlineInfo(sym).get.body + inlineInfo(sym).map(_.body).getOrElse(inlineBody(sym).get) /** The accessors to non-public members needed by the inlinable body of `sym`. * @pre hasBodyToInline(sym) */ - - def removeInlineAccessors(sym: SymDenotation)(implicit ctx: Context): List[MemberDef] = - inlineInfo(sym).get.removeAccessors + def removeInlineAccessors(sym: SymDenotation)(implicit ctx: Context): List[MemberDef] = { + val inlineAnnotTree = sym.getAnnotation(defn.InlineAnnot).get.tree + val inlineInfo = inlineAnnotTree.removeAttachment(InlineInfo).get + inlineAnnotTree.putAttachment(InlineBody, inlineInfo.body) + inlineInfo.accessors + } /** Try to inline a call to a `@inline` method. Fail with error if the maximal * inline depth is exceeded. diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 4c7d1c50d..885bc56d6 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -1359,10 +1359,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case tree1: TypeTree => tree1 // no change owner necessary here ... case tree1: Ident => tree1 // ... or here case tree1 => - if (ctx.owner ne tree.owner) { - println(i"changing owner of $tree1 from ${tree.owner} to ${ctx.owner}") - tree1.changeOwner(tree.owner, ctx.owner) - } + if (ctx.owner ne tree.owner) tree1.changeOwner(tree.owner, ctx.owner) else tree1 } -- cgit v1.2.3