Skip to content

Commit 90e7556

Browse files
authored
Fix #16682: CheckUnused missed some used symbols (#16690)
- Register every symbol and related (companion, module, etc.) - Fixes #16682 - Update test suits @szymon-rd
2 parents 7527594 + 906dc04 commit 90e7556

File tree

3 files changed

+55
-13
lines changed

3 files changed

+55
-13
lines changed

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

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ class CheckUnused extends MiniPhase:
102102

103103
override def prepareForValDef(tree: tpd.ValDef)(using Context): Context =
104104
_key.unusedDataApply{ud =>
105-
ud.registerDef(tree)
105+
// do not register the ValDef generated for `object`
106+
if !tree.symbol.is(Module) then
107+
ud.registerDef(tree)
106108
ud.addIgnoredUsage(tree.symbol)
107109
}
108110

@@ -341,15 +343,11 @@ object CheckUnused:
341343

342344
/** Register a symbol that should be ignored */
343345
def addIgnoredUsage(sym: Symbol)(using Context): Unit =
344-
doNotRegister += sym
345-
if sym.is(Flags.Module) then
346-
doNotRegister += sym.moduleClass
346+
doNotRegister ++= sym.everySymbol
347347

348348
/** Remove a symbol that shouldn't be ignored anymore */
349349
def removeIgnoredUsage(sym: Symbol)(using Context): Unit =
350-
doNotRegister -= sym
351-
if sym.is(Flags.Module) then
352-
doNotRegister -= sym.moduleClass
350+
doNotRegister --= sym.everySymbol
353351

354352

355353
/** Register an import */
@@ -447,27 +445,37 @@ object CheckUnused:
447445
Nil
448446
val sortedLocalDefs =
449447
if ctx.settings.WunusedHas.locals then
450-
localDefInScope.filter(d => !usedDef(d.symbol)).map(d => d.namePos -> WarnTypes.LocalDefs).toList
448+
localDefInScope
449+
.filterNot(d => d.symbol.usedDefContains)
450+
.map(d => d.namePos -> WarnTypes.LocalDefs).toList
451451
else
452452
Nil
453453
val sortedExplicitParams =
454454
if ctx.settings.WunusedHas.explicits then
455-
explicitParamInScope.filter(d => !usedDef(d.symbol)).map(d => d.namePos -> WarnTypes.ExplicitParams).toList
455+
explicitParamInScope
456+
.filterNot(d => d.symbol.usedDefContains)
457+
.map(d => d.namePos -> WarnTypes.ExplicitParams).toList
456458
else
457459
Nil
458460
val sortedImplicitParams =
459461
if ctx.settings.WunusedHas.implicits then
460-
implicitParamInScope.filter(d => !usedDef(d.symbol)).map(d => d.namePos -> WarnTypes.ImplicitParams).toList
462+
implicitParamInScope
463+
.filterNot(d => d.symbol.usedDefContains)
464+
.map(d => d.namePos -> WarnTypes.ImplicitParams).toList
461465
else
462466
Nil
463467
val sortedPrivateDefs =
464468
if ctx.settings.WunusedHas.privates then
465-
privateDefInScope.filter(d => !usedDef(d.symbol)).map(d => d.namePos -> WarnTypes.PrivateMembers).toList
469+
privateDefInScope
470+
.filterNot(d => d.symbol.usedDefContains)
471+
.map(d => d.namePos -> WarnTypes.PrivateMembers).toList
466472
else
467473
Nil
468474
val sortedPatVars =
469475
if ctx.settings.WunusedHas.patvars then
470-
patVarsInScope.filter(d => !usedDef(d.symbol)).map(d => d.namePos -> WarnTypes.PatVars).toList
476+
patVarsInScope
477+
.filterNot(d => d.symbol.usedDefContains)
478+
.map(d => d.namePos -> WarnTypes.PatVars).toList
471479
else
472480
Nil
473481
val warnings = List(sortedImp, sortedLocalDefs, sortedExplicitParams, sortedImplicitParams, sortedPrivateDefs, sortedPatVars).flatten.sortBy { s =>
@@ -567,6 +575,14 @@ object CheckUnused:
567575
else
568576
false
569577

578+
private def usedDefContains(using Context): Boolean =
579+
sym.everySymbol.exists(usedDef.apply)
580+
581+
private def everySymbol(using Context): List[Symbol] =
582+
List(sym, sym.companionClass, sym.companionModule, sym.moduleClass).filter(_.exists)
583+
584+
end extension
585+
570586
extension (defdef: tpd.DefDef)
571587
// so trivial that it never consumes params
572588
private def isTrivial(using Context): Boolean =

tests/neg-custom-args/fatal-warnings/i15503b.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,16 @@ package foo.scala2.tests:
8787
(new Bippy): Something
8888
}
8989
}
90+
91+
package test.foo.twisted.i16682:
92+
def myPackage =
93+
object IntExtractor: // OK
94+
def unapply(s: String): Option[Int] = s.toIntOption
95+
96+
def isInt(s: String) = s match { // OK
97+
case IntExtractor(i) => println(s"Number $i")
98+
case _ => println("NaN")
99+
}
100+
isInt
101+
102+
def f = myPackage("42")

tests/neg-custom-args/fatal-warnings/i15503c.scala

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,17 @@ package foo.test.contructors:
2424
class B private (val x: Int) // OK
2525
class C private (private val x: Int) // error
2626
class D private (private val x: Int): // OK
27-
def y = x
27+
def y = x
28+
29+
30+
package test.foo.i16682:
31+
object myPackage:
32+
private object IntExtractor: // OK
33+
def unapply(s: String): Option[Int] = s.toIntOption
34+
35+
def isInt(s: String) = s match {
36+
case IntExtractor(i) => println(s"Number $i")
37+
case _ => println("NaN")
38+
}
39+
40+
def f = myPackage.isInt("42")

0 commit comments

Comments
 (0)