Skip to content

Commit cd5affc

Browse files
committed
Dealias only conditionally when symbol is derived val type in wunused
1 parent e7f310b commit cd5affc

File tree

1 file changed

+15
-12
lines changed

1 file changed

+15
-12
lines changed

compiler/src/dotty/tools/dotc/transform/CheckUnused.scala

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import dotty.tools.dotc.core.Annotations
2424
import dotty.tools.dotc.core.Definitions
2525
import dotty.tools.dotc.core.NameKinds.WildcardParamName
2626
import dotty.tools.dotc.core.Symbols.Symbol
27-
27+
import dotty.tools.dotc.core.StdNames.nme
2828

2929

3030
/**
@@ -109,6 +109,9 @@ class CheckUnused extends MiniPhase:
109109
traverseAnnotations(tree.symbol)
110110
if !tree.symbol.is(Module) then
111111
ud.registerDef(tree)
112+
if tree.name.mangledString.startsWith(nme.derived.mangledString + "$")
113+
&& tree.typeOpt != NoType then
114+
ud.registerUsed(tree.typeOpt.typeSymbol, None, true)
112115
ud.addIgnoredUsage(tree.symbol)
113116
}
114117

@@ -304,7 +307,7 @@ object CheckUnused:
304307
*
305308
* See the `isAccessibleAsIdent` extension method below in the file
306309
*/
307-
private val usedInScope = MutStack(MutSet[(Symbol,Boolean, Option[Name])]())
310+
private val usedInScope = MutStack(MutSet[(Symbol,Boolean, Option[Name], Boolean)]())
308311
private val usedInPosition = MutSet[(SrcPos, Name)]()
309312
/* unused import collected during traversal */
310313
private val unusedImport = MutSet[ImportSelector]()
@@ -347,14 +350,14 @@ object CheckUnused:
347350
* The optional name will be used to target the right import
348351
* as the same element can be imported with different renaming
349352
*/
350-
def registerUsed(sym: Symbol, name: Option[Name])(using Context): Unit =
353+
def registerUsed(sym: Symbol, name: Option[Name], isDerived: Boolean = false)(using Context): Unit =
351354
if !isConstructorOfSynth(sym) && !doNotRegister(sym) then
352355
if sym.isConstructor && sym.exists then
353356
registerUsed(sym.owner, None) // constructor are "implicitly" imported with the class
354357
else
355-
usedInScope.top += ((sym, sym.isAccessibleAsIdent, name))
356-
usedInScope.top += ((sym.companionModule, sym.isAccessibleAsIdent, name))
357-
usedInScope.top += ((sym.companionClass, sym.isAccessibleAsIdent, name))
358+
usedInScope.top += ((sym, sym.isAccessibleAsIdent, name, isDerived))
359+
usedInScope.top += ((sym.companionModule, sym.isAccessibleAsIdent, name, isDerived))
360+
usedInScope.top += ((sym.companionClass, sym.isAccessibleAsIdent, name, isDerived))
358361
name.map(n => usedInPosition += ((sym.sourcePos, n)))
359362

360363
/** Register a symbol that should be ignored */
@@ -408,15 +411,15 @@ object CheckUnused:
408411
// used symbol in this scope
409412
val used = usedInScope.pop().toSet
410413
// used imports in this scope
411-
val imports = impInScope.pop().toSet
414+
val imports = impInScope.pop()
412415
val kept = used.filterNot { t =>
413-
val (sym, isAccessible, optName) = t
416+
val (sym, isAccessible, optName, isDerived) = t
414417
// keep the symbol for outer scope, if it matches **no** import
415418
// This is the first matching wildcard selector
416419
var selWildCard: Option[ImportSelector] = None
417420

418421
val exists = imports.exists { imp =>
419-
sym.isInImport(imp, isAccessible, optName) match
422+
sym.isInImport(imp, isAccessible, optName, isDerived) match
420423
case None => false
421424
case optSel@Some(sel) if sel.isWildcard =>
422425
if selWildCard.isEmpty then selWildCard = optSel
@@ -587,7 +590,7 @@ object CheckUnused:
587590
}
588591

589592
/** Given an import and accessibility, return an option of selector that match import<->symbol */
590-
private def isInImport(imp: tpd.Import, isAccessible: Boolean, symName: Option[Name])(using Context): Option[ImportSelector] =
593+
private def isInImport(imp: tpd.Import, isAccessible: Boolean, symName: Option[Name], isDerived: Boolean)(using Context): Option[ImportSelector] =
591594
val tpd.Import(qual, sels) = imp
592595
val dealiasedSym = dealias(sym)
593596
val simpleSelections = qual.tpe.member(sym.name).alternatives
@@ -596,9 +599,9 @@ object CheckUnused:
596599
val selectionsToDealias = typeSelections ::: termSelections
597600
val qualHasSymbol = simpleSelections.map(_.symbol).contains(sym) || (simpleSelections ::: selectionsToDealias).map(_.symbol).map(dealias).contains(dealiasedSym)
598601
def selector = sels.find(sel => (sel.name.toTermName == sym.name || sel.name.toTypeName == sym.name) && symName.map(n => n.toTermName == sel.rename).getOrElse(true))
599-
def dealiasedSelector = sels.flatMap(sel => selectionsToDealias.map(m => (sel, m.symbol))).collect {
602+
def dealiasedSelector = if(isDerived) sels.flatMap(sel => selectionsToDealias.map(m => (sel, m.symbol))).collect {
600603
case (sel, sym) if dealias(sym) == dealiasedSym => sel
601-
}.headOption
604+
}.headOption else None
602605
def wildcard = sels.find(sel => sel.isWildcard && ((sym.is(Given) == sel.isGiven) || sym.is(Implicit)))
603606
if qualHasSymbol && !isAccessible && sym.exists then
604607
selector.orElse(dealiasedSelector).orElse(wildcard) // selector with name or wildcard (or given)

0 commit comments

Comments
 (0)