Skip to content

Commit 906dc04

Browse files
committed
Fix CheckUnused missed some used symbols
- Register every symbol and related (companion, module, etc.) - Fix #16682 - Update test suits
1 parent 722acb9 commit 906dc04

File tree

3 files changed

+55
-13
lines changed

3 files changed

+55
-13
lines changed

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

+28-12
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,9 @@ class CheckUnused extends MiniPhase:
9797

9898
override def prepareForValDef(tree: tpd.ValDef)(using Context): Context =
9999
_key.unusedDataApply{ud =>
100-
ud.registerDef(tree)
100+
// do not register the ValDef generated for `object`
101+
if !tree.symbol.is(Module) then
102+
ud.registerDef(tree)
101103
ud.addIgnoredUsage(tree.symbol)
102104
}
103105

@@ -336,15 +338,11 @@ object CheckUnused:
336338

337339
/** Register a symbol that should be ignored */
338340
def addIgnoredUsage(sym: Symbol)(using Context): Unit =
339-
doNotRegister += sym
340-
if sym.is(Flags.Module) then
341-
doNotRegister += sym.moduleClass
341+
doNotRegister ++= sym.everySymbol
342342

343343
/** Remove a symbol that shouldn't be ignored anymore */
344344
def removeIgnoredUsage(sym: Symbol)(using Context): Unit =
345-
doNotRegister -= sym
346-
if sym.is(Flags.Module) then
347-
doNotRegister -= sym.moduleClass
345+
doNotRegister --= sym.everySymbol
348346

349347

350348
/** Register an import */
@@ -442,27 +440,37 @@ object CheckUnused:
442440
Nil
443441
val sortedLocalDefs =
444442
if ctx.settings.WunusedHas.locals then
445-
localDefInScope.filter(d => !usedDef(d.symbol)).map(d => d.namePos -> WarnTypes.LocalDefs).toList
443+
localDefInScope
444+
.filterNot(d => d.symbol.usedDefContains)
445+
.map(d => d.namePos -> WarnTypes.LocalDefs).toList
446446
else
447447
Nil
448448
val sortedExplicitParams =
449449
if ctx.settings.WunusedHas.explicits then
450-
explicitParamInScope.filter(d => !usedDef(d.symbol)).map(d => d.namePos -> WarnTypes.ExplicitParams).toList
450+
explicitParamInScope
451+
.filterNot(d => d.symbol.usedDefContains)
452+
.map(d => d.namePos -> WarnTypes.ExplicitParams).toList
451453
else
452454
Nil
453455
val sortedImplicitParams =
454456
if ctx.settings.WunusedHas.implicits then
455-
implicitParamInScope.filter(d => !usedDef(d.symbol)).map(d => d.namePos -> WarnTypes.ImplicitParams).toList
457+
implicitParamInScope
458+
.filterNot(d => d.symbol.usedDefContains)
459+
.map(d => d.namePos -> WarnTypes.ImplicitParams).toList
456460
else
457461
Nil
458462
val sortedPrivateDefs =
459463
if ctx.settings.WunusedHas.privates then
460-
privateDefInScope.filter(d => !usedDef(d.symbol)).map(d => d.namePos -> WarnTypes.PrivateMembers).toList
464+
privateDefInScope
465+
.filterNot(d => d.symbol.usedDefContains)
466+
.map(d => d.namePos -> WarnTypes.PrivateMembers).toList
461467
else
462468
Nil
463469
val sortedPatVars =
464470
if ctx.settings.WunusedHas.patvars then
465-
patVarsInScope.filter(d => !usedDef(d.symbol)).map(d => d.namePos -> WarnTypes.PatVars).toList
471+
patVarsInScope
472+
.filterNot(d => d.symbol.usedDefContains)
473+
.map(d => d.namePos -> WarnTypes.PatVars).toList
466474
else
467475
Nil
468476
val warnings = List(sortedImp, sortedLocalDefs, sortedExplicitParams, sortedImplicitParams, sortedPrivateDefs, sortedPatVars).flatten.sortBy { s =>
@@ -562,6 +570,14 @@ object CheckUnused:
562570
else
563571
false
564572

573+
private def usedDefContains(using Context): Boolean =
574+
sym.everySymbol.exists(usedDef.apply)
575+
576+
private def everySymbol(using Context): List[Symbol] =
577+
List(sym, sym.companionClass, sym.companionModule, sym.moduleClass).filter(_.exists)
578+
579+
end extension
580+
565581
extension (defdef: tpd.DefDef)
566582
// so trivial that it never consumes params
567583
private def isTrivial(using Context): Boolean =

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

+13
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

+14-1
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)