Skip to content

Commit c5fb5c4

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 c5fb5c4

File tree

1 file changed

+31
-22
lines changed

1 file changed

+31
-22
lines changed

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

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,33 @@ 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+
val fn = symFn
57+
mySym = null
58+
mySym = fn(ctx)
59+
case sym: Symbol if sym.defRunId != ctx.runId =>
60+
mySym = sym.denot.current.symbol
61+
case _ =>
62+
}
63+
mySym.asInstanceOf[Symbol]
64+
65+
protected var myTree: Tree | (Context => Tree)
66+
def tree(using ctx: Context): Tree =
67+
assert(myTree != null)
68+
myTree match {
69+
case treeFn: (Context => Tree) @unchecked =>
70+
val fn = treeFn
71+
myTree = null
72+
myTree = fn(ctx)
73+
case _ =>
74+
}
75+
myTree.asInstanceOf[Tree]
5976

60-
override def isEvaluated: Boolean = myTree != null
77+
override def isEvaluated: Boolean = myTree.isInstanceOf[Tree]
6178
}
6279

6380
/** An annotation indicating the body of a right-hand side,
@@ -120,23 +137,15 @@ object Annotations {
120137
/** Create an annotation where the tree is computed lazily. */
121138
def deferred(sym: Symbol)(treeFn: Context ?=> Tree)(implicit ctx: Context): Annotation =
122139
new LazyAnnotation {
123-
override def symbol(implicit ctx: Context): Symbol = sym
124-
def complete(implicit ctx: Context) = treeFn(using ctx)
140+
protected var myTree: Tree | (Context => Tree) = ctx => treeFn(using ctx)
141+
protected var mySym: Symbol | (Context => Symbol) = sym
125142
}
126143

127144
/** 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 =
145+
def deferredSymAndTree(symFn: Context ?=> Symbol)(treeFn: Context ?=> Tree)(implicit ctx: Context): Annotation =
129146
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)
147+
protected var mySym: Symbol | (Context => Symbol) = ctx => symFn(using ctx)
148+
protected var myTree: Tree | (Context => Tree) = ctx => treeFn(using ctx)
140149
}
141150

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

0 commit comments

Comments
 (0)