@@ -10,6 +10,7 @@ import dotty.tools.dotc.ast.untpd.ImportSelector
1010import dotty .tools .dotc .config .ScalaSettings
1111import dotty .tools .dotc .core .Contexts .*
1212import dotty .tools .dotc .core .Decorators .{em , i }
13+ import dotty .tools .dotc .core .Denotations .SingleDenotation
1314import dotty .tools .dotc .core .Flags .*
1415import dotty .tools .dotc .core .Phases .Phase
1516import dotty .tools .dotc .core .StdNames
@@ -406,13 +407,18 @@ object CheckUnused:
406407 * as the same element can be imported with different renaming
407408 */
408409 def registerUsed (sym : Symbol , name : Option [Name ], isDerived : Boolean = false )(using Context ): Unit =
409- if ! isConstructorOfSynth(sym) && ! doNotRegister(sym) then
410- if sym.isConstructor && sym.exists then
410+ if sym.exists && ! isConstructorOfSynth(sym) && ! doNotRegister(sym) then
411+ if sym.isConstructor then
411412 registerUsed(sym.owner, None ) // constructor are "implicitly" imported with the class
412413 else
413- usedInScope.top += ((sym, sym.isAccessibleAsIdent, name, isDerived))
414- usedInScope.top += ((sym.companionModule, sym.isAccessibleAsIdent, name, isDerived))
415- usedInScope.top += ((sym.companionClass, sym.isAccessibleAsIdent, name, isDerived))
414+ val accessibleAsIdent = sym.isAccessibleAsIdent
415+ def addIfExists (sym : Symbol ): Unit =
416+ if sym.exists then
417+ usedDef += sym
418+ usedInScope.top += ((sym, accessibleAsIdent, name, isDerived))
419+ addIfExists(sym)
420+ addIfExists(sym.companionModule)
421+ addIfExists(sym.companionClass)
416422 if sym.sourcePos.exists then
417423 for n <- name do
418424 usedInPosition.getOrElseUpdate(n, MutSet .empty) += sym
@@ -505,8 +511,6 @@ object CheckUnused:
505511 // we keep the symbols not referencing an import in this scope
506512 // as it can be the only reference to an outer import
507513 usedInScope.top ++= kept
508- // register usage in this scope for other warnings at the end of the phase
509- usedDef ++= used.map(_._1)
510514 // retrieve previous scope type
511515 currScopeType.pop
512516 end popScope
@@ -682,40 +686,64 @@ object CheckUnused:
682686 extension (sym : Symbol )
683687 /** is accessible without import in current context */
684688 private def isAccessibleAsIdent (using Context ): Boolean =
685- sym.exists &&
686- ctx.outersIterator.exists{ c =>
687- c.owner == sym.owner
688- || sym.owner.isClass && c.owner.isClass
689- && c.owner.thisType.baseClasses.contains(sym.owner)
690- && c.owner.thisType.member(sym.name).alternatives.contains(sym)
691- }
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+ }
692695
693696 /** Given an import and accessibility, return selector that matches import<->symbol */
694697 private def isInImport (imp : tpd.Import , isAccessible : Boolean , symName : Option [Name ], isDerived : Boolean )(using Context ): Option [ImportSelector ] =
698+ assert(sym.exists)
699+
695700 val tpd .Import (qual, sels) = imp
696- val dealiasedSym = dealias(sym)
697- val simpleSelections = qual.tpe.member(sym.name).alternatives
698- val typeSelections = sels.flatMap(n => qual.tpe.member(n.name.toTypeName).alternatives)
699- val termSelections = sels.flatMap(n => qual.tpe.member(n.name.toTermName).alternatives)
700- val sameTermPath = qual.isTerm && sym.exists && sym.owner.isType && qual.tpe.typeSymbol == sym.owner.asType
701- val selectionsToDealias = typeSelections ::: termSelections
702- val renamedSelection = if sameTermPath then sels.find(sel => sel.imported.name == sym.name) else None
703- val qualHasSymbol = simpleSelections.map(_.symbol).contains(sym) || (simpleSelections ::: selectionsToDealias).map(_.symbol).map(dealias).contains(dealiasedSym) || renamedSelection.isDefined
704- def selector = sels.find(sel => (sel.name.toTermName == sym.name || sel.name.toTypeName == sym.name) && symName.map(n => n.toTermName == sel.rename).getOrElse(true ))
705- def dealiasedSelector = if (isDerived) sels.flatMap(sel => selectionsToDealias.map(m => (sel, m.symbol))).collect {
706- case (sel, sym) if dealias(sym) == dealiasedSym => sel
707- }.headOption else None
708- def givenSelector = if sym.is(Given ) || sym.is(Implicit )
709- then sels.filter(sel => sel.isGiven && ! sel.bound.isEmpty).find(sel => sel.boundTpe =:= sym.info)
710- else None
711- def wildcard = sels.find(sel => sel.isWildcard && ((sym.is(Given ) == sel.isGiven && sel.bound.isEmpty) || sym.is(Implicit )))
712- if qualHasSymbol && (! isAccessible || sym.isRenamedSymbol(symName)) && sym.exists then
713- selector.orElse(dealiasedSelector).orElse(givenSelector).orElse(wildcard).orElse(renamedSelection) // selector with name or wildcard (or given)
714- else
715- None
716701
717- private def isRenamedSymbol (symNameInScope : Option [Name ])(using Context ) =
718- sym.name != nme.NO_NAME && symNameInScope.exists(_.toSimpleName != sym.name.toSimpleName)
702+ val renamedSelection : Option [ImportSelector ] =
703+ val sameTermPath = qual.isTerm && sym.owner.isType && qual.tpe.typeSymbol == sym.owner.asType
704+ if sameTermPath then sels.find(sel => sel.name == sym.name) else None
705+
706+ if renamedSelection.isDefined then
707+ renamedSelection
708+ else
709+ val dealiasedSym : Symbol = dealias(sym)
710+
711+ val selectionsToDealias : List [SingleDenotation ] =
712+ val typeSelections = sels.flatMap(n => qual.tpe.member(n.name.toTypeName).alternatives)
713+ val termSelections = sels.flatMap(n => qual.tpe.member(n.name.toTermName).alternatives)
714+ typeSelections ::: termSelections
715+
716+ val qualHasSymbol : Boolean =
717+ val simpleSelections = qual.tpe.member(sym.name).alternatives
718+ simpleSelections.exists(d => d.symbol == sym || dealias(d.symbol) == dealiasedSym)
719+ || selectionsToDealias.exists(d => dealias(d.symbol) == dealiasedSym)
720+
721+ def selector : Option [ImportSelector ] =
722+ sels.find(sel => sym.name.toTermName == sel.name && symName.forall(n => n.toTermName == sel.rename))
723+
724+ def dealiasedSelector : Option [ImportSelector ] =
725+ if isDerived then
726+ sels.flatMap(sel => selectionsToDealias.map(m => (sel, m.symbol))).collectFirst {
727+ case (sel, sym) if dealias(sym) == dealiasedSym => sel
728+ }
729+ else
730+ None
731+
732+ def givenSelector : Option [ImportSelector ] =
733+ if sym.is(Given ) || sym.is(Implicit ) then
734+ sels.filter(sel => sel.isGiven && ! sel.bound.isEmpty).find(sel => sel.boundTpe =:= sym.info)
735+ else
736+ None
737+
738+ def wildcard : Option [ImportSelector ] =
739+ sels.find(sel => sel.isWildcard && ((sym.is(Given ) == sel.isGiven && sel.bound.isEmpty) || sym.is(Implicit )))
740+
741+ if qualHasSymbol && (! isAccessible || symName.exists(_.toSimpleName != sym.name.toSimpleName)) then
742+ selector.orElse(dealiasedSelector).orElse(givenSelector).orElse(wildcard) // selector with name or wildcard (or given)
743+ else
744+ None
745+ end if
746+ end isInImport
719747
720748 private def dealias (symbol : Symbol )(using Context ): Symbol =
721749 if (symbol.isType && symbol.asType.denot.isAliasType) then
0 commit comments