diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index 37eee35fdb39..68145ab47fd9 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -450,6 +450,7 @@ object CheckUnused: val refs = mutable.Set.empty[Symbol] // references val asss = mutable.Set.empty[Symbol] // targets of assignment val skip = mutable.Set.empty[Symbol] // methods to skip (don't warn about their params) + val nowarn = mutable.Set.empty[Symbol] // marked @nowarn val imps = new IdentityHashMap[Import, Unit] // imports val sels = new IdentityHashMap[ImportSelector, Unit] // matched selectors def register(tree: Tree)(using Context): Unit = if inlined.isEmpty then @@ -462,7 +463,9 @@ object CheckUnused: then imps.put(imp, ()) case tree: Bind => - if !tree.name.isInstanceOf[DerivedName] && !tree.name.is(WildcardParamName) && !tree.hasAttachment(NoWarn) then + if !tree.name.isInstanceOf[DerivedName] && !tree.name.is(WildcardParamName) then + if tree.hasAttachment(NoWarn) then + nowarn.addOne(tree.symbol) pats.addOne((tree.symbol, tree.namePos)) case tree: ValDef if tree.hasAttachment(PatternVar) => if !tree.name.isInstanceOf[DerivedName] then @@ -470,9 +473,10 @@ object CheckUnused: case tree: NamedDefTree => if (tree.symbol ne NoSymbol) && !tree.name.isWildcard - && !tree.hasAttachment(NoWarn) && !tree.symbol.is(ModuleVal) // track only the ModuleClass using the object symbol, with correct namePos then + if tree.hasAttachment(NoWarn) then + nowarn.addOne(tree.symbol) defs.addOne((tree.symbol.userSymbol, tree.namePos)) case _ => if tree.symbol ne NoSymbol then @@ -540,6 +544,7 @@ object CheckUnused: && !sym.name.is(BodyRetainerName) && !sym.isSerializationSupport && !(sym.is(Mutable) && sym.isSetter && sym.owner.is(Trait)) // tracks sym.underlyingSymbol sibling getter + && !infos.nowarn(sym) then warnAt(pos)(UnusedSymbol.privateMembers) @@ -634,7 +639,7 @@ object CheckUnused: val byPos = infos.pats.groupMap(uniformPos(_, _))((sym, pos) => sym) for (pos, syms) <- byPos if pos.span.exists && !syms.exists(_.hasAnnotation(defn.UnusedAnnot)) do if !syms.exists(infos.refs(_)) then - if !syms.exists(v => !v.isLocal && !v.is(Private)) then + if !syms.exists(v => !v.isLocal && !v.is(Private) || infos.nowarn(v)) then warnAt(pos)(UnusedSymbol.patVars) else if syms.exists(_.is(Mutable)) then // check unassigned var val sym = // recover the original diff --git a/tests/warn/i15503d.scala b/tests/warn/i15503d.scala index 2981986daff6..9e6e4792d729 100644 --- a/tests/warn/i15503d.scala +++ b/tests/warn/i15503d.scala @@ -22,7 +22,7 @@ case class K(i: Int, j: Int) class C(c0: Option[Int], k0: K): private val Some(c) = c0: @unchecked // warn valdef from pattern - private val K(i, j) = k0 // warn // warn valdefs from pattern (RHS patvars are NoWarn) + private val K(i, j) = k0 // nowarn (name of case class element is nowarn) val K(v, w) = k0 // nowarn nonprivate private val K(r, s) = k0 // warn // warn valdefs from pattern def f(x: Option[Int]) = x match diff --git a/tests/warn/t13095.scala b/tests/warn/t13095.scala new file mode 100644 index 000000000000..0634f4ed903d --- /dev/null +++ b/tests/warn/t13095.scala @@ -0,0 +1,10 @@ +//> using options -Wunused:patvars -Werror + +case class A(x: Int, y: Int) + +object Main { + for { + a <- List.empty[A] + A(x, y) = a + } yield x + y +}