Skip to content

Commit 01ad683

Browse files
committed
Simplify handling of Assign in unused check
1 parent 68396ca commit 01ad683

File tree

2 files changed

+35
-21
lines changed

2 files changed

+35
-21
lines changed

compiler/src/dotty/tools/dotc/transform/CheckUnused.scala

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
5151
tree
5252

5353
override def transformIdent(tree: Ident)(using Context): tree.type =
54-
refInfos.isAssignment = tree.hasAttachment(AssignmentTarget)
5554
if tree.symbol.exists then
5655
// if in an inline expansion, resolve at summonInline (synthetic pos) or in an enclosing call site
5756
val resolving =
@@ -67,12 +66,10 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
6766
resolveUsage(tree.symbol, tree.name, tree.typeOpt.importPrefix.skipPackageObject, imports = resolving)
6867
else if tree.hasType then
6968
resolveUsage(tree.tpe.classSymbol, tree.name, tree.tpe.importPrefix.skipPackageObject)
70-
refInfos.isAssignment = false
7169
tree
7270

7371
// import x.y; y may be rewritten x.y, also import x.z as y
7472
override def transformSelect(tree: Select)(using Context): tree.type =
75-
refInfos.isAssignment = tree.hasAttachment(AssignmentTarget)
7673
val name = tree.removeAttachment(OriginalName).getOrElse(nme.NO_NAME)
7774
inline def isImportable = tree.qualifier.srcPos.isSynthetic
7875
&& tree.qualifier.tpe.match
@@ -96,7 +93,6 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
9693
resolveUsage(sym, name, tree.qualifier.tpe)
9794
else if !ignoreTree(tree) then
9895
refUsage(sym)
99-
refInfos.isAssignment = false
10096
tree
10197

10298
override def transformLiteral(tree: Literal)(using Context): tree.type =
@@ -132,10 +128,11 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
132128
tree
133129

134130
override def prepareForAssign(tree: Assign)(using Context): Context =
135-
tree.lhs.putAttachment(AssignmentTarget, ()) // don't take LHS reference as a read
131+
if tree.lhs.symbol.exists then
132+
refInfos.setAssignmentTarget(tree.lhs.symbol)
136133
ctx
137134
override def transformAssign(tree: Assign)(using Context): tree.type =
138-
tree.lhs.removeAttachment(AssignmentTarget)
135+
refInfos.resetAssignmentTarget()
139136
tree
140137

141138
override def prepareForMatch(tree: Match)(using Context): Context =
@@ -310,13 +307,15 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
310307
for annot <- sym.denot.annotations do
311308
transformAllDeep(annot.tree)
312309

313-
/** If sym is not an enclosing element with respect to the give context, record the reference
310+
/** If sym is not an enclosing element with respect to the given context, record the reference
314311
*
315312
* Also check that every enclosing element is not a synthetic member
316313
* of the sym's case class companion module.
314+
*
315+
* The LHS of a current Assign is never recorded as a reference (that is, a usage).
317316
*/
318317
def refUsage(sym: Symbol)(using Context): Unit =
319-
if !refInfos.hasRef(sym) then
318+
if !refInfos.hasRef(sym) && !refInfos.isAssignmentTarget(sym) then
320319
val isCase = sym.is(Case) && sym.isClass
321320
if !ctx.outersIterator.exists: outer =>
322321
val owner = outer.owner
@@ -505,9 +504,6 @@ object CheckUnused:
505504
/** Ignore reference. */
506505
val Ignore = Property.StickyKey[Unit]
507506

508-
/** Tree is LHS of Assign. */
509-
val AssignmentTarget = Property.StickyKey[Unit]
510-
511507
/** Tree is an inlined parameter. */
512508
val InlinedParameter = Property.StickyKey[Unit]
513509

@@ -559,18 +555,18 @@ object CheckUnused:
559555

560556
var inliners = 0 // depth of inline def (not inlined yet)
561557

562-
// instead of refs.addOne, use refUsage -> addRef to distinguish a read from a write to var
563-
var isAssignment = false
558+
private var assignmentTarget: Symbol = NoSymbol
559+
def isAssignmentTarget(sym: Symbol): Boolean = sym eq assignmentTarget
560+
def resetAssignmentTarget(): Unit =
561+
assignmentTarget = NoSymbol
562+
def setAssignmentTarget(sym: Symbol): Unit =
563+
assignmentTarget = sym
564+
asss.addOne(sym)
565+
// @pre !isAssignmentTarget(sym), see refUsage
564566
def addRef(sym: Symbol): Unit =
565-
if isAssignment then
566-
asss.addOne(sym)
567-
else
568-
refs.addOne(sym)
567+
refs.addOne(sym)
569568
def hasRef(sym: Symbol): Boolean =
570-
if isAssignment then
571-
asss(sym)
572-
else
573-
refs(sym)
569+
refs(sym)
574570

575571
// currently compiletime.testing is completely erased, so ignore the unit
576572
var isNullified = false

tests/warn/i24280.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//> using options -Wunused:all
2+
3+
class Foo {
4+
def foo(): Any = {
5+
var i = 0 // warn mutated but not read
6+
val f = () => i += 1
7+
f
8+
}
9+
def bar(): Any = {
10+
var i = 0 // warn
11+
val g = () => i = i + 1
12+
g
13+
}
14+
object Select:
15+
private var i = 0 // warn
16+
class Select:
17+
def test = Select.i += 1
18+
}

0 commit comments

Comments
 (0)