From de492fcd0431d41d82fbc10c56b73a8f97f51f5f Mon Sep 17 00:00:00 2001 From: Szymon Rodziewicz Date: Fri, 29 Sep 2023 12:25:50 +0200 Subject: [PATCH] Fix false positive in WUnused for renamed path-dependent imports (attempt 2) --- compiler/src/dotty/tools/dotc/core/StdNames.scala | 2 +- .../src/dotty/tools/dotc/transform/CheckUnused.scala | 12 +++++++----- tests/pos/i18366.scala | 10 ++++++++++ 3 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 tests/pos/i18366.scala diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 4fc7ea4185d8..40f8ac2dc252 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -53,7 +53,7 @@ object StdNames { protected def kw(name: N): N = { kws += name; name } final val keywords: collection.Set[N] = kws - } + } abstract class ScalaNames[N <: Name] extends DefinedNames[N] { protected def encode(s: String): N = fromName(fromString(s).encode) diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index eb3c37622e0d..96c6cb1a9743 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -337,7 +337,7 @@ object CheckUnused: * - usage */ private class UnusedData: - import collection.mutable.{Set => MutSet, Map => MutMap, Stack => MutStack} + import collection.mutable.{Set => MutSet, Map => MutMap, Stack => MutStack, ListBuffer => MutList} import UnusedData.* /** The current scope during the tree traversal */ @@ -346,7 +346,7 @@ object CheckUnused: var unusedAggregate: Option[UnusedResult] = None /* IMPORTS */ - private val impInScope = MutStack(MutSet[tpd.Import]()) + private val impInScope = MutStack(MutList[tpd.Import]()) /** * We store the symbol along with their accessibility without import. * Accessibility to their definition in outer context/scope @@ -449,7 +449,7 @@ object CheckUnused: def pushScope(newScopeType: ScopeType): Unit = // unused imports : currScopeType.push(newScopeType) - impInScope.push(MutSet()) + impInScope.push(MutList()) usedInScope.push(MutSet()) def registerSetVar(sym: Symbol): Unit = @@ -669,8 +669,10 @@ object CheckUnused: val simpleSelections = qual.tpe.member(sym.name).alternatives val typeSelections = sels.flatMap(n => qual.tpe.member(n.name.toTypeName).alternatives) val termSelections = sels.flatMap(n => qual.tpe.member(n.name.toTermName).alternatives) + val sameTermPath = qual.isTerm && sym.exists && sym.owner.isType && qual.tpe.typeSymbol == sym.owner.asType val selectionsToDealias = typeSelections ::: termSelections - val qualHasSymbol = simpleSelections.map(_.symbol).contains(sym) || (simpleSelections ::: selectionsToDealias).map(_.symbol).map(dealias).contains(dealiasedSym) + val renamedSelection = if sameTermPath then sels.find(sel => sel.imported.name == sym.name) else None + val qualHasSymbol = simpleSelections.map(_.symbol).contains(sym) || (simpleSelections ::: selectionsToDealias).map(_.symbol).map(dealias).contains(dealiasedSym) || renamedSelection.isDefined def selector = sels.find(sel => (sel.name.toTermName == sym.name || sel.name.toTypeName == sym.name) && symName.map(n => n.toTermName == sel.rename).getOrElse(true)) def dealiasedSelector = if(isDerived) sels.flatMap(sel => selectionsToDealias.map(m => (sel, m.symbol))).collect { case (sel, sym) if dealias(sym) == dealiasedSym => sel @@ -680,7 +682,7 @@ object CheckUnused: else None def wildcard = sels.find(sel => sel.isWildcard && ((sym.is(Given) == sel.isGiven && sel.bound.isEmpty) || sym.is(Implicit))) if qualHasSymbol && (!isAccessible || sym.isRenamedSymbol(symName)) && sym.exists then - selector.orElse(dealiasedSelector).orElse(givenSelector).orElse(wildcard) // selector with name or wildcard (or given) + selector.orElse(dealiasedSelector).orElse(givenSelector).orElse(wildcard).orElse(renamedSelection) // selector with name or wildcard (or given) else None diff --git a/tests/pos/i18366.scala b/tests/pos/i18366.scala new file mode 100644 index 000000000000..698510ad13a2 --- /dev/null +++ b/tests/pos/i18366.scala @@ -0,0 +1,10 @@ +//> using options -Xfatal-warnings -Wunused:all + +trait Builder { + def foo(): Unit +} + +def repro = + val builder: Builder = ??? + import builder.{foo => bar} + bar() \ No newline at end of file