@@ -53,19 +53,19 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
5353 override def transformIdent (tree : Ident )(using Context ): tree.type =
5454 if tree.symbol.exists then
5555 // if in an inline expansion, resolve at summonInline (synthetic pos) or in an enclosing call site
56- val resolving =
56+ val resolvingImports =
5757 tree.srcPos.isUserCode(using if tree.hasAttachment(InlinedParameter ) then ctx.outer else ctx)
5858 || tree.srcPos.isZeroExtentSynthetic // take as summonInline
5959 if ! ignoreTree(tree) then
6060 def loopOverPrefixes (prefix : Type , depth : Int ): Unit =
6161 if depth < 10 && prefix.exists && ! prefix.classSymbol.isEffectiveRoot then
62- resolveUsage(prefix.classSymbol, nme.NO_NAME , NoPrefix , imports = resolving )
62+ resolveUsage(prefix.classSymbol, nme.NO_NAME , NoPrefix , tree.srcPos, resolvingImports )
6363 loopOverPrefixes(prefix.normalizedPrefix, depth + 1 )
6464 if tree.srcPos.isZeroExtentSynthetic then
6565 loopOverPrefixes(tree.typeOpt.normalizedPrefix, depth = 0 )
66- resolveUsage(tree.symbol, tree.name, tree.typeOpt.importPrefix.skipPackageObject, imports = resolving )
66+ resolveUsage(tree.symbol, tree.name, tree.typeOpt.importPrefix.skipPackageObject, tree.srcPos, resolvingImports )
6767 else if tree.hasType then
68- resolveUsage(tree.tpe.classSymbol, tree.name, tree.tpe.importPrefix.skipPackageObject)
68+ resolveUsage(tree.tpe.classSymbol, tree.name, tree.tpe.importPrefix.skipPackageObject, tree.srcPos )
6969 tree
7070
7171 // import x.y; y may be rewritten x.y, also import x.z as y
@@ -86,13 +86,13 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
8686 else if tycon.typeSymbol == defn.TypeableType then args(0 ) // T in Typeable[T]
8787 else return tree
8888 val target = res.dealias.typeSymbol
89- resolveUsage(target, target.name, res.importPrefix.skipPackageObject) // case _: T =>
89+ resolveUsage(target, target.name, res.importPrefix.skipPackageObject, tree.srcPos ) // case _: T =>
9090 case _ =>
9191 else if isImportable || name.exists(_ != sym.name) then
9292 if ! ignoreTree(tree) then
93- resolveUsage(sym, name, tree.qualifier.tpe)
93+ resolveUsage(sym, name, tree.qualifier.tpe, tree.srcPos )
9494 else if ! ignoreTree(tree) then
95- refUsage(sym)
95+ refUsage(sym, tree.srcPos )
9696 tree
9797
9898 override def transformLiteral (tree : Literal )(using Context ): tree.type =
@@ -117,23 +117,21 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
117117 tree match
118118 case Apply (Select (left, nme.Equals | nme.NotEquals ), right :: Nil ) =>
119119 val caneq = defn.CanEqualClass .typeRef.appliedTo(left.tpe.widen :: right.tpe.widen :: Nil )
120- resolveScoped(caneq)
120+ resolveScoped(caneq, tree.srcPos )
121121 case tree =>
122- refUsage(tree.tpe.typeSymbol)
122+ refUsage(tree.tpe.typeSymbol, tree.srcPos )
123123 tree
124124
125125 override def transformTypeApply (tree : TypeApply )(using Context ): tree.type =
126126 if tree.symbol.exists && tree.symbol.isConstructor then
127- refUsage(tree.symbol.owner) // redundant with use of resultType in transformSelect of fun
127+ refUsage(tree.symbol.owner, tree.srcPos ) // redundant with use of resultType in transformSelect of fun
128128 tree
129129
130130 override def prepareForAssign (tree : Assign )(using Context ): Context =
131131 if tree.lhs.symbol.exists then
132- refInfos.setAssignmentTarget(tree.lhs.symbol)
133- ctx
134- override def transformAssign (tree : Assign )(using Context ): tree.type =
135- refInfos.resetAssignmentTarget()
136- tree
132+ refInfos.addAssignmentTarget(tree.lhs.symbol)
133+ ctx.fresh.setTree(tree)
134+ else ctx
137135
138136 override def prepareForMatch (tree : Match )(using Context ): Context =
139137 // allow case.pat against tree.selector (simple var pat only for now)
@@ -144,13 +142,14 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
144142 override def transformMatch (tree : Match )(using Context ): tree.type =
145143 if tree.isInstanceOf [InlineMatch ] && tree.selector.isEmpty then
146144 val sf = defn.Compiletime_summonFrom
147- resolveUsage(sf, sf.name, NoPrefix )
145+ resolveUsage(sf, sf.name, NoPrefix , tree.srcPos )
148146 tree
149147
150148 override def transformTypeTree (tree : TypeTree )(using Context ): tree.type =
151149 tree.tpe match
152150 case AnnotatedType (_, annot) => transformAllDeep(annot.tree)
153- case tpt if ! tree.isInferred && tpt.typeSymbol.exists => resolveUsage(tpt.typeSymbol, tpt.typeSymbol.name, NoPrefix )
151+ case tpt if ! tree.isInferred && tpt.typeSymbol.exists =>
152+ resolveUsage(tpt.typeSymbol, tpt.typeSymbol.name, NoPrefix , tree.srcPos)
154153 case _ =>
155154 tree
156155
@@ -191,12 +190,14 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
191190 traverseAnnotations(tree.symbol)
192191 if tree.name.startsWith(" derived$" ) && tree.hasType then
193192 def loop (t : Tree ): Unit = t match
194- case Ident (name) => resolveUsage(t.tpe.typeSymbol, name, t.tpe.underlyingPrefix.skipPackageObject)
195- case Select (t, _) => loop(t)
196- case _ =>
193+ case Ident (name) =>
194+ resolveUsage(t.tpe.typeSymbol, name, t.tpe.underlyingPrefix.skipPackageObject, tree.srcPos)
195+ case Select (t, _) =>
196+ loop(t)
197+ case _ =>
197198 tree.getAttachment(OriginalTypeClass ).foreach(loop)
198199 if tree.symbol.isAllOf(DeferredGivenFlags ) then
199- resolveUsage(defn.Compiletime_deferred , nme.NO_NAME , NoPrefix )
200+ resolveUsage(defn.Compiletime_deferred , nme.NO_NAME , NoPrefix , tree.srcPos )
200201 tree
201202
202203 override def prepareForDefDef (tree : DefDef )(using Context ): Context =
@@ -216,7 +217,7 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
216217 if tree.symbol.is(Inline ) then
217218 refInfos.inliners -= 1
218219 if tree.symbol.isAllOf(DeferredGivenFlags ) then
219- resolveUsage(defn.Compiletime_deferred , nme.NO_NAME , NoPrefix )
220+ resolveUsage(defn.Compiletime_deferred , nme.NO_NAME , NoPrefix , tree.srcPos )
220221 tree
221222
222223 override def transformTypeDef (tree : TypeDef )(using Context ): tree.type =
@@ -282,7 +283,7 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
282283 def resolve (tpe : Type ): Unit =
283284 val sym = tpe.typeSymbol
284285 if sym.exists then
285- resolveUsage(sym, sym.name, NoPrefix )
286+ resolveUsage(sym, sym.name, NoPrefix , tree.srcPos )
286287 resolve(lo)
287288 resolve(hi)
288289 case _ =>
@@ -314,8 +315,8 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
314315 *
315316 * The LHS of a current Assign is never recorded as a reference (that is, a usage).
316317 */
317- def refUsage (sym : Symbol )(using Context ): Unit =
318- if ! refInfos.hasRef(sym) && ! refInfos.isAssignmentTarget(sym) then
318+ def refUsage (sym : Symbol , pos : SrcPos )(using Context ): Unit =
319+ if ! refInfos.hasRef(sym) then
319320 val isCase = sym.is(Case ) && sym.isClass
320321 if ! ctx.outersIterator.exists: outer =>
321322 val owner = outer.owner
@@ -324,6 +325,9 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
324325 && owner.exists
325326 && owner.is(Synthetic )
326327 && owner.owner.eq(sym.companionModule.moduleClass)
328+ || outer.tree.match
329+ case Assign (lhs, _) => lhs.symbol.eq(sym) && outer.tree.srcPos.sourcePos.contains(pos.sourcePos)
330+ case _ => false
327331 then
328332 refInfos.addRef(sym)
329333
@@ -338,7 +342,7 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
338342 * The `imports` flag is whether an identifier can mark an import as used: the flag is false
339343 * for inlined code, except for `summonInline` (and related constructs) which are resolved at inlining.
340344 */
341- def resolveUsage (sym0 : Symbol , name : Name , prefix : Type , imports : Boolean = true )(using Context ): Unit =
345+ def resolveUsage (sym0 : Symbol , name : Name , prefix : Type , pos : SrcPos , imports : Boolean = true )(using Context ): Unit =
342346 import PrecedenceLevels .*
343347 val sym = sym0.userSymbol
344348
@@ -441,15 +445,15 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
441445 end while
442446 // record usage and possibly an import
443447 if ! enclosed then
444- refUsage(sym)
448+ refUsage(sym, pos )
445449 if imports && candidate != NoContext && candidate.isImportContext && importer != null then
446450 refInfos.sels.put(importer, ())
447451 end resolveUsage
448452
449453 /** Simulate implicit search for contextual implicits in lexical scope and mark any definitions or imports as used.
450454 * Avoid cached ctx.implicits because it needs the precise import context that introduces the given.
451455 */
452- def resolveScoped (tp : Type )(using Context ): Unit =
456+ def resolveScoped (tp : Type , pos : SrcPos )(using Context ): Unit =
453457 var done = false
454458 val ctxs = ctx.outersIterator
455459 while ! done && ctxs.hasNext do
@@ -461,15 +465,15 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
461465 else Nil
462466 implicitRefs.find(ref => ref.underlyingRef.widen <:< tp) match
463467 case Some (found : TermRef ) =>
464- refUsage(found.denot.symbol)
468+ refUsage(found.denot.symbol, pos )
465469 if cur.isImportContext then
466470 cur.importInfo.nn.selectors.find(sel => sel.isGiven || sel.rename == found.name) match
467471 case Some (sel) =>
468472 refInfos.sels.put(sel, ())
469473 case _ =>
470474 return
471475 case Some (found : RenamedImplicitRef ) if cur.isImportContext =>
472- refUsage(found.underlyingRef.denot.symbol)
476+ refUsage(found.underlyingRef.denot.symbol, pos )
473477 cur.importInfo.nn.selectors.find(sel => sel.rename == found.implicitName) match
474478 case Some (sel) =>
475479 refInfos.sels.put(sel, ())
@@ -555,14 +559,8 @@ object CheckUnused:
555559
556560 var inliners = 0 // depth of inline def (not inlined yet)
557561
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
562+ def addAssignmentTarget (sym : Symbol ): Unit =
564563 asss.addOne(sym)
565- // @pre !isAssignmentTarget(sym), see refUsage
566564 def addRef (sym : Symbol ): Unit =
567565 refs.addOne(sym)
568566 def hasRef (sym : Symbol ): Boolean =
0 commit comments