From bc99ccd830f3eb3e7bbd188c143ded42ede08bbc Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 25 Nov 2020 12:37:47 -0800 Subject: [PATCH] Lint option for unused context bounds --- src/compiler/scala/tools/nsc/settings/Warnings.scala | 6 ++++-- .../scala/tools/nsc/typechecker/TypeDiagnostics.scala | 4 +++- test/files/neg/warn-unused-explicits.check | 6 ++++++ test/files/neg/warn-unused-explicits.scala | 10 ++++++++++ test/files/neg/warn-unused-params.check | 11 ++++++++++- test/files/neg/warn-unused-params.scala | 10 ++++++++-- 6 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 test/files/neg/warn-unused-explicits.check create mode 100644 test/files/neg/warn-unused-explicits.scala diff --git a/src/compiler/scala/tools/nsc/settings/Warnings.scala b/src/compiler/scala/tools/nsc/settings/Warnings.scala index 2703f4a0ea39..9dbe262b4e81 100644 --- a/src/compiler/scala/tools/nsc/settings/Warnings.scala +++ b/src/compiler/scala/tools/nsc/settings/Warnings.scala @@ -124,8 +124,9 @@ trait Warnings { val Locals = Choice("locals", "Warn if a local definition is unused.") val Explicits = Choice("explicits", "Warn if an explicit parameter is unused.") val Implicits = Choice("implicits", "Warn if an implicit parameter is unused.") + val Synthetics = Choice("synthetics", "Warn if a synthetic implicit parameter (context bound) is unused.") val Nowarn = Choice("nowarn", "Warn if a @nowarn annotation does not suppress any warnings.") - val Params = Choice("params", "Enable -Wunused:explicits,implicits.", expandsTo = List(Explicits, Implicits)) + val Params = Choice("params", "Enable -Wunused:explicits,implicits,synthetics.", expandsTo = List(Explicits, Implicits, Synthetics)) val Linted = Choice("linted", "-Xlint:unused.", expandsTo = List(Imports, Privates, Locals, Implicits, Nowarn)) } @@ -142,9 +143,10 @@ trait Warnings { def warnUnusedPatVars = warnUnused contains UnusedWarnings.PatVars def warnUnusedPrivates = warnUnused contains UnusedWarnings.Privates def warnUnusedLocals = warnUnused contains UnusedWarnings.Locals - def warnUnusedParams = warnUnusedExplicits || warnUnusedImplicits + def warnUnusedParams = warnUnusedExplicits || warnUnusedImplicits || warnUnusedSynthetics def warnUnusedExplicits = warnUnused contains UnusedWarnings.Explicits def warnUnusedImplicits = warnUnused contains UnusedWarnings.Implicits + def warnUnusedSynthetics = warnUnused contains UnusedWarnings.Synthetics def warnUnusedNowarn = warnUnused contains UnusedWarnings.Nowarn val warnExtraImplicit = BooleanSetting("-Wextra-implicit", "Warn when more than one implicit parameter section is defined.") withAbbreviation "-Ywarn-extra-implicit" diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 4e70ec399426..2ee0a2efba1f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -597,7 +597,9 @@ trait TypeDiagnostics { case nme.CONSTRUCTOR => sym.owner.companion.isCaseClass case nme.copy => sym.owner.typeSignature.member(nme.copy).isSynthetic } - sym.isDefaultGetter && !privateSyntheticDefault + def defaultGetterOK = sym.isDefaultGetter && !privateSyntheticDefault + def contextBoundOK = sym.isImplicit && settings.warnUnusedSynthetics + contextBoundOK || defaultGetterOK } def isUnusedTerm(m: Symbol): Boolean = ( m.isTerm diff --git a/test/files/neg/warn-unused-explicits.check b/test/files/neg/warn-unused-explicits.check new file mode 100644 index 000000000000..06cc4bcf5c60 --- /dev/null +++ b/test/files/neg/warn-unused-explicits.check @@ -0,0 +1,6 @@ +warn-unused-explicits.scala:9: warning: parameter value x in method warn is never used + def warn(x: Int) = 42 + ^ +error: No warnings can be incurred under -Werror. +1 warning +1 error diff --git a/test/files/neg/warn-unused-explicits.scala b/test/files/neg/warn-unused-explicits.scala new file mode 100644 index 000000000000..fb147c2c2fb9 --- /dev/null +++ b/test/files/neg/warn-unused-explicits.scala @@ -0,0 +1,10 @@ +// scalac: -Wunused:explicits -Werror +// +trait Context[A] +trait ExplicitsOnly { + def i(implicit s: String) = 42 + def f[A](implicit ctx: Context[A]) = 42 + def g[A: Context] = 42 + + def warn(x: Int) = 42 +} diff --git a/test/files/neg/warn-unused-params.check b/test/files/neg/warn-unused-params.check index 6c72ad9087db..36f4a5430567 100644 --- a/test/files/neg/warn-unused-params.check +++ b/test/files/neg/warn-unused-params.check @@ -28,6 +28,15 @@ warn-unused-params.scala:89: warning: parameter value i in anonymous function is warn-unused-params.scala:95: warning: parameter value i in anonymous function is never used def g = for (i <- List(1)) yield 42 // warn map.(i => 42) ^ +warn-unused-params.scala:99: warning: parameter value ctx in method f is never used + def f[A](implicit ctx: Context[A]) = 42 + ^ +warn-unused-params.scala:100: warning: parameter value evidence$1 in method g is never used + def g[A: Context] = 42 + ^ +warn-unused-params.scala:102: warning: parameter value evidence$2 in class Bound is never used +class Bound[A: Context] + ^ error: No warnings can be incurred under -Werror. -10 warnings +13 warnings 1 error diff --git a/test/files/neg/warn-unused-params.scala b/test/files/neg/warn-unused-params.scala index 870a6fcf986e..47d2eec1a87e 100644 --- a/test/files/neg/warn-unused-params.scala +++ b/test/files/neg/warn-unused-params.scala @@ -1,4 +1,4 @@ -// scalac: -Ywarn-unused:params -Xfatal-warnings +// scalac: -Wunused:params -Werror // trait InterFace { @@ -13,7 +13,7 @@ trait BadAPI extends InterFace { println(c) a } - @deprecated ("no warn in deprecated API", since="yesterday") + @deprecated("no warn in deprecated API", since="yesterday") def g(a: Int, b: String, // no warn c: Double): Int = { @@ -94,3 +94,9 @@ trait Anonymous { def g = for (i <- List(1)) yield 42 // warn map.(i => 42) } +trait Context[A] +trait Implicits { + def f[A](implicit ctx: Context[A]) = 42 + def g[A: Context] = 42 +} +class Bound[A: Context]