aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala7
-rw-r--r--src/dotty/tools/dotc/typer/Inliner.scala45
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala2
4 files changed, 36 insertions, 22 deletions
diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
index b148cced5..1b8434129 100644
--- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
@@ -489,8 +489,11 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
forkAt(templateStart).indexTemplateParams()(localContext(sym))
}
else if (annots.exists(_.symbol == defn.InlineAnnot)) {
- val inlineCtx = localContext(sym).addMode(Mode.ReadPositions)
- Inliner.registerInlineInfo(sym, implicit ctx => forkAt(rhsStart).readTerm())(inlineCtx)
+ Inliner.registerInlineInfo(
+ sym,
+ implicit ctx => forkAt(rhsStart).readTerm(),
+ implicit ctx => localContext(sym).addMode(Mode.ReadPositions))
+ // Previous line avoids space leaks because it does not capture the current context.
}
goto(start)
sym
diff --git a/src/dotty/tools/dotc/typer/Inliner.scala b/src/dotty/tools/dotc/typer/Inliner.scala
index c11001363..44946c37b 100644
--- a/src/dotty/tools/dotc/typer/Inliner.scala
+++ b/src/dotty/tools/dotc/typer/Inliner.scala
@@ -42,11 +42,16 @@ object Inliner {
*
* @param treeExpr A function that computes the tree to be inlined, given a context
* This tree may still refer to non-public members.
- * @param inlineCtx The context in which to compute the tree. This context needs
+ * @param inlineCtxFn A function that maps the current context to the context in
+ * which to compute the tree. The resulting context needs
* to have the inlined method as owner.
+ *
+ * The reason to use a function rather than a fixed context here
+ * is to avoid space leaks. InlineInfos can survive multiple runs
+ * because they might be created as part of an unpickled method
+ * and consumed only in a future run (or never).
*/
- private final class InlineInfo(treeExpr: Context => Tree, var inlineCtx: Context) {
- private val inlineMethod = inlineCtx.owner
+ private final class InlineInfo(treeExpr: Context => Tree, var inlineCtxFn: Context => Context) {
private val myAccessors = new mutable.ListBuffer[MemberDef]
private var myBody: Tree = _
private var evaluated = false
@@ -56,7 +61,8 @@ object Inliner {
* This means that references to a provate type will lead to typing failures
* on the code when it is inlined. Less than ideal, but hard to do better (see below).
*/
- private def prepareForInline = new TreeMap {
+ private def prepareForInline(inlineCtx: Context) = new TreeMap {
+ val inlineMethod = inlineCtx.owner
/** A definition needs an accessor if it is private, protected, or qualified private */
def needsAccessor(sym: Symbol)(implicit ctx: Context) =
@@ -182,19 +188,22 @@ object Inliner {
def isEvaluated = evaluated
private def ensureEvaluated()(implicit ctx: Context) =
- try if (!evaluated) {
+ if (!evaluated) {
evaluated = true // important to set early to prevent overwrites by attachInlineInfo in typedDefDef
- myBody = treeExpr(inlineCtx)
- myBody = prepareForInline.transform(myBody)(inlineCtx)
- inlining.println(i"inlinable body of ${inlineCtx.owner} = $myBody")
- inlineCtx = null // null out to avoid space leaks
+ val inlineCtx = inlineCtxFn(ctx)
+ inlineCtxFn = null // null out to avoid space leaks
+ try {
+ myBody = treeExpr(inlineCtx)
+ myBody = prepareForInline(inlineCtx).transform(myBody)(inlineCtx)
+ inlining.println(i"inlinable body of ${inlineCtx.owner} = $myBody")
+ }
+ catch {
+ case ex: AssertionError =>
+ println(i"failure while expanding ${inlineCtx.owner}")
+ throw ex
+ }
}
else assert(myBody != null)
- catch {
- case ex: AssertionError =>
- println(i"failure while expanding $inlineMethod")
- throw ex
- }
/** The body to inline */
def body(implicit ctx: Context): Tree = {
@@ -224,16 +233,18 @@ object Inliner {
* @param sym The symbol denotatioon of the inline method for which info is registered
* @param treeExpr A function that computes the tree to be inlined, given a context
* This tree may still refer to non-public members.
- * @param ctx The current context is the one in which the tree is computed. It needs
+ * @param inlineCtxFn A function that maps the current context to the context in
+ * which to compute the tree. The resulting context needs
* to have the inlined method as owner.
*/
- def registerInlineInfo(sym: SymDenotation, treeExpr: Context => Tree)(implicit ctx: Context): Unit = {
+ def registerInlineInfo(
+ sym: SymDenotation, treeExpr: Context => Tree, inlineCtxFn: Context => Context)(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, ctx))
+ inlineAnnot.tree.putAttachment(InlineInfo, new InlineInfo(treeExpr, inlineCtxFn))
}
}
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index 2e714ab6d..9ba6a8963 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -588,8 +588,8 @@ class Namer { typer: Typer =>
case original: untpd.DefDef =>
Inliner.registerInlineInfo(
denot,
- implicit ctx => typedAheadExpr(original).asInstanceOf[tpd.DefDef].rhs
- )(localContext(denot.symbol))
+ implicit ctx => typedAheadExpr(original).asInstanceOf[tpd.DefDef].rhs,
+ _ => localContext(denot.symbol))
case _ =>
}
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 58fb47f2c..85102841e 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -1176,7 +1176,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
// Overwrite inline body to make sure it is not evaluated twice
if (sym.hasAnnotation(defn.InlineAnnot))
- Inliner.registerInlineInfo(sym, ctx => rhs1)
+ Inliner.registerInlineInfo(sym, _ => rhs1, _ => ctx)
if (sym.isAnonymousFunction) {
// If we define an anonymous function, make sure the return type does not