Skip to content

Commit abdd570

Browse files
committed
Merge pull request scala#3885 from som-snytt/issue/8525-cleanup
SI-8525 Clarify usage of -Xlint:_,flag
2 parents 04cb634 + 68560dd commit abdd570

File tree

9 files changed

+133
-110
lines changed

9 files changed

+133
-110
lines changed

src/compiler/scala/tools/nsc/CompilerCommand.scala

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,15 @@ class CompilerCommand(arguments: List[String], val settings: Settings) {
103103
val components = global.phaseNames // global.phaseDescriptors // one initializes
104104
s"Phase graph of ${components.size} components output to ${genPhaseGraph.value}*.dot."
105105
}
106-
else ""
106+
// would be nicer if we could ask all the options for their helpful messages
107+
else {
108+
val sb = new StringBuilder
109+
allSettings foreach {
110+
case s: MultiChoiceSetting if s.isHelping => sb append s.help
111+
case _ =>
112+
}
113+
sb.toString
114+
}
107115
}
108116

109117
/**

src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ trait AbsScalaSettings {
2929
def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String): ChoiceSetting
3030
def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]): IntSetting
3131
def MultiStringSetting(name: String, helpArg: String, descr: String): MultiStringSetting
32-
def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: () => Unit): MultiChoiceSetting
32+
def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: () => Unit)(helper: MultiChoiceSetting => String): MultiChoiceSetting
3333
def OutputSetting(outputDirs: OutputDirs, default: String): OutputSetting
3434
def PathSetting(name: String, descr: String, default: String): PathSetting
3535
def PhasesSetting(name: String, descr: String, default: String): PhasesSetting

src/compiler/scala/tools/nsc/settings/MutableSettings.scala

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,10 @@ class MutableSettings(val errorFn: String => Unit)
211211
add(new ChoiceSetting(name, helpArg, descr, choices, default))
212212
def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]) = add(new IntSetting(name, descr, default, range, parser))
213213
def MultiStringSetting(name: String, arg: String, descr: String) = add(new MultiStringSetting(name, arg, descr))
214-
def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: () => Unit = () => ()) =
215-
add(new MultiChoiceSetting(name, helpArg, descr, choices, default))
214+
def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: () => Unit = () => ())(
215+
helper: MultiChoiceSetting => String = _ => choices.mkString(f"$descr:%n", f"%n ", f"%n")
216+
) =
217+
add(new MultiChoiceSetting(name, helpArg, descr, choices, default, helper))
216218
def OutputSetting(outputDirs: OutputDirs, default: String) = add(new OutputSetting(outputDirs, default))
217219
def PhasesSetting(name: String, descr: String, default: String = "") = add(new PhasesSetting(name, descr, default))
218220
def StringSetting(name: String, arg: String, descr: String, default: String) = add(new StringSetting(name, arg, descr, default))
@@ -552,7 +554,7 @@ class MutableSettings(val errorFn: String => Unit)
552554
}
553555

554556
/** A setting that receives any combination of enumerated values,
555-
* including "_" to mean all values.
557+
* including "_" to mean all values and "help" for verbose info.
556558
* In non-colonated mode, stops consuming args at the first
557559
* non-value, instead of at the next option, as for a multi-string.
558560
*/
@@ -561,19 +563,21 @@ class MutableSettings(val errorFn: String => Unit)
561563
arg: String,
562564
descr: String,
563565
override val choices: List[String],
564-
val default: () => Unit
565-
) extends MultiStringSetting(name, arg, s"$descr${ choices.mkString(": ", ",", ".") }") {
566+
val default: () => Unit,
567+
helper: MultiChoiceSetting => String
568+
) extends MultiStringSetting(name, s"_,$arg,-$arg", s"$descr: `_' for all, `$name:help' to list") {
566569

567-
def badChoice(s: String, n: String) = errorFn(s"'$s' is not a valid choice for '$name'")
568-
def choosing = choices.nonEmpty
569-
def isChoice(s: String) = (s == "_") || (choices contains (s stripPrefix "-"))
570-
def wildcards = choices // filter (!_.isSetByUser)
570+
private def badChoice(s: String, n: String) = errorFn(s"'$s' is not a valid choice for '$name'")
571+
private def choosing = choices.nonEmpty
572+
private def isChoice(s: String) = (s == "_") || (choices contains (s stripPrefix "-"))
573+
private var sawHelp = false
571574

572575
override protected def tts(args: List[String], halting: Boolean) = {
573-
val total = collection.mutable.ListBuffer.empty[String] ++ value
576+
val added = collection.mutable.ListBuffer.empty[String]
574577
def tryArg(arg: String) = arg match {
575-
case "_" if choosing => wildcards foreach (total += _)
576-
case s if !choosing || isChoice(s) => total += s
578+
case "_" if choosing => default()
579+
case "help" if choosing => sawHelp = true
580+
case s if !choosing || isChoice(s) => added += s
577581
case s => badChoice(s, name)
578582
}
579583
def stoppingAt(arg: String) = (arg startsWith "-") || (choosing && !isChoice(arg))
@@ -584,9 +588,12 @@ class MutableSettings(val errorFn: String => Unit)
584588
}
585589
val rest = loop(args)
586590
if (rest.size == args.size) default() // if no arg consumed, trigger default action
587-
else value = total.toList // update once
591+
else value = added.toList // update all new settings at once
588592
Some(rest)
589593
}
594+
595+
def isHelping: Boolean = sawHelp
596+
def help: String = helper(this)
590597
}
591598

