Skip to content

Commit 710791f

Browse files
committed
Move logic from InlineInfo to BodyAnnot
Now that we have BodyAnnot, InlineInfo can be eliminated.
1 parent 8080b75 commit 710791f

File tree

7 files changed

+63
-116
lines changed

7 files changed

+63
-116
lines changed

src/dotty/tools/dotc/ast/TreeTypeMap.scala

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import core._
66
import Types._, Contexts._, Constants._, Names._, Flags._
77
import SymDenotations._, Symbols._, Annotations._, Trees._, Symbols._
88
import Denotations._, Decorators._
9-
import typer.Inliner
109
import config.Printers.inlining
1110
import dotty.tools.dotc.transform.SymUtils._
1211

@@ -95,9 +94,9 @@ final class TreeTypeMap(
9594
val (tmap1, tparams1) = transformDefs(ddef.tparams)
9695
val (tmap2, vparamss1) = tmap1.transformVParamss(vparamss)
9796
val res = cpy.DefDef(ddef)(name, tparams1, vparamss1, tmap2.transform(tpt), tmap2.transform(ddef.rhs))
98-
if (Inliner.hasBodyToInline(res.symbol)) {
99-
inlining.println(i"update inline body ${res.symbol}")
100-
Inliner.updateInlineBody(res.symbol, res.rhs)
97+
res.symbol.transformAnnotations {
98+
case ann: BodyAnnotation => ann.derivedAnnotation(res.rhs)
99+
case ann => ann
101100
}
102101
res
103102
case blk @ Block(stats, expr) =>

src/dotty/tools/dotc/core/Annotations.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ object Annotations {
2626
}
2727
def argumentConstant(i: Int)(implicit ctx: Context): Option[Constant] =
2828
for (ConstantType(c) <- argument(i) map (_.tpe)) yield c
29+
30+
def ensureCompleted(implicit ctx: Context): Unit = tree
2931
}
3032

3133
case class ConcreteAnnotation(t: Tree) extends Annotation {
@@ -44,13 +46,14 @@ object Annotations {
4446

4547
/** An annotation indicating the body of a right-hand side,
4648
* typically of an inline method. Treated specially in
47-
* pickling/unpickling and treecopies
49+
* pickling/unpickling and TypeTreeMaps
4850
*/
4951
abstract class BodyAnnotation extends Annotation {
5052
override def symbol(implicit ctx: Context) = defn.BodyAnnot
5153
override def derivedAnnotation(tree: Tree)(implicit ctx: Context) =
5254
if (tree eq this.tree) this else ConcreteBodyAnnotation(tree)
5355
override def arguments(implicit ctx: Context) = Nil
56+
override def ensureCompleted(implicit ctx: Context) = ()
5457
}
5558

5659
case class ConcreteBodyAnnotation(body: Tree) extends BodyAnnotation {
@@ -68,6 +71,7 @@ object Annotations {
6871
}
6972
myBody
7073
}
74+
def isEvaluated = evaluated
7175
}
7276

7377
object Annotation {

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,12 @@ object SymDenotations {
297297
final def removeAnnotation(cls: Symbol)(implicit ctx: Context): Unit =
298298
annotations = myAnnotations.filterNot(_ matches cls)
299299

300+
/** Remove any annotations with same class as `annot`, and add `annot` */
301+
final def updateAnnotation(annot: Annotation)(implicit ctx: Context): Unit = {
302+
removeAnnotation(annot.symbol)
303+
addAnnotation(annot)
304+
}
305+
300306
/** Add all given annotations to this symbol */
301307
final def addAnnotations(annots: TraversableOnce[Annotation])(implicit ctx: Context): Unit =
302308
annots.foreach(addAnnotation)

src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, Name
77
import StdNames._, Denotations._, Flags._, Constants._, Annotations._
88
import util.Positions._
99
import ast.{tpd, Trees, untpd}
10-
import typer.Inliner
1110
import Trees._
1211
import Decorators._
1312
import TastyUnpickler._, TastyBuffer._

src/dotty/tools/dotc/typer/Inliner.scala

Lines changed: 45 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -25,44 +25,28 @@ import util.{Property, SourceFile, NoSource}
2525
import collection.mutable
2626
import transform.TypeUtils._
2727

28-
/** Todo wrt inline SIP:
29-
*
30-
* 1. According to Inline SIP, by-name parameters are not hoisted out, but we currently
31-
* do hoist them.
32-
*
33-
* 2. Inline call-by-name parameters are currently ignored. Not sure what the rules should be.
34-
*/
3528
object Inliner {
3629
import tpd._
3730

38-
/** An attachment for inline methods, which contains
39-
*
40-
* - the body to inline, as a typed tree
41-
* - the definitions of all needed accessors to non-public members from inlined code
42-
*
43-
* @param treeExpr A function that computes the tree to be inlined, given a context
44-
* This tree may still refer to non-public members.
45-
* @param inlineCtxFn A function that maps the current context to the context in
46-
* which to compute the tree. The resulting context needs
47-
* to have the inlined method as owner.
48-
*
49-
* The reason to use a function rather than a fixed context here
50-
* is to avoid space leaks. InlineInfos can survive multiple runs
51-
* because they might be created as part of an unpickled method
52-
* and consumed only in a future run (or never).
31+
/** A key to be used in a context property that tracks enclosing inlined calls */
32+
private val InlinedCalls = new Property.Key[List[Tree]] // to be used in context
33+
34+
/** Adds accessors accessors for all non-public term members accessed
35+
* from `tree`. Non-public type members are currently left as they are.
36+
* This means that references to a private type will lead to typing failures
37+
* on the code when it is inlined. Less than ideal, but hard to do better (see below).
38+
*
39+
* @return If there are accessors generated, a thicket consisting of the rewritten `tree`
40+
* and all accessors, otherwise the original tree.
5341
*/
54-
private final class InlineInfo(treeExpr: Context => Tree, var inlineCtxFn: Context => Context) {
55-
private val myAccessors = new mutable.ListBuffer[MemberDef]
56-
private var myBody: Tree = _
57-
private var evaluated = false
42+
def makeInlineable(tree: Tree)(implicit ctx: Context) = {
5843

5944
/** A tree map which inserts accessors for all non-public term members accessed
60-
* from inlined code. Non-public type members are currently left as they are.
61-
* This means that references to a provate type will lead to typing failures
62-
* on the code when it is inlined. Less than ideal, but hard to do better (see below).
45+
* from inlined code. Accesors are collected in the `accessors` buffer.
6346
*/
64-
private def prepareForInline(inlineCtx: Context) = new TreeMap {
65-
val inlineMethod = inlineCtx.owner
47+
object addAccessors extends TreeMap {
48+
val inlineMethod = ctx.owner
49+
val accessors = new mutable.ListBuffer[MemberDef]
6650

6751
/** A definition needs an accessor if it is private, protected, or qualified private */
6852
def needsAccessor(sym: Symbol)(implicit ctx: Context) =
@@ -149,7 +133,7 @@ object Inliner {
149133
.appliedToArgss((qual :: Nil) :: argss)
150134
(accessorDef, accessorRef)
151135
}
152-
myAccessors += accessorDef
136+
accessors += accessorDef
153137
inlining.println(i"added inline accessor: $accessorDef")
154138
accessorRef
155139
}
@@ -184,106 +168,61 @@ object Inliner {
184168
}
185169
}
186170

187-
/** Is the inline info evaluated? */
188-
def isEvaluated = evaluated
189-
190-
private def ensureEvaluated()(implicit ctx: Context) =
191-
if (!evaluated) {
192-
evaluated = true // important to set early to prevent overwrites by attachInlineInfo in typedDefDef
193-
val inlineCtx = inlineCtxFn(ctx)
194-
inlineCtxFn = null // null out to avoid space leaks
195-
try {
196-
myBody = treeExpr(inlineCtx)
197-
myBody = prepareForInline(inlineCtx).transform(myBody)(inlineCtx)
198-
inlining.println(i"inlinable body of ${inlineCtx.owner} = $myBody")
199-
}
200-
catch {
201-
case ex: AssertionError =>
202-
println(i"failure while expanding ${inlineCtx.owner}")
203-
throw ex
204-
}
205-
}
206-
else assert(myBody != null)
207-
208-
/** The body to inline */
209-
def body(implicit ctx: Context): Tree = {
210-
ensureEvaluated()
211-
myBody
212-
}
213-
214-
/** The accessor defs to non-public members which need to be defined
215-
* together with the inline method
216-
*/
217-
def accessors(implicit ctx: Context): List[MemberDef] = {
218-
ensureEvaluated()
219-
myAccessors.toList
220-
}
171+
val tree1 = addAccessors.transform(tree)
172+
flatTree(tree1 :: addAccessors.accessors.toList)
221173
}
222174

223-
/** A key to be used in an attachment for `@inline` annotations */
224-
private val InlineInfo = new Property.Key[InlineInfo]
225-
226-
/** A key to be used in a context property that tracks enclosing inlined calls */
227-
private val InlinedCalls = new Property.Key[List[Tree]] // to be used in context
228-
229175
/** Register inline info for given inline method `sym`.
230176
*
231177
* @param sym The symbol denotatioon of the inline method for which info is registered
232178
* @param treeExpr A function that computes the tree to be inlined, given a context
233179
* This tree may still refer to non-public members.
234-
* @param inlineCtxFn A function that maps the current context to the context in
235-
* which to compute the tree. The resulting context needs
180+
* @param ctx The context to use for evaluating `treeExpr`. It needs
236181
* to have the inlined method as owner.
237182
*/
238183
def registerInlineInfo(
239-
sym: SymDenotation, treeExpr: Context => Tree, inlineCtxFn: Context => Context)(implicit ctx: Context): Unit = {
240-
if (sym.unforcedAnnotation(defn.BodyAnnot).isEmpty) {
241-
val inlineAnnotTree = sym.unforcedAnnotation(defn.InlineAnnot).get.tree
242-
inlineAnnotTree.getAttachment(InlineInfo) match {
243-
case Some(inlineInfo) if inlineInfo.isEvaluated => // keep existing attachment
244-
case _ =>
245-
if (!ctx.isAfterTyper)
246-
inlineAnnotTree.putAttachment(InlineInfo, new InlineInfo(treeExpr, inlineCtxFn))
247-
}
184+
sym: SymDenotation, treeExpr: Context => Tree)(implicit ctx: Context): Unit = {
185+
sym.unforcedAnnotation(defn.BodyAnnot) match {
186+
case Some(ann: ConcreteBodyAnnotation) =>
187+
case Some(ann: LazyBodyAnnotation) if ann.isEvaluated =>
188+
case _ =>
189+
if (!ctx.isAfterTyper) {
190+
val inlineCtx = ctx
191+
sym.updateAnnotation(LazyBodyAnnotation { _ =>
192+
implicit val ctx: Context = inlineCtx
193+
val tree1 = treeExpr(ctx)
194+
makeInlineable(tree1)
195+
})
196+
}
248197
}
249198
}
250199

251-
/** Register an evaluated inline body for `sym` */
252-
def updateInlineBody(sym: SymDenotation, body: Tree)(implicit ctx: Context): Unit = {
253-
assert(sym.unforcedAnnotation(defn.BodyAnnot).isDefined)
254-
sym.removeAnnotation(defn.BodyAnnot)
255-
sym.addAnnotation(ConcreteBodyAnnotation(body))
256-
}
257-
258-
/** Optionally, the inline info attached to the `@inline` annotation of `sym`. */
259-
private def inlineInfo(sym: SymDenotation)(implicit ctx: Context): Option[InlineInfo] =
260-
sym.getAnnotation(defn.InlineAnnot).get.tree.getAttachment(InlineInfo)
261-
262-
/** Optionally, the inline body attached to the `@inline` annotation of `sym`. */
263-
private def inlineBody(sym: SymDenotation)(implicit ctx: Context): Option[Tree] =
264-
sym.getAnnotation(defn.BodyAnnot).map(_.tree)
265-
266-
/** Definition is an inline method with a known body to inline (note: definitions coming
200+
/** `sym` has an inline method with a known body to inline (note: definitions coming
267201
* from Scala2x class files might be `@inline`, but still lack that body.
268202
*/
269203
def hasBodyToInline(sym: SymDenotation)(implicit ctx: Context): Boolean =
270-
sym.isInlineMethod && (inlineInfo(sym).isDefined || inlineBody(sym).isDefined)
204+
sym.isInlineMethod && sym.hasAnnotation(defn.BodyAnnot)
205+
206+
private def bodyAndAccessors(sym: SymDenotation)(implicit ctx: Context): (Tree, List[MemberDef]) =
207+
sym.unforcedAnnotation(defn.BodyAnnot).get.tree match {
208+
case Thicket(body :: accessors) => (body, accessors.asInstanceOf[List[MemberDef]])
209+
case body => (body, Nil)
210+
}
271211

272212
/** The body to inline for method `sym`.
273213
* @pre hasBodyToInline(sym)
274214
*/
275215
def bodyToInline(sym: SymDenotation)(implicit ctx: Context): Tree =
276-
inlineInfo(sym).map(_.body).getOrElse(inlineBody(sym).get)
216+
bodyAndAccessors(sym)._1
277217

278218
/** The accessors to non-public members needed by the inlinable body of `sym`.
219+
* These accessors are dropped as a side effect of calling this method.
279220
* @pre hasBodyToInline(sym)
280221
*/
281222
def removeInlineAccessors(sym: SymDenotation)(implicit ctx: Context): List[MemberDef] = {
282-
val inlineAnnotTree = sym.getAnnotation(defn.InlineAnnot).get.tree
283-
val inlineInfo = inlineAnnotTree.removeAttachment(InlineInfo).get
284-
sym.addAnnotation(ConcreteBodyAnnotation(inlineInfo.body))
285-
assert(sym.getAnnotation(defn.BodyAnnot).isDefined)
286-
inlineInfo.accessors
223+
val (body, accessors) = bodyAndAccessors(sym)
224+
if (accessors.nonEmpty) sym.updateAnnotation(ConcreteBodyAnnotation(body))
225+
accessors
287226
}
288227

289228
/** Try to inline a call to a `@inline` method. Fail with error if the maximal

src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -587,8 +587,8 @@ class Namer { typer: Typer =>
587587
case original: untpd.DefDef =>
588588
Inliner.registerInlineInfo(
589589
denot,
590-
implicit ctx => typedAheadExpr(original).asInstanceOf[tpd.DefDef].rhs,
591-
_ => localContext(denot.symbol))
590+
implicit ctx => typedAheadExpr(original).asInstanceOf[tpd.DefDef].rhs
591+
)(localContext(denot.symbol))
592592
case _ =>
593593
}
594594

src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,7 +1089,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
10891089

10901090
def completeAnnotations(mdef: untpd.MemberDef, sym: Symbol)(implicit ctx: Context): Unit = {
10911091
// necessary to force annotation trees to be computed.
1092-
sym.annotations.foreach(_.tree)
1092+
sym.annotations.foreach(_.ensureCompleted)
10931093
val annotCtx = ctx.outersIterator.dropWhile(_.owner == sym).next
10941094
// necessary in order to mark the typed ahead annotations as definitely typed:
10951095
untpd.modsDeco(mdef).mods.annotations.foreach(typedAnnotation(_)(annotCtx))
@@ -1144,7 +1144,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
11441144

11451145
// Overwrite inline body to make sure it is not evaluated twice
11461146
if (sym.hasAnnotation(defn.InlineAnnot))
1147-
Inliner.registerInlineInfo(sym, _ => rhs1, _ => ctx)
1147+
Inliner.registerInlineInfo(sym, _ => rhs1)
11481148

11491149
if (sym.isAnonymousFunction) {
11501150
// If we define an anonymous function, make sure the return type does not

0 commit comments

Comments
 (0)