@@ -24,7 +24,7 @@ import dotty.tools.dotc.core.Annotations
2424import dotty .tools .dotc .core .Definitions
2525import dotty .tools .dotc .core .NameKinds .WildcardParamName
2626import 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