1
1
package dotty .tools .dotc .transform
2
2
3
3
import scala .annotation .tailrec
4
+ import scala .collection .mutable
4
5
5
6
import dotty .tools .uncheckedNN
6
7
import dotty .tools .dotc .ast .tpd
@@ -24,7 +25,7 @@ import dotty.tools.dotc.core.Mode
24
25
import dotty .tools .dotc .core .Types .{AnnotatedType , ConstantType , NoType , TermRef , Type , TypeTraverser }
25
26
import dotty .tools .dotc .core .Flags .flagsString
26
27
import dotty .tools .dotc .core .Flags
27
- import dotty .tools .dotc .core .Names .Name
28
+ import dotty .tools .dotc .core .Names .{ Name , TermName }
28
29
import dotty .tools .dotc .core .NameOps .isReplWrapperName
29
30
import dotty .tools .dotc .transform .MegaPhase .MiniPhase
30
31
import dotty .tools .dotc .core .Annotations
@@ -211,7 +212,7 @@ class CheckUnused private (phaseMode: CheckUnused.PhaseMode, suffix: String, _ke
211
212
/**
212
213
* This traverse is the **main** component of this phase
213
214
*
214
- * It traverse the tree the tree and gather the data in the
215
+ * It traverses the tree and gathers the data in the
215
216
* corresponding context property
216
217
*/
217
218
private def traverser = new TreeTraverser :
@@ -456,14 +457,21 @@ object CheckUnused:
456
457
val (wildcardSels, nonWildcardSels) = imp.selectors.partition(_.isWildcard)
457
458
nonWildcardSels ::: wildcardSels
458
459
460
+ val excludedMembers : mutable.Set [TermName ] = mutable.Set .empty
461
+
459
462
val newDataInScope =
460
463
for sel <- reorderdSelectors yield
461
464
val data = new ImportSelectorData (qualTpe, sel)
462
465
if shouldSelectorBeReported(imp, sel) || isImportExclusion(sel) || isImportIgnored(imp, sel) then
463
466
// Immediately mark the selector as used
464
467
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)
465
473
data
466
- impInScope.top.prependAll (newDataInScope)
474
+ impInScope.top.appendAll (newDataInScope)
467
475
end registerImport
468
476
469
477
/** Register (or not) some `val` or `def` according to the context, scope and flags */
@@ -703,7 +711,7 @@ object CheckUnused:
703
711
704
712
/** Given an import and accessibility, return selector that matches import<->symbol */
705
713
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 " )
707
715
708
716
val selector = selData.selector
709
717
@@ -719,7 +727,10 @@ object CheckUnused:
719
727
selData.allSymbolsForNamed.contains(sym)
720
728
else
721
729
// 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
723
734
// The qualifier does not have the target symbol as a member
724
735
false
725
736
else
@@ -832,11 +843,14 @@ object CheckUnused:
832
843
833
844
final class ImportSelectorData (val qualTpe : Type , val selector : ImportSelector ):
834
845
private var myUsed : Boolean = false
846
+ var excludedMembers : Set [TermName ] = Set .empty
835
847
836
848
def markUsed (): Unit = myUsed = true
837
849
838
850
def isUsed : Boolean = myUsed
839
851
852
+ def markExcluded (excluded : Set [TermName ]): Unit = excludedMembers ++= excluded
853
+
840
854
private var myAllSymbols : Set [Symbol ] | Null = null
841
855
842
856
def allSymbolsForNamed (using Context ): Set [Symbol ] =
0 commit comments