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