diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index ababe3f94479..3078d5f07d28 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -172,9 +172,7 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha override def prepareForValDef(tree: ValDef)(using Context): Context = if !tree.symbol.is(Deferred) && tree.rhs.symbol != defn.Predef_undefined then refInfos.register(tree) - tree.tpt match - case RefinedTypeTree(_, refinements) => relax(tree.rhs, refinements) - case _ => + relax(tree.rhs, tree.tpt.tpe) ctx override def transformValDef(tree: ValDef)(using Context): tree.type = traverseAnnotations(tree.symbol) @@ -198,9 +196,7 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha refInfos.inliners += 1 else if !tree.symbol.is(Deferred) && tree.rhs.symbol != defn.Predef_undefined then refInfos.register(tree) - tree.tpt match - case RefinedTypeTree(_, refinements) => relax(tree.rhs, refinements) - case _ => + relax(tree.rhs, tree.tpt.tpe) ctx override def transformDefDef(tree: DefDef)(using Context): tree.type = traverseAnnotations(tree.symbol) @@ -864,15 +860,21 @@ object CheckUnused: case tree => traverseChildren(tree) // NoWarn members in tree that correspond to refinements; currently uses only names. - def relax(tree: Tree, refinements: List[Tree])(using Context): Unit = - val names = refinements.collect { case named: NamedDefTree => named.name }.toSet - val relaxer = new TreeTraverser: - def traverse(tree: Tree)(using Context) = - tree match - case tree: NamedDefTree if names(tree.name) => tree.withAttachment(NoWarn, ()) - case _ => - traverseChildren(tree) - relaxer.traverse(tree) + def relax(tree: Tree, tpe: Type)(using Context): Unit = + def refinements(tpe: Type, names: List[Name]): List[Name] = + tpe match + case RefinedType(parent, refinedName, refinedInfo) => refinedName :: refinements(parent, names) + case _ => names + val refinedNames = refinements(tpe, Nil) + if !refinedNames.isEmpty then + val names = refinedNames.toSet + val relaxer = new TreeTraverser: + def traverse(tree: Tree)(using Context) = + tree match + case tree: NamedDefTree if names(tree.name) => tree.withAttachment(NoWarn, ()) + case _ => + traverseChildren(tree) + relaxer.traverse(tree) extension (nm: Name) inline def exists(p: Name => Boolean): Boolean = nm.ne(nme.NO_NAME) && p(nm) diff --git a/tests/warn/i22681.scala b/tests/warn/i22681.scala index e15d186479c3..81f12923d4d6 100644 --- a/tests/warn/i22681.scala +++ b/tests/warn/i22681.scala @@ -6,12 +6,10 @@ trait T: class C: def f: Runnable { def u: Int } = new Runnable with T: - private def v = 42 // avoid g judged too trivial to warn def run() = () - def g = v // warn effectively private member is unused - def t = v // nowarn - def u = v // nowarn because leaked by refinement + def g = 42 // warn effectively private member is unused + def t = 42 // nowarn + def u = 42 // nowarn because leaked by refinement val v: Runnable { def u: Int } = new Runnable: - private def v = 42 // avoid g judged too trivial to warn def run() = () - def u = v // nowarn because leaked by refinement + def u = 42 // nowarn because leaked by refinement diff --git a/tests/warn/i23323.scala b/tests/warn/i23323.scala new file mode 100644 index 000000000000..85a5b0646b6e --- /dev/null +++ b/tests/warn/i23323.scala @@ -0,0 +1,14 @@ +//> using options -Wunused:all + +class C: + val x = new reflect.Selectable: + def f = 42 + def g = 27 + val y: Selectable = new reflect.Selectable: + def f = 42 // warn + def g = 27 // warn + val z = new scala.Selectable: + def f = 42 + def g = 27 + def selectDynamic(name: String): Any = ??? + def applyDynamic(name: String)(args: Any*): Any = ???