Skip to content

Commit 803dff7

Browse files
committed
Refactor unused imports to try and make sense of it.
1 parent 701d69f commit 803dff7

File tree

1 file changed

+46
-30
lines changed

1 file changed

+46
-30
lines changed

compiler/src/dotty/tools/dotc/transform/CheckUnused.scala

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import dotty.tools.dotc.ast.untpd.ImportSelector
1010
import dotty.tools.dotc.config.ScalaSettings
1111
import dotty.tools.dotc.core.Contexts.*
1212
import dotty.tools.dotc.core.Decorators.{em, i}
13+
import dotty.tools.dotc.core.Denotations.SingleDenotation
1314
import dotty.tools.dotc.core.Flags.*
1415
import dotty.tools.dotc.core.Phases.Phase
1516
import dotty.tools.dotc.core.StdNames
@@ -409,13 +410,18 @@ object CheckUnused:
409410
* as the same element can be imported with different renaming
410411
*/
411412
def registerUsed(sym: Symbol, name: Option[Name], isDerived: Boolean = false)(using Context): Unit =
412-
if !isConstructorOfSynth(sym) && !doNotRegister(sym) then
413-
if sym.isConstructor && sym.exists then
413+
if sym.exists && !isConstructorOfSynth(sym) && !doNotRegister(sym) then
414+
if sym.isConstructor then
414415
registerUsed(sym.owner, None) // constructor are "implicitly" imported with the class
415416
else
416-
usedInScope.top += ((sym, sym.isAccessibleAsIdent, name, isDerived))
417-
usedInScope.top += ((sym.companionModule, sym.isAccessibleAsIdent, name, isDerived))
418-
usedInScope.top += ((sym.companionClass, sym.isAccessibleAsIdent, name, isDerived))
417+
val accessibleAsIdent = sym.isAccessibleAsIdent
418+
def addIfExists(sym: Symbol): Unit =
419+
if sym.exists then
420+
usedDef += sym
421+
usedInScope.top += ((sym, accessibleAsIdent, name, isDerived))
422+
addIfExists(sym)
423+
addIfExists(sym.companionModule)
424+
addIfExists(sym.companionClass)
419425
if sym.sourcePos.exists then
420426
for n <- name do
421427
usedInPosition.getOrElseUpdate(n, MutSet.empty) += sym
@@ -508,8 +514,6 @@ object CheckUnused:
508514
// we keep the symbols not referencing an import in this scope
509515
// as it can be the only reference to an outer import
510516
usedInScope.top ++= kept
511-
// register usage in this scope for other warnings at the end of the phase
512-
usedDef ++= used.map(_._1)
513517
// retrieve previous scope type
514518
currScopeType.pop
515519
end popScope
@@ -685,42 +689,54 @@ object CheckUnused:
685689
extension (sym: Symbol)
686690
/** is accessible without import in current context */
687691
private def isAccessibleAsIdent(using Context): Boolean =
688-
sym.exists &&
689-
ctx.outersIterator.exists{ c =>
690-
c.owner == sym.owner
691-
|| sym.owner.isClass && c.owner.isClass
692-
&& c.owner.thisType.baseClasses.contains(sym.owner)
693-
&& c.owner.thisType.member(sym.name).alternatives.contains(sym)
694-
}
692+
ctx.outersIterator.exists{ c =>
693+
c.owner == sym.owner
694+
|| sym.owner.isClass && c.owner.isClass
695+
&& c.owner.thisType.baseClasses.contains(sym.owner)
696+
&& c.owner.thisType.member(sym.name).alternatives.contains(sym)
697+
}
695698

696699
/** Given an import and accessibility, return selector that matches import<->symbol */
697700
private def isInImport(imp: tpd.Import, isAccessible: Boolean, altName: Option[Name], isDerived: Boolean)(using Context): Option[ImportSelector] =
701+
assert(sym.exists)
702+
698703
val tpd.Import(qual, sels) = imp
699704
val qualTpe = qual.tpe
700705
val dealiasedSym = sym.dealias
701-
val simpleSelections = qualTpe.member(sym.name).alternatives
702-
val selectionsToDealias = sels.flatMap(sel =>
703-
qualTpe.member(sel.name.toTypeName).alternatives
704-
::: qualTpe.member(sel.name.toTermName).alternatives)
705-
def qualHasSymbol = simpleSelections.map(_.symbol).contains(sym) || (simpleSelections ::: selectionsToDealias).map(_.symbol).map(_.dealias).contains(dealiasedSym)
706-
def selector = sels.find(sel => (sel.name.toTermName == sym.name || sel.name.toTypeName == sym.name) && altName.map(n => n.toTermName == sel.rename).getOrElse(true))
707-
def dealiasedSelector =
706+
707+
val selectionsToDealias: List[SingleDenotation] =
708+
val typeSelections = sels.flatMap(n => qualTpe.member(n.name.toTypeName).alternatives)
709+
val termSelections = sels.flatMap(n => qualTpe.member(n.name.toTermName).alternatives)
710+
typeSelections ::: termSelections
711+
712+
val qualHasSymbol: Boolean =
713+
val simpleSelections = qualTpe.member(sym.name).alternatives
714+
simpleSelections.exists(d => d.symbol == sym || d.symbol.dealias == dealiasedSym)
715+
|| selectionsToDealias.exists(d => d.symbol.dealias == dealiasedSym)
716+
717+
def selector: Option[ImportSelector] =
718+
sels.find(sel => sym.name.toTermName == sel.name && altName.forall(n => n.toTermName == sel.rename))
719+
720+
def dealiasedSelector: Option[ImportSelector] =
708721
if isDerived then
709-
sels.flatMap(sel => selectionsToDealias.map(m => (sel, m.symbol))).collect {
722+
sels.flatMap(sel => selectionsToDealias.map(m => (sel, m.symbol))).collectFirst {
710723
case (sel, sym) if sym.dealias == dealiasedSym => sel
711-
}.headOption
724+
}
712725
else None
713-
def givenSelector = if sym.is(Given) || sym.is(Implicit)
714-
then sels.filter(sel => sel.isGiven && !sel.bound.isEmpty).find(sel => sel.boundTpe =:= sym.info)
726+
727+
def givenSelector: Option[ImportSelector] =
728+
if sym.is(Given) || sym.is(Implicit) then
729+
sels.filter(sel => sel.isGiven && !sel.bound.isEmpty).find(sel => sel.boundTpe =:= sym.info)
715730
else None
716-
def wildcard = sels.find(sel => sel.isWildcard && ((sym.is(Given) == sel.isGiven && sel.bound.isEmpty) || sym.is(Implicit)))
717-
if sym.exists && qualHasSymbol && (!isAccessible || sym.isRenamedSymbol(altName)) then
731+
732+
def wildcard: Option[ImportSelector] =
733+
sels.find(sel => sel.isWildcard && ((sym.is(Given) == sel.isGiven && sel.bound.isEmpty) || sym.is(Implicit)))
734+
735+
if qualHasSymbol && (!isAccessible || altName.exists(_.toSimpleName != sym.name.toSimpleName)) then
718736
selector.orElse(dealiasedSelector).orElse(givenSelector).orElse(wildcard) // selector with name or wildcard (or given)
719737
else
720738
None
721-
722-
private def isRenamedSymbol(symNameInScope: Option[Name])(using Context) =
723-
sym.name != nme.NO_NAME && symNameInScope.exists(_.toSimpleName != sym.name.toSimpleName)
739+
end isInImport
724740

725741
private def dealias(using Context): Symbol =
726742
if sym.isType && sym.asType.denot.isAliasType then

0 commit comments

Comments
 (0)