11package dotty .tools .dotc .transform
22
33import scala .annotation .tailrec
4+ import scala .collection .mutable
45
56import dotty .tools .uncheckedNN
67import dotty .tools .dotc .ast .tpd
@@ -24,7 +25,7 @@ import dotty.tools.dotc.core.Mode
2425import dotty .tools .dotc .core .Types .{AnnotatedType , ConstantType , NoType , TermRef , Type , TypeTraverser }
2526import dotty .tools .dotc .core .Flags .flagsString
2627import dotty .tools .dotc .core .Flags
27- import dotty .tools .dotc .core .Names .Name
28+ import dotty .tools .dotc .core .Names .{ Name , TermName }
2829import dotty .tools .dotc .core .NameOps .isReplWrapperName
2930import dotty .tools .dotc .transform .MegaPhase .MiniPhase
3031import dotty .tools .dotc .core .Annotations
@@ -211,7 +212,7 @@ class CheckUnused private (phaseMode: CheckUnused.PhaseMode, suffix: String, _ke
211212 /**
212213 * This traverse is the **main** component of this phase
213214 *
214- * It traverse the tree the tree and gather the data in the
215+ * It traverses the tree and gathers the data in the
215216 * corresponding context property
216217 */
217218 private def traverser = new TreeTraverser :
@@ -456,14 +457,21 @@ object CheckUnused:
456457 val (wildcardSels, nonWildcardSels) = imp.selectors.partition(_.isWildcard)
457458 nonWildcardSels ::: wildcardSels
458459
460+ val excludedMembers : mutable.Set [TermName ] = mutable.Set .empty
461+
459462 val newDataInScope =
460463 for sel <- reorderdSelectors yield
461464 val data = new ImportSelectorData (qualTpe, sel)
462465 if shouldSelectorBeReported(imp, sel) || isImportExclusion(sel) || isImportIgnored(imp, sel) then
463466 // Immediately mark the selector as used
464467 data.markUsed()
468+ if isImportExclusion(sel) then
469+ excludedMembers += sel.name
470+ if sel.isWildcard && excludedMembers.nonEmpty then
471+ // mark excluded members for the wildcard import
472+ data.markExcluded(excludedMembers.toSet)
465473 data
466- impInScope.top.prependAll (newDataInScope)
474+ impInScope.top.appendAll (newDataInScope)
467475 end registerImport
468476
469477 /** Register (or not) some `val` or `def` according to the context, scope and flags */
@@ -703,7 +711,7 @@ object CheckUnused:
703711
704712 /** Given an import and accessibility, return selector that matches import<->symbol */
705713 private def isInImport (selData : ImportSelectorData , altName : Option [Name ], isDerived : Boolean )(using Context ): Boolean =
706- assert(sym.exists)
714+ assert(sym.exists, s " Symbol $sym does not exist " )
707715
708716 val selector = selData.selector
709717
@@ -719,7 +727,10 @@ object CheckUnused:
719727 selData.allSymbolsForNamed.contains(sym)
720728 else
721729 // Wildcard
722- if ! selData.qualTpe.member(sym.name).hasAltWith(_.symbol == sym) then
730+ if selData.excludedMembers.contains(altName.getOrElse(sym.name).toTermName) then
731+ // Wildcard with exclusions that match the symbol
732+ false
733+ else if ! selData.qualTpe.member(sym.name).hasAltWith(_.symbol == sym) then
723734 // The qualifier does not have the target symbol as a member
724735 false
725736 else
@@ -832,11 +843,14 @@ object CheckUnused:
832843
833844 final class ImportSelectorData (val qualTpe : Type , val selector : ImportSelector ):
834845 private var myUsed : Boolean = false
846+ var excludedMembers : Set [TermName ] = Set .empty
835847
836848 def markUsed (): Unit = myUsed = true
837849
838850 def isUsed : Boolean = myUsed
839851
852+ def markExcluded (excluded : Set [TermName ]): Unit = excludedMembers ++= excluded
853+
840854 private var myAllSymbols : Set [Symbol ] | Null = null
841855
842856 def allSymbolsForNamed (using Context ): Set [Symbol ] =
0 commit comments