From 6195663f444cd715eea49e8012a59cfaf9d49152 Mon Sep 17 00:00:00 2001 From: Szymon Rodziewicz Date: Mon, 10 Apr 2023 20:19:48 +0200 Subject: [PATCH 1/3] WIP: Disable WUnused for params of non-private defs --- .../src/dotty/tools/dotc/transform/CheckUnused.scala | 12 +++++++++++- .../fatal-warnings/i15503-scala2/scala2-t11681.scala | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index d7c88a1fca40..d49e69c46206 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -114,6 +114,10 @@ class CheckUnused extends MiniPhase: override def prepareForDefDef(tree: tpd.DefDef)(using Context): Context = unusedDataApply{ ud => + if !tree.rawMods.is(Private) then + tree.termParamss.flatten.foreach { p => + ud.addIgnoredParam(p.symbol) + } import ud.registerTrivial tree.registerTrivial traverseAnnotations(tree.symbol) @@ -331,6 +335,8 @@ object CheckUnused: /** Trivial definitions, avoid registering params */ private val trivialDefs = MutSet[Symbol]() + private val paramsToSkip = MutSet[Symbol]() + /** * Push a new Scope of the given type, executes the given Unit and * pop it back to the original type. @@ -365,6 +371,10 @@ object CheckUnused: def removeIgnoredUsage(sym: Symbol)(using Context): Unit = doNotRegister --= sym.everySymbol + def addIgnoredParam(sym: Symbol)(using Context): Unit = + paramsToSkip += sym + + /** Register an import */ def registerImport(imp: tpd.Import)(using Context): Unit = @@ -380,7 +390,7 @@ object CheckUnused: if memDef.isValidParam then if memDef.symbol.isOneOf(GivenOrImplicit) then implicitParamInScope += memDef - else + else if !paramsToSkip.contains(memDef.symbol) then explicitParamInScope += memDef else if currScopeType.top == ScopeType.Local then localDefInScope += memDef diff --git a/tests/neg-custom-args/fatal-warnings/i15503-scala2/scala2-t11681.scala b/tests/neg-custom-args/fatal-warnings/i15503-scala2/scala2-t11681.scala index 18aa6879eeba..162bf9128a98 100644 --- a/tests/neg-custom-args/fatal-warnings/i15503-scala2/scala2-t11681.scala +++ b/tests/neg-custom-args/fatal-warnings/i15503-scala2/scala2-t11681.scala @@ -9,7 +9,7 @@ trait InterFace { } trait BadAPI extends InterFace { - def f(a: Int, + private def f(a: Int, b: String, // error c: Double): Int = { println(c) From 14dd04b1f11ec4c0aa5ed57fd4b744f134caf09b Mon Sep 17 00:00:00 2001 From: Szymon Rodziewicz Date: Thu, 13 Apr 2023 15:32:56 +0200 Subject: [PATCH 2/3] Handle implicit params and adjust tests in WUnused --- .../tools/dotc/transform/CheckUnused.scala | 5 ++-- .../i15503-scala2/scala2-t11681.scala | 22 +++++++++--------- .../fatal-warnings/i15503e.scala | 18 ++++++++------- .../fatal-warnings/i15503f.scala | 17 +++++++------- .../fatal-warnings/i15503g.scala | 23 ++++++++++--------- .../fatal-warnings/i15503h.scala | 2 +- .../fatal-warnings/i15503i.scala | 10 +++++--- 7 files changed, 52 insertions(+), 45 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index d49e69c46206..f083690db11f 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -374,8 +374,6 @@ object CheckUnused: def addIgnoredParam(sym: Symbol)(using Context): Unit = paramsToSkip += sym - - /** Register an import */ def registerImport(imp: tpd.Import)(using Context): Unit = if !tpd.languageImport(imp.expr).nonEmpty && !imp.isGeneratedByEnum && !isTransparentAndInline(imp) then @@ -389,7 +387,8 @@ object CheckUnused: if memDef.isValidMemberDef then if memDef.isValidParam then if memDef.symbol.isOneOf(GivenOrImplicit) then - implicitParamInScope += memDef + if !paramsToSkip.contains(memDef.symbol) then + implicitParamInScope += memDef else if !paramsToSkip.contains(memDef.symbol) then explicitParamInScope += memDef else if currScopeType.top == ScopeType.Local then diff --git a/tests/neg-custom-args/fatal-warnings/i15503-scala2/scala2-t11681.scala b/tests/neg-custom-args/fatal-warnings/i15503-scala2/scala2-t11681.scala index 162bf9128a98..c26ac6c57770 100644 --- a/tests/neg-custom-args/fatal-warnings/i15503-scala2/scala2-t11681.scala +++ b/tests/neg-custom-args/fatal-warnings/i15503-scala2/scala2-t11681.scala @@ -33,7 +33,7 @@ trait BadAPI extends InterFace { override def equals(other: Any): Boolean = true // OK - def i(implicit s: String) = answer // error + def i(implicit s: String) = answer // ok /* def future(x: Int): Int = { @@ -63,7 +63,7 @@ case class CaseyKasem(k: Int) // OK case class CaseyAtTheBat(k: Int)(s: String) // error trait Ignorance { - def f(readResolve: Int) = answer // error + def f(readResolve: Int) = answer // ok } class Reusing(u: Int) extends Unusing(u) // OK @@ -78,28 +78,28 @@ trait Unimplementation { } trait DumbStuff { - def f(implicit dummy: DummyImplicit) = answer // todo // error - def g(dummy: DummyImplicit) = answer // error + def f(implicit dummy: DummyImplicit) = answer // ok + def g(dummy: DummyImplicit) = answer // ok } trait Proofs { - def f[A, B](implicit ev: A =:= B) = answer // todo // error - def g[A, B](implicit ev: A <:< B) = answer // todo // error - def f2[A, B](ev: A =:= B) = answer // error - def g2[A, B](ev: A <:< B) = answer // error + def f[A, B](implicit ev: A =:= B) = answer // ok + def g[A, B](implicit ev: A <:< B) = answer // ok + def f2[A, B](ev: A =:= B) = answer // ok + def g2[A, B](ev: A <:< B) = answer // ok } trait Anonymous { - def f = (i: Int) => answer // error + def f = (i: Int) => answer // ok def f1 = (_: Int) => answer // OK def f2: Int => Int = _ + 1 // OK - def g = for (i <- List(1)) yield answer // error + def g = for (i <- List(1)) yield answer // ok } trait Context[A] trait Implicits { - def f[A](implicit ctx: Context[A]) = answer // error + def f[A](implicit ctx: Context[A]) = answer // ok def g[A: Context] = answer // OK } class Bound[A: Context] // OK diff --git a/tests/neg-custom-args/fatal-warnings/i15503e.scala b/tests/neg-custom-args/fatal-warnings/i15503e.scala index 56aec702a39e..6d166aff7347 100644 --- a/tests/neg-custom-args/fatal-warnings/i15503e.scala +++ b/tests/neg-custom-args/fatal-warnings/i15503e.scala @@ -1,14 +1,16 @@ // scalac: -Wunused:explicits -/* This goes around the "trivial method" detection */ -val default_val = 1 +object Foo { + /* This goes around the "trivial method" detection */ + val default_val = 1 -def f1(a: Int) = a // OK -def f2(a: Int) = default_val // error -def f3(a: Int)(using Int) = a // OK -def f4(a: Int)(using Int) = default_val // error -def f6(a: Int)(using Int) = summon[Int] // error -def f7(a: Int)(using Int) = summon[Int] + a // OK + private def f1(a: Int) = a // OK + private def f2(a: Int) = default_val // error + private def f3(a: Int)(using Int) = a // OK + private def f4(a: Int)(using Int) = default_val // error + private def f6(a: Int)(using Int) = summon[Int] // error + private def f7(a: Int)(using Int) = summon[Int] + a // OK +} package scala2main.unused.args: object happyBirthday { diff --git a/tests/neg-custom-args/fatal-warnings/i15503f.scala b/tests/neg-custom-args/fatal-warnings/i15503f.scala index 67c595d74f40..f909272af732 100644 --- a/tests/neg-custom-args/fatal-warnings/i15503f.scala +++ b/tests/neg-custom-args/fatal-warnings/i15503f.scala @@ -3,11 +3,12 @@ /* This goes around the "trivial method" detection */ val default_int = 1 -def f1(a: Int) = a // OK -def f2(a: Int) = 1 // OK -def f3(a: Int)(using Int) = a // OK -def f4(a: Int)(using Int) = default_int // OK -def f6(a: Int)(using Int) = summon[Int] // OK -def f7(a: Int)(using Int) = summon[Int] + a // OK -def f8(a: Int)(using foo: Int) = a // error - +object Xd { + private def f1(a: Int) = a // OK + private def f2(a: Int) = 1 // OK + private def f3(a: Int)(using Int) = a // OK + private def f4(a: Int)(using Int) = default_int // OK + private def f6(a: Int)(using Int) = summon[Int] // OK + private def f7(a: Int)(using Int) = summon[Int] + a // OK + private def f8(a: Int)(using foo: Int) = a // error +} diff --git a/tests/neg-custom-args/fatal-warnings/i15503g.scala b/tests/neg-custom-args/fatal-warnings/i15503g.scala index a0822e7e1611..0d71d516adad 100644 --- a/tests/neg-custom-args/fatal-warnings/i15503g.scala +++ b/tests/neg-custom-args/fatal-warnings/i15503g.scala @@ -1,15 +1,16 @@ // scalac: -Wunused:params /* This goes around the "trivial method" detection */ -val default_int = 1 +object Foo { + val default_int = 1 -def f1(a: Int) = a // OK -def f2(a: Int) = default_int // error -def f3(a: Int)(using Int) = a // OK -def f4(a: Int)(using Int) = default_int // error -def f6(a: Int)(using Int) = summon[Int] // error -def f7(a: Int)(using Int) = summon[Int] + a // OK - -/* --- Trivial method check --- */ -def g1(x: Int) = 1 // OK -def g2(x: Int) = ??? // OK \ No newline at end of file + private def f1(a: Int) = a // OK + private def f2(a: Int) = default_int // error + private def f3(a: Int)(using Int) = a // OK + private def f4(a: Int)(using Int) = default_int // error + private def f6(a: Int)(using Int) = summon[Int] // error + private def f7(a: Int)(using Int) = summon[Int] + a // OK + /* --- Trivial method check --- */ + private def g1(x: Int) = 1 // OK + private def g2(x: Int) = ??? // OK +} \ No newline at end of file diff --git a/tests/neg-custom-args/fatal-warnings/i15503h.scala b/tests/neg-custom-args/fatal-warnings/i15503h.scala index f8d1d6f2202f..3bab6cdbd098 100644 --- a/tests/neg-custom-args/fatal-warnings/i15503h.scala +++ b/tests/neg-custom-args/fatal-warnings/i15503h.scala @@ -7,7 +7,7 @@ class A { val b = 2 // OK private def c = 2 // error - def d(using x:Int): Int = b // error + def d(using x:Int): Int = b // ok def e(x: Int) = 1 // OK def f = val x = 1 // error diff --git a/tests/neg-custom-args/fatal-warnings/i15503i.scala b/tests/neg-custom-args/fatal-warnings/i15503i.scala index 9ac2ec5ef622..2b86e444c44f 100644 --- a/tests/neg-custom-args/fatal-warnings/i15503i.scala +++ b/tests/neg-custom-args/fatal-warnings/i15503i.scala @@ -17,10 +17,10 @@ class A { private def c2 = 2 // OK def c3 = c2 - def d1(using x:Int): Int = default_int // error + def d1(using x:Int): Int = default_int // ok def d2(using x:Int): Int = x // OK - def e1(x: Int) = default_int // error + def e1(x: Int) = default_int // ok def e2(x: Int) = x // OK def f = val x = 1 // error @@ -44,7 +44,11 @@ package foo.test.scala.annotation: val default_int = 12 def a1(a: Int) = a // OK - def a2(a: Int) = default_int // error + def a2(a: Int) = default_int // ok + + private def a2_p(a: Int) = default_int // error + def a2_p_used = a2_p(3) + def a3(@unused a: Int) = default_int //OK def b1 = From 013a2842092a31461b2a1eb4a7d81aa3cd762d70 Mon Sep 17 00:00:00 2001 From: Szymon Rodziewicz Date: Thu, 13 Apr 2023 17:28:33 +0200 Subject: [PATCH 3/3] Fix tests for WUnused/disable for public defs --- .../fatal-warnings/i15503e.scala | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/neg-custom-args/fatal-warnings/i15503e.scala b/tests/neg-custom-args/fatal-warnings/i15503e.scala index 6d166aff7347..57664cd08dcd 100644 --- a/tests/neg-custom-args/fatal-warnings/i15503e.scala +++ b/tests/neg-custom-args/fatal-warnings/i15503e.scala @@ -14,7 +14,7 @@ object Foo { package scala2main.unused.args: object happyBirthday { - def main(args: Array[String]): Unit = println("Hello World") // error + def main(args: Array[String]): Unit = println("Hello World") // ok } package scala2main: @@ -31,7 +31,7 @@ package scala3main: package foo.test.lambda.param: val default_val = 1 val a = (i: Int) => i // OK - val b = (i: Int) => default_val // error + val b = (i: Int) => default_val // OK val c = (_: Int) => default_val // OK package foo.test.trivial: @@ -39,19 +39,19 @@ package foo.test.trivial: class C { def answer: 42 = 42 object X - def g0(x: Int) = ??? // OK - def f0(x: Int) = () // OK - def f1(x: Int) = throw new RuntimeException // OK - def f2(x: Int) = 42 // OK - def f3(x: Int): Option[Int] = None // OK - def f4(x: Int) = classOf[Int] // OK - def f5(x: Int) = answer + 27 // OK - def f6(x: Int) = X // OK - def f7(x: Int) = Y // OK - def f8(x: Int): List[C] = Nil // OK - def f9(x: Int): List[Int] = List(1,2,3,4) // error - def foo:Int = 32 // OK - def f77(x: Int) = foo // error + private def g0(x: Int) = ??? // OK + private def f0(x: Int) = () // OK + private def f1(x: Int) = throw new RuntimeException // OK + private def f2(x: Int) = 42 // OK + private def f3(x: Int): Option[Int] = None // OK + private def f4(x: Int) = classOf[Int] // OK + private def f5(x: Int) = answer + 27 // OK + private def f6(x: Int) = X // OK + private def f7(x: Int) = Y // OK + private def f8(x: Int): List[C] = Nil // OK + private def f9(x: Int): List[Int] = List(1,2,3,4) // error + private def foo:Int = 32 // OK + private def f77(x: Int) = foo // error } object Y