Skip to content

Commit

Permalink
WIP: Disable WUnused for params of non-private defs (scala#17223)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kordyjan authored Apr 13, 2023
2 parents 45fb481 + 013a284 commit 083027e
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 60 deletions.
13 changes: 11 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/CheckUnused.scala
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ class CheckUnused private (phaseMode: CheckUnused.PhaseMode, suffix: String, _ke

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)
Expand Down Expand Up @@ -350,6 +354,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.
Expand Down Expand Up @@ -396,6 +402,8 @@ 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 =
Expand All @@ -410,8 +418,9 @@ object CheckUnused:
if memDef.isValidMemberDef then
if memDef.isValidParam then
if memDef.symbol.isOneOf(GivenOrImplicit) then
implicitParamInScope += memDef
else
if !paramsToSkip.contains(memDef.symbol) then
implicitParamInScope += memDef
else if !paramsToSkip.contains(memDef.symbol) then
explicitParamInScope += memDef
else if currScopeType.top == ScopeType.Local then
localDefInScope += memDef
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 = {
Expand Down Expand Up @@ -63,7 +63,7 @@ case class CaseyKasem(k: Int) // OK
case class CaseyAtTheBat(k: Int)(s: String) // ok

trait Ignorance {
def f(readResolve: Int) = answer // error
def f(readResolve: Int) = answer // ok
}

class Reusing(u: Int) extends Unusing(u) // OK
Expand All @@ -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
Expand Down
48 changes: 25 additions & 23 deletions tests/neg-custom-args/fatal-warnings/i15503e.scala
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
// 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 {
def main(args: Array[String]): Unit = println("Hello World") // error
def main(args: Array[String]): Unit = println("Hello World") // ok
}

package scala2main:
Expand All @@ -29,27 +31,27 @@ 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:
/* A twisted test from Scala 2 */
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

Expand Down
17 changes: 9 additions & 8 deletions tests/neg-custom-args/fatal-warnings/i15503f.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
23 changes: 12 additions & 11 deletions tests/neg-custom-args/fatal-warnings/i15503g.scala
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
// 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
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
}

package foo.test.i17101:
type Test[A] = A
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-custom-args/fatal-warnings/i15503h.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 7 additions & 3 deletions tests/neg-custom-args/fatal-warnings/i15503i.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 =
Expand Down

0 comments on commit 083027e

Please sign in to comment.