592599
/** A setting that accumulates all strings supplied to it,

src/compiler/scala/tools/nsc/settings/ScalaSettings.scala

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,11 @@ trait ScalaSettings extends AbsScalaSettings
4444
/** If any of these settings is enabled, the compiler should print a message and exit. */
4545
def infoSettings = List[Setting](version, help, Xhelp, Yhelp, showPlugins, showPhases, genPhaseGraph)
4646

47+
/** Any -multichoice:help? Nicer if any option could report that it had help to offer. */
48+
private def multihelp = allSettings exists { case s: MultiChoiceSetting => s.isHelping case _ => false }
49+
4750
/** Is an info setting set? */
48-
def isInfo = infoSettings exists (_.isSetByUser)
51+
def isInfo = (infoSettings exists (_.isSetByUser)) || multihelp
4952

5053
/** Disable a setting */
5154
def disable(s: Setting) = allSettings -= s
@@ -67,8 +70,27 @@ trait ScalaSettings extends AbsScalaSettings
6770
// Would be nice to build this dynamically from scala.languageFeature.
6871
// The two requirements: delay error checking until you have symbols, and let compiler command build option-specific help.
6972
val language = {
70-
val features = List("dynamics", "postfixOps", "reflectiveCalls", "implicitConversions", "higherKinds", "existentials", "experimental.macros")
71-
MultiChoiceSetting("-language", "feature", "Enable one or more language features", features)
73+
val features = List(
74+
"dynamics" -> "Allow direct or indirect subclasses of scala.Dynamic",
75+
"postfixOps" -> "Allow postfix operator notation, such as `1 to 10 toList'",
76+
"reflectiveCalls" -> "Allow reflective access to members of structural types",
77+
"implicitConversions" -> "Allow definition of implicit functions called views",
78+
"higherKinds" -> "Allow higher-kinded types", // "Ask Adriaan, but if you have to ask..."
79+
"existentials" -> "Existential types (besides wildcard types) can be written and inferred",
80+
"experimental.macros" -> "Allow macro defintion (besides implementation and application)"
81+
)
82+
val description = "Enable or disable language features"
83+
MultiChoiceSetting(
84+
name = "-language",
85+
helpArg = "feature",
86+
descr = description,
87+
choices = features map (_._1)
88+
) { s =>
89+
val helpline: ((String, String)) => String = {
90+
case (name, text) => f" $name%-25s $text%n"
91+
}
92+
features map helpline mkString (f"$description:%n", "", f"%n")
93+
}
7294
}
7395

7496
/*

src/compiler/scala/tools/nsc/settings/Warnings.scala

Lines changed: 67 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@ trait Warnings {
1717
// Warning semantics.
1818
val fatalWarnings = BooleanSetting("-Xfatal-warnings", "Fail the compilation if there are any warnings.")
1919

20-
// These warnings are all so noisy as to be useless in their
20+
// These additional warnings are all so noisy as to be useless in their
2121
// present form, but have the potential to offer useful info.
2222
protected def allWarnings = lintWarnings ++ List(
2323
warnDeadCode,
2424
warnValueDiscard,
25-
warnNumericWiden
25+
warnNumericWiden,
26+
warnUnused, // SI-7712, SI-7707 warnUnused not quite ready for prime-time
27+
warnUnusedImport, // currently considered too noisy for general use
28+
warnValueOverrides // currently turned off as experimental
2629
)
2730
// These warnings should be pretty quiet unless you're doing
2831
// something inadvisable.
@@ -32,9 +35,6 @@ trait Warnings {
3235
warnNullaryUnit,
3336
warnAdaptedArgs,
3437
warnInferAny,
35-
// warnUnused SI-7712, SI-7707 warnUnused not quite ready for prime-time
36-
// warnUnusedImport currently considered too noisy for general use
37-
// warnValueOverrides
3838
warnMissingInterpolator,
3939
warnDocDetached,
4040
warnPrivateShadow,
@@ -46,22 +46,26 @@ trait Warnings {
4646
warnUnsoundMatch
4747
)
4848

49-
private lazy val warnSelectNullable = BooleanSetting("-Xcheck-null", "This option is obsolete and does nothing.")
49+
// Individual warnings. They can be set with -Ywarn.
50+
private def nonlintflag(name: String, text: String): BooleanSetting = BooleanSetting(name, text)
5051

51-
// Individual warnings.
52-
val warnDeadCode = BooleanSetting("-Ywarn-dead-code",
52+
val warnDeadCode = nonlintflag("-Ywarn-dead-code",
5353
"Warn when dead code is identified.")
54-
val warnValueDiscard = BooleanSetting("-Ywarn-value-discard",
54+
val warnValueDiscard = nonlintflag("-Ywarn-value-discard",
5555
"Warn when non-Unit expression results are unused.")
56-
val warnNumericWiden = BooleanSetting("-Ywarn-numeric-widen",
56+
val warnNumericWiden = nonlintflag("-Ywarn-numeric-widen",
5757
"Warn when numerics are widened.")
58-
val warnUnused = BooleanSetting("-Ywarn-unused",
58+
val warnUnused = nonlintflag("-Ywarn-unused",
5959
"Warn when local and private vals, vars, defs, and types are are unused")
60-
val warnUnusedImport = BooleanSetting("-Ywarn-unused-import",
60+
val warnUnusedImport = nonlintflag("-Ywarn-unused-import",
6161
"Warn when imports are unused")
6262

63-
// Lint warnings that are not -Y, created with new instead of autoregistering factory method
64-
private def lintflag(name: String, text: String) = new BooleanSetting(name, text)
63+
// Lint warnings that have no -Y avatar, created with new instead of the autoregistering factory method.
64+
// They evaluate true if set to true or else are unset but -Xlint is true
65+
private def lintflag(name: String, text: String): BooleanSetting =
66+
new BooleanSetting(name, text) {
67+
override def value = if (isSetByUser) super.value else xlint
68+
}
6569

6670
val warnAdaptedArgs = lintflag("adapted-args",
6771
"Warn if an argument list is modified to match the receiver.")
@@ -92,59 +96,65 @@ trait Warnings {
9296
val warnUnsoundMatch = lintflag("unsound-match",
9397
"Pattern match may not be typesafe")
9498

95-
// Lint warnings that are not enabled yet
96-
val warnValueOverrides = lintflag("value-overrides", "Generated value class method overrides an implementation")
99+
// Experimental lint warnings that are turned off, but which could be turned on programmatically.
100+
// These warnings are said to blind those who dare enable them.
101+
// They are not activated by -Xlint and can't be enabled on the command line.
102+
val warnValueOverrides = {
103+
val flag = lintflag("value-overrides", "Generated value class method overrides an implementation")
104+
flag.value = false
105+
flag
106+
}
97107

98-
// Warning groups.
99-
val lint = {
100-
// Boolean setting for testing if lint is on; not "added" to option processing
101-
val xlint = lintflag("-Xlint", "Enable recommended additional warnings.")
102-
val yprefix = "-Ywarn-"
103-
def lintables = (lintWarnings map (_.name stripPrefix yprefix)).sorted
104-
def isAnon(b: BooleanSetting) = !(b.name startsWith "-")
105-
def setPolitely(b: BooleanSetting, v: Boolean) = if (!b.isSetByUser) b.value = v
106-
def set(w: String, v: Boolean) = lintWarnings find (s => (s.name stripPrefix yprefix) == w) foreach (b => setPolitely(b, v))
107-
val Neg = "-"
108-
def propagate(ss: List[String]): Unit = ss match {
109-
case w :: rest => if (w startsWith Neg) set(w stripPrefix Neg, false) else set(w, true) ; propagate(rest)
110-
case Nil => ()
111-
}
112-
// enable lint and the group, honoring previous -Y settings
113-
def enableAll(): Unit = {
114-
xlint.value = true
115-
for (s <- lintWarnings) setPolitely(s, true)
108+
// The Xlint warning group.
109+
private val xlint = new BooleanSetting("-Zunused", "True if -Xlint or -Xlint:_")
110+
// On -Xlint or -Xlint:_, set xlint, otherwise set the lint warning unless already set true
111+
val lint = {
112+
val description = "Enable or disable specific warnings"
113+
val choices = (lintWarnings map (_.name)).sorted
114+
MultiChoiceSetting(
115+
name = "-Xlint",
116+
helpArg = "warning",
117+
descr = description,
118+
choices = choices,
119+
default = () => xlint.value = true
120+
) { s =>
121+
def helpline(n: String) = lintWarnings.find(_.name == n).map(w => f" ${w.name}%-25s ${w.helpDescription}%n")
122+
choices flatMap (helpline(_)) mkString (f"$description:%n", "", f"%n")
123+
} withPostSetHook { x =>
124+
val Neg = "-"
125+
def setPolitely(b: BooleanSetting, v: Boolean) = if (!b.isSetByUser || !b) b.value = v
126+
def set(w: String, v: Boolean) = lintWarnings find (_.name == w) foreach (setPolitely(_, v))
127+
def propagate(ss: List[String]): Unit = ss match {
128+
case w :: rest => if (w startsWith Neg) set(w stripPrefix Neg, false) else set(w, true) ; propagate(rest)
129+
case Nil => ()
130+
}
131+
propagate(x.value)
116132
}
117-
// The command option
118-
MultiChoiceSetting("-Xlint", "warning", "Enable recommended additional warnings", choices = lintables, default = enableAll) withPostSetHook { x =>
119-
propagate(x.value) // enabling the selections (on each append to value)
120-
xlint.value = true // only enables lint, not the group
121-
for (b <- lintWarnings if isAnon(b) && !b.isSetByUser) b.value = true // init anonymous settings (but not if disabled)
122-
}
123-
xlint
124133
}
125134

126135
// Lint warnings that are currently -Y, but deprecated in that usage
127-
// Alas, the -Yarg must have a doppelgaenger that is not deprecated
128-
@deprecated("Use the Xlint flag", since="2.11.2")
136+
@deprecated("Use warnAdaptedArgs", since="2.11.2")
129137
val YwarnAdaptedArgs = BooleanSetting("-Ywarn-adapted-args",
130-
"Warn if an argument list is modified to match the receiver.") withDeprecationMessage
131-
"Enable -Xlint:adapted-args" enabling List(warnAdaptedArgs)
132-
@deprecated("Use the Xlint flag", since="2.11.2")
138+
"Warn if an argument list is modified to match the receiver.") enabling List(warnAdaptedArgs)
139+
//withDeprecationMessage "Enable -Xlint:adapted-args"
140+
@deprecated("Use warnNullaryUnit", since="2.11.2")
133141
val YwarnNullaryUnit = BooleanSetting("-Ywarn-nullary-unit",
134-
"Warn when nullary methods return Unit.") withDeprecationMessage
135-
"Enable -Xlint:nullary-unit" enabling List(warnNullaryUnit)
136-
@deprecated("Use the Xlint flag", since="2.11.2")
142+
"Warn when nullary methods return Unit.") enabling List(warnNullaryUnit)
143+
//withDeprecationMessage "Enable -Xlint:nullary-unit"
144+
@deprecated("Use warnInaccessible", since="2.11.2")
137145
val YwarnInaccessible = BooleanSetting("-Ywarn-inaccessible",
138-
"Warn about inaccessible types in method signatures.") withDeprecationMessage
139-
"Enable -Xlint:inaccessible" enabling List(warnInaccessible)
140-
@deprecated("Use the Xlint flag", since="2.11.2")
146+
"Warn about inaccessible types in method signatures.") enabling List(warnInaccessible)
147+
//withDeprecationMessage "Enable -Xlint:inaccessible"
148+
@deprecated("Use warnNullaryOverride", since="2.11.2")
141149
val YwarnNullaryOverride = BooleanSetting("-Ywarn-nullary-override",
142-
"Warn when non-nullary `def f()' overrides nullary `def f'.") withDeprecationMessage
143-
"Enable -Xlint:nullary-override" enabling List(warnNullaryOverride)
144-
@deprecated("Use the Xlint flag", since="2.11.2")
150+
"Warn when non-nullary `def f()' overrides nullary `def f'.") enabling List(warnNullaryOverride)
151+
//withDeprecationMessage "Enable -Xlint:nullary-override"
152+
@deprecated("Use warnInferAny", since="2.11.2")
145153
val YwarnInferAny = BooleanSetting("-Ywarn-infer-any",
146-
"Warn when a type argument is inferred to be `Any`.") withDeprecationMessage
147-
"Enable -Xlint:infer-any" enabling List(warnInferAny)
154+
"Warn when a type argument is inferred to be `Any`.") enabling List(warnInferAny)
155+
//withDeprecationMessage "Enable -Xlint:infer-any"
156+
157+
private lazy val warnSelectNullable = BooleanSetting("-Xcheck-null", "This option is obsolete and does nothing.")
148158

149159
// Backward compatibility.
150160
@deprecated("Use fatalWarnings", "2.11.0") def Xwarnfatal = fatalWarnings // used by sbt

test/files/neg/t8610-arg.check

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,6 @@
1-
t8610-arg.scala:5: warning: possible missing interpolator: detected interpolated identifier `$name`
2-
def x = "Hi, $name" // missing interp
3-
^
4-
t8610-arg.scala:7: warning: Adapting argument list by creating a 2-tuple: this may not be what you want.
5-
signature: X.f(p: (Int, Int)): Int
6-
given arguments: 3, 4
7-
after adaptation: X.f((3, 4): (Int, Int))
8-
def g = f(3, 4) // adapted
9-
^
10-
t8610-arg.scala:9: warning: private[this] value name in class X shadows mutable name inherited from class Named. Changes to name will not be visible within class X - you may want to give them distinct names.
11-
override def toString = name // shadowing mutable var name
12-
^
131
t8610-arg.scala:8: warning: side-effecting nullary methods are discouraged: suggest defining as `def u()` instead
142
def u: Unit = () // unitarian universalist
153
^
164
error: No warnings can be incurred under -Xfatal-warnings.
17-
four warnings found
5+
one warning found
186
one error found

test/files/neg/t8610-arg.flags

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
-Xfatal-warnings -Xlint warn-nullary-unit
1+
-Xfatal-warnings -Xlint nullary-unit

test/files/run/t8610.check

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
1-
t8610.scala:4: warning: possible missing interpolator: detected interpolated identifier `$name`
2-
def x = "Hi, $name" // missing interp
3-
^
41
t8610.scala:6: warning: Adapting argument list by creating a 2-tuple: this may not be what you want.
52
signature: X.f(p: (Int, Int)): Int
63
given arguments: 3, 4
74
after adaptation: X.f((3, 4): (Int, Int))
85
def g = f(3, 4) // adapted
96
^
10-
t8610.scala:7: warning: side-effecting nullary methods are discouraged: suggest defining as `def u()` instead
11-
def u: Unit = () // unitarian universalist
12-
^
137
Hi, $name

0 commit comments

Comments
 (0)