Skip to content

Commit 776bb54

Browse files
committed
LazyAnnotation: avoid unnecessary memory leaks
When a deferred annotation has been completed, let the completer closure be garbage-collected to avoid potential leaks.
1 parent a324502 commit 776bb54

File tree

1 file changed

+29
-22
lines changed

1 file changed

+29
-22
lines changed

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

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,31 @@ object Annotations {
4848
}
4949

5050
abstract class LazyAnnotation extends Annotation {
51-
override def symbol(implicit ctx: Context): Symbol
52-
def complete(implicit ctx: Context): Tree
53-
54-
private var myTree: Tree = null
55-
def tree(implicit ctx: Context): Tree = {
56-
if (myTree == null) myTree = complete(ctx)
57-
myTree
58-
}
51+
protected var mySym: Symbol | (Context => Symbol)
52+
override def symbol(using ctx: Context): Symbol =
53+
assert(mySym != null)
54+
mySym match {
55+
case symFn: (Context => Symbol) @unchecked =>
56+
mySym = null
57+
mySym = symFn(ctx)
58+
case sym: Symbol if sym.defRunId != ctx.runId =>
59+
mySym = sym.denot.current.symbol
60+
case _ =>
61+
}
62+
mySym.asInstanceOf[Symbol]
63+
64+
protected var myTree: Tree | (Context => Tree)
65+
def tree(using ctx: Context): Tree =
66+
assert(myTree != null)
67+
myTree match {
68+
case treeFn: (Context => Tree) @unchecked =>
69+
myTree = null
70+
myTree = treeFn(ctx)
71+
case _ =>
72+
}
73+
myTree.asInstanceOf[Tree]
5974

60-
override def isEvaluated: Boolean = myTree != null
75+
override def isEvaluated: Boolean = myTree.isInstanceOf[Tree]
6176
}
6277

6378
/** An annotation indicating the body of a right-hand side,
@@ -120,23 +135,15 @@ object Annotations {
120135
/** Create an annotation where the tree is computed lazily. */
121136
def deferred(sym: Symbol)(treeFn: Context ?=> Tree)(implicit ctx: Context): Annotation =
122137
new LazyAnnotation {
123-
override def symbol(implicit ctx: Context): Symbol = sym
124-
def complete(implicit ctx: Context) = treeFn(using ctx)
138+
protected var myTree: Tree | (Context => Tree) = ctx => treeFn(using ctx)
139+
protected var mySym: Symbol | (Context => Symbol) = sym
125140
}
126141

127142
/** Create an annotation where the symbol and the tree are computed lazily. */
128-
def deferredSymAndTree(symf: Context ?=> Symbol)(treeFn: Context ?=> Tree)(implicit ctx: Context): Annotation =
143+
def deferredSymAndTree(symFn: Context ?=> Symbol)(treeFn: Context ?=> Tree)(implicit ctx: Context): Annotation =
129144
new LazyAnnotation {
130-
private var mySym: Symbol = _
131-
132-
override def symbol(implicit ctx: Context): Symbol = {
133-
if (mySym == null || mySym.defRunId != ctx.runId) {
134-
mySym = symf(using ctx)
135-
assert(mySym != null)
136-
}
137-
mySym
138-
}
139-
def complete(implicit ctx: Context) = treeFn(using ctx)
145+
protected var mySym: Symbol | (Context => Symbol) = ctx => symFn(using ctx)
146+
protected var myTree: Tree | (Context => Tree) = ctx => treeFn(using ctx)
140147
}
141148

142149
def deferred(atp: Type, args: List[Tree])(implicit ctx: Context): Annotation =

0 commit comments

Comments
 (0)