@@ -203,8 +203,11 @@ class CheckUnused private (phaseMode: CheckUnused.PhaseMode, suffix: String, _ke
203
203
override def traverse (tree : tpd.Tree )(using Context ): Unit =
204
204
val newCtx = if tree.symbol.exists then ctx.withOwner(tree.symbol) else ctx
205
205
tree match
206
- case imp: tpd.Import =>
206
+ case imp : tpd.Import =>
207
207
unusedDataApply(_.registerImport(imp))
208
+ imp.selectors.filter(_.isGiven).map(_.bound).collect {
209
+ case untpd.TypedSplice (tree1) => tree1
210
+ }.foreach(traverse(_)(using newCtx))
208
211
traverseChildren(tree)(using newCtx)
209
212
case ident : Ident =>
210
213
prepareForIdent(ident)
@@ -450,13 +453,12 @@ object CheckUnused:
450
453
val used = usedInScope.pop().toSet
451
454
// used imports in this scope
452
455
val imports = impInScope.pop()
453
- val kept = used.filterNot { t =>
454
- val (sym, isAccessible, optName, isDerived) = t
456
+ val kept = used.filterNot { (sym, isAccessible, optName, isDerived) =>
455
457
// keep the symbol for outer scope, if it matches **no** import
456
458
// This is the first matching wildcard selector
457
459
var selWildCard : Option [ImportSelector ] = None
458
460
459
- val exists = imports.exists { imp =>
461
+ val matchedExplicitImport = imports.exists { imp =>
460
462
sym.isInImport(imp, isAccessible, optName, isDerived) match
461
463
case None => false
462
464
case optSel@ Some (sel) if sel.isWildcard =>
@@ -467,11 +469,11 @@ object CheckUnused:
467
469
unusedImport -= sel
468
470
true
469
471
}
470
- if ! exists && selWildCard.isDefined then
472
+ if ! matchedExplicitImport && selWildCard.isDefined then
471
473
unusedImport -= selWildCard.get
472
474
true // a matching import exists so the symbol won't be kept for outer scope
473
475
else
474
- exists
476
+ matchedExplicitImport
475
477
}
476
478
477
479
// if there's an outer scope
@@ -611,12 +613,17 @@ object CheckUnused:
611
613
* return true
612
614
*/
613
615
private def shouldSelectorBeReported (imp : tpd.Import , sel : ImportSelector )(using Context ): Boolean =
614
- if ctx.settings.WunusedHas .strictNoImplicitWarn then
616
+ ctx.settings.WunusedHas .strictNoImplicitWarn && (
615
617
sel.isWildcard ||
616
618
imp.expr.tpe.member(sel.name.toTermName).alternatives.exists(_.symbol.isOneOf(GivenOrImplicit )) ||
617
619
imp.expr.tpe.member(sel.name.toTypeName).alternatives.exists(_.symbol.isOneOf(GivenOrImplicit ))
618
- else
619
- false
620
+ )
621
+
622
+ extension (tree : ImportSelector )
623
+ def boundTpe : Type = tree.bound match {
624
+ case untpd.TypedSplice (tree1) => tree1.tpe
625
+ case _ => NoType
626
+ }
620
627
621
628
extension (sym : Symbol )
622
629
/** is accessible without import in current context */
@@ -629,7 +636,7 @@ object CheckUnused:
629
636
&& c.owner.thisType.member(sym.name).alternatives.contains(sym)
630
637
}
631
638
632
- /** Given an import and accessibility, return an option of selector that match import<->symbol */
639
+ /** Given an import and accessibility, return selector that matches import<->symbol */
633
640
private def isInImport (imp : tpd.Import , isAccessible : Boolean , symName : Option [Name ], isDerived : Boolean )(using Context ): Option [ImportSelector ] =
634
641
val tpd .Import (qual, sels) = imp
635
642
val dealiasedSym = dealias(sym)
@@ -642,9 +649,12 @@ object CheckUnused:
642
649
def dealiasedSelector = if (isDerived) sels.flatMap(sel => selectionsToDealias.map(m => (sel, m.symbol))).collect {
643
650
case (sel, sym) if dealias(sym) == dealiasedSym => sel
644
651
}.headOption else None
645
- def wildcard = sels.find(sel => sel.isWildcard && ((sym.is(Given ) == sel.isGiven) || sym.is(Implicit )))
652
+ def givenSelector = if sym.is(Given ) || sym.is(Implicit )
653
+ then sels.filter(sel => sel.isGiven && ! sel.bound.isEmpty).find(sel => sel.boundTpe =:= sym.info)
654
+ else None
655
+ def wildcard = sels.find(sel => sel.isWildcard && ((sym.is(Given ) == sel.isGiven && sel.bound.isEmpty) || sym.is(Implicit )))
646
656
if qualHasSymbol && (! isAccessible || sym.isRenamedSymbol(symName)) && sym.exists then
647
- selector.orElse(dealiasedSelector).orElse(wildcard) // selector with name or wildcard (or given)
657
+ selector.orElse(dealiasedSelector).orElse(givenSelector).orElse( wildcard) // selector with name or wildcard (or given)
648
658
else
649
659
None
650
660
0 commit comments