diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index c82bc6ce001c..56f3dc8840d7 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -7,7 +7,7 @@ import dotty.tools.dotc.config.ScalaSettings import dotty.tools.dotc.core.Contexts.* import dotty.tools.dotc.core.Flags.* import dotty.tools.dotc.core.Names.{Name, SimpleName, DerivedName, TermName, termName} -import dotty.tools.dotc.core.NameOps.{isAnonymousFunctionName, isReplWrapperName} +import dotty.tools.dotc.core.NameOps.{isAnonymousFunctionName, isReplWrapperName, setterName} import dotty.tools.dotc.core.NameKinds.{ BodyRetainerName, ContextBoundParamName, ContextFunctionParamName, DefaultGetterName, WildcardParamName} import dotty.tools.dotc.core.StdNames.nme @@ -505,7 +505,13 @@ object CheckUnused: if sym.isLocalToBlock then if ctx.settings.WunusedHas.locals && sym.is(Mutable) && !infos.asss(sym) then warnAt(pos)(UnusedSymbol.unsetLocals) - else if ctx.settings.WunusedHas.privates && sym.isAllOf(Private | Mutable) && !infos.asss(sym) then + else if ctx.settings.WunusedHas.privates + && sym.is(Mutable) + && (sym.is(Private) || sym.isEffectivelyPrivate) + && !sym.isSetter // tracks sym.underlyingSymbol sibling getter, check setter below + && !infos.asss(sym) + && !infos.refs(sym.owner.info.member(sym.name.asTermName.setterName).symbol) + then warnAt(pos)(UnusedSymbol.unsetPrivates) def checkPrivate(sym: Symbol, pos: SrcPos) = @@ -514,7 +520,10 @@ object CheckUnused: && !sym.isOneOf(SelfName | Synthetic | CaseAccessor) && !sym.name.is(BodyRetainerName) && !sym.isSerializationSupport - && !(sym.is(Mutable) && sym.isSetter && sym.owner.is(Trait)) // tracks sym.underlyingSymbol sibling getter + && !( sym.is(Mutable) + && sym.isSetter // tracks sym.underlyingSymbol sibling getter + && (sym.owner.is(Trait) || sym.owner.isAnonymousClass) + ) && !infos.nowarn(sym) then warnAt(pos)(UnusedSymbol.privateMembers) diff --git a/tests/warn/i23200.check b/tests/warn/i23200.check new file mode 100644 index 000000000000..75d663f0f338 --- /dev/null +++ b/tests/warn/i23200.check @@ -0,0 +1,8 @@ +-- [E198] Unused Symbol Warning: tests/warn/i23200.scala:8:8 ----------------------------------------------------------- +8 | var x: Int = 42 // warn + | ^ + | unset private variable, consider using an immutable val instead +-- [E198] Unused Symbol Warning: tests/warn/i23200.scala:40:6 ---------------------------------------------------------- +40 | var x: Int = 42 // warn local var + | ^ + | unset local variable, consider using an immutable val instead diff --git a/tests/warn/i23200.scala b/tests/warn/i23200.scala new file mode 100644 index 000000000000..613e8df32262 --- /dev/null +++ b/tests/warn/i23200.scala @@ -0,0 +1,41 @@ +//> using options -Wunused:all + +trait Foo +trait Bar + +def `anon not updated` = + new Foo { + var x: Int = 42 // warn + val _ = new Bar: + println(x) + //x = 27 + //x_=(27) + } +def `anon yes updated` = + new Foo { + var x: Int = 42 // nowarn + val _ = new Bar: + println(x) + x = 27 + //x_=(27) + } +def `anon yes updated from nested context` = + new Foo { + var x: Int = 42 // nowarn + val _ = new Bar: + println(x) + x = 27 + //x_=(27) + } +def `anon yes updated in daring use of setter` = + new Foo { + var x: Int = 42 // nowarn + val _ = new Bar: + println(x) + //x = 27 + x_=(27) + } + +def f: Unit = + var x: Int = 42 // warn local var + println(x)