summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSom Snytt <som.snytt@gmail.com>2014-08-25 10:15:04 -0700
committerLukas Rytz <lukas.rytz@gmail.com>2014-09-05 20:27:59 +0200
commit7655a70489f565a5a7a165f893b4a1e44c3cb2b8 (patch)
tree9a2a54ae5802211c5444006ffea06aef497bbe3b
parentb562d965dc30bb1fdd9433a6675bfe8e38b8c667 (diff)
downloadscala-7655a70489f565a5a7a165f893b4a1e44c3cb2b8.tar.gz
scala-7655a70489f565a5a7a165f893b4a1e44c3cb2b8.tar.bz2
scala-7655a70489f565a5a7a165f893b4a1e44c3cb2b8.zip
Use Enumeration for MultiChoiceSetting
This is pretty easy, since a ValueSet is a BitSet. When the setting is updated, recompute the current set of values, which is cheap and succinct. Checking a flag is also easy and fast. Choices in MultiChoiceSettings may enable other choices.
-rw-r--r--src/compiler/scala/tools/nsc/CompilerCommand.scala2
-rw-r--r--src/compiler/scala/tools/nsc/MainBench.scala2
-rw-r--r--src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala24
-rw-r--r--src/compiler/scala/tools/nsc/settings/MutableSettings.scala241
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala39
-rw-r--r--src/compiler/scala/tools/nsc/settings/Warnings.scala100
-rw-r--r--src/compiler/scala/tools/nsc/util/StatisticsInfo.scala2
-rw-r--r--test/junit/scala/tools/nsc/settings/SettingsTest.scala46
8 files changed, 288 insertions, 168 deletions
diff --git a/src/compiler/scala/tools/nsc/CompilerCommand.scala b/src/compiler/scala/tools/nsc/CompilerCommand.scala
index 3ded456378..9b8e9fa330 100644
--- a/src/compiler/scala/tools/nsc/CompilerCommand.scala
+++ b/src/compiler/scala/tools/nsc/CompilerCommand.scala
@@ -107,7 +107,7 @@ class CompilerCommand(arguments: List[String], val settings: Settings) {
else {
val sb = new StringBuilder
allSettings foreach {
- case s: MultiChoiceSetting if s.isHelping => sb append s.help
+ case s: MultiChoiceSetting[_] if s.isHelping => sb append s.help
case _ =>
}
sb.toString
diff --git a/src/compiler/scala/tools/nsc/MainBench.scala b/src/compiler/scala/tools/nsc/MainBench.scala
index eb56c8a230..f01de0cbe1 100644
--- a/src/compiler/scala/tools/nsc/MainBench.scala
+++ b/src/compiler/scala/tools/nsc/MainBench.scala
@@ -24,7 +24,7 @@ object MainBench extends Driver with EvalLoop {
var start = System.nanoTime()
for (i <- 0 until NIter) {
if (i == NIter-1) {
- theCompiler.settings.YstatisticsPhases.value = theCompiler.settings.YstatisticsPhases.default.get
+ theCompiler.settings.Ystatistics.default.get foreach theCompiler.settings.Ystatistics.add
Statistics.enabled = true
}
process(args)
diff --git a/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala
index cd2cb183b3..6b339b2a6d 100644
--- a/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala
@@ -7,20 +7,24 @@ package scala
package tools.nsc
package settings
+import scala.language.higherKinds
+
trait AbsScalaSettings {
self: AbsSettings =>
+ type MultiChoiceEnumeration <: Enumeration
+
type Setting <: AbsSetting
- type BooleanSetting <: Setting { type T = Boolean }
- type ChoiceSetting <: Setting { type T = String }
- type IntSetting <: Setting { type T = Int }
- type MultiStringSetting <: Setting { type T = List[String] }
- type MultiChoiceSetting <: Setting { type T = List[String] }
- type PathSetting <: Setting { type T = String }
- type PhasesSetting <: Setting { type T = List[String] }
- type StringSetting <: Setting { type T = String }
- type PrefixSetting <: Setting { type T = List[String] }
+ type BooleanSetting <: Setting { type T = Boolean }
+ type ChoiceSetting <: Setting { type T = String }
+ type IntSetting <: Setting { type T = Int }
+ type MultiStringSetting <: Setting { type T = List[String] }
+ type MultiChoiceSetting[E <: MultiChoiceEnumeration] <: Setting { type T <: E#ValueSet }
+ type PathSetting <: Setting { type T = String }
+ type PhasesSetting <: Setting { type T = List[String] }
+ type StringSetting <: Setting { type T = String }
+ type PrefixSetting <: Setting { type T = List[String] }
type OutputDirs
type OutputSetting <: Setting
@@ -29,7 +33,7 @@ trait AbsScalaSettings {
def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String): ChoiceSetting
def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]): IntSetting
def MultiStringSetting(name: String, helpArg: String, descr: String): MultiStringSetting
- def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], descriptions: List[String], default: Option[List[String]]): MultiChoiceSetting
+ def MultiChoiceSetting[E <: MultiChoiceEnumeration](name: String, helpArg: String, descr: String, domain: E, default: Option[List[String]]): MultiChoiceSetting[E]
def OutputSetting(outputDirs: OutputDirs, default: String): OutputSetting
def PathSetting(name: String, descr: String, default: String): PathSetting
def PhasesSetting(name: String, descr: String, default: String): PhasesSetting
diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
index b9b9257d63..78d7061066 100644
--- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
@@ -212,8 +212,8 @@ class MutableSettings(val errorFn: String => Unit)
def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]) =
add(new IntSetting(name, descr, default, range, parser))
def MultiStringSetting(name: String, arg: String, descr: String) = add(new MultiStringSetting(name, arg, descr))
- def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], descriptions: List[String], default: Option[List[String]] = None) =
- add(new MultiChoiceSetting(name, helpArg, descr, choices, descriptions, default))
+ def MultiChoiceSetting[E <: MultiChoiceEnumeration](name: String, helpArg: String, descr: String, domain: E, default: Option[List[String]] = None) =
+ add(new MultiChoiceSetting[E](name, helpArg, descr, domain, default))
def OutputSetting(outputDirs: OutputDirs, default: String) = add(new OutputSetting(outputDirs, default))
def PhasesSetting(name: String, descr: String, default: String = "") = add(new PhasesSetting(name, descr, default))
def StringSetting(name: String, arg: String, descr: String, default: String) = add(new StringSetting(name, arg, descr, default))
@@ -366,7 +366,7 @@ class MutableSettings(val errorFn: String => Unit)
def withDeprecationMessage(msg: String): this.type = { _deprecationMessage = Some(msg) ; this }
}
- /** A setting represented by an integer */
+ /** A setting represented by an integer. */
class IntSetting private[nsc](
name: String,
descr: String,
@@ -553,122 +553,179 @@ class MutableSettings(val errorFn: String => Unit)
}
/**
- * A setting that receives multiple values. There are two modes
- * - choosing: the setting has a list of allowed chioces.
- * - These choices can be positive or negative, for exmample "-option:positive,-negative"
- * - If an option is both enabled positively and negatively, the positive wins
- * - The choice "_" enables all choices that have not explicitly been disabled
+ * Each [[MultiChoiceSetting]] takes a MultiChoiceEnumeration as domain. The enumartion may
+ * use the Choice class to define values, or simply use the default `Value` constructor:
*
- * - !choosing: the setting accumulates all arguments.
+ * object SettingDomain extends MultiChoiceEnumeration { val arg1, arg2 = Value }
*
- * Arguments can be provided in colonated or non-colonated mode, i.e. "-option a b" or
- * "-option:a,b". Note that arguments starting with a "-" can only be provided in colonated mode,
- * otherwise they are interpreted as a new option.
+ * Or
*
- * In colonated and choosing mode, the setting stops consuming arguments at the first non-choice,
- * i.e. "-option a b c" only consumes "a" and "b" if "c" is not a valid choice.
+ * object SettingDomain extends MultiChoiceEnumeration {
+ * val arg1 = Choice("arg1", "help")
+ * val arg2 = Choice("arg2", "help")
+ * }
*
- * @param name command-line setting name, eg "-Xlint"
- * @param arg description of the kind of arguments that need to be passed, eg "warning"
- * @param descr description of the setting
- * @param choices a list of allowed arguments. if empty, accepts any argument that doesn't start with "-"
- * @param descriptions a description for each choice (for the help message), may be empty if no descriptions are necessary
- * @param default default arguments, if none are provided
+ * Choices with a non-empty `expandsTo` enable other options. Note that expanding choices are
+ * not present in the multiChoiceSetting.value set, only their expansion.
*/
- class MultiChoiceSetting private[nsc](
+ abstract class MultiChoiceEnumeration extends Enumeration {
+ case class Choice(name: String, help: String = "", expandsTo: List[Choice] = Nil) extends Val(name)
+ }
+
+ /** A Setting that collects string-valued settings from an enumerated domain.
+ * - These choices can be turned on or off: "-option:on,-off"
+ * - If an option is set both on and off, then the option is on
+ * - The choice "_" enables all choices that have not been explicitly disabled
+ *
+ * Arguments can be provided in colonated or non-colonated mode, i.e. "-option a b" or
+ * "-option:a,b". Note that arguments starting with a "-" can only be provided in colonated mode,
+ * otherwise they are interpreted as a new option.
+ *
+ * In non-colonated mode, the setting stops consuming arguments at the first non-choice,
+ * i.e. "-option a b c" only consumes "a" and "b" if "c" is not a valid choice.
+ *
+ * @param name command-line setting name, eg "-Xlint"
+ * @param helpArg help description for the kind of arguments it takes, eg "warning"
+ * @param descr description of the setting
+ * @param domain enumeration of choices implementing MultiChoice, or the string value is
+ * taken for the name
+ * @param default If Some(args), the default options if none are provided. If None, an
+ * error is printed if there are no arguments.
+ */
+ class MultiChoiceSetting[E <: MultiChoiceEnumeration] private[nsc](
name: String,
- arg: String,
+ helpArg: String,
descr: String,
- override val choices: List[String],
- val descriptions: List[String],
+ val domain: E,
val default: Option[List[String]]
- ) extends MultiStringSetting(name, s"_,$arg,-$arg", s"$descr: `_' for all, `$name:help' to list") {
+ ) extends Setting(name, s"$descr: `_' for all, `$name:help' to list") with Clearable {
+
+ withHelpSyntax(s"$name:<_,$helpArg,-$helpArg>")
- private def badChoice(s: String, n: String) = errorFn(s"'$s' is not a valid choice for '$name'")
- private def choosing = choices.nonEmpty // choices are known, error on invalid args
- private def isChoice(s: String) = (s == "_") || (choices contains (s stripPrefix "-"))
+ object ChoiceOrVal {
+ def unapply(a: Any): Option[(String, String, List[domain.Choice])] = a match {
+ case c: domain.Choice => Some((c.name, c.help, c.expandsTo))
+ case v: domain.Value => Some((v.toString, "", Nil))
+ case _ => None
+ }
+ }
- private var sawHelp = false
- private var sawAll = false
+ type T = domain.ValueSet
+ protected var v: T = domain.ValueSet.empty
+
+ // Explicitly enabled or disabled. Yeas may contain expanding options, nays may not.
+ private var yeas = domain.ValueSet.empty
+ private var nays = domain.ValueSet.empty
+
+ // Asked for help
+ private var sawHelp = false
+ // Wildcard _ encountered
+ private var sawAll = false
+
+ private def badChoice(s: String) = errorFn(s"'$s' is not a valid choice for '$name'")
+ private def isChoice(s: String) = (s == "_") || (choices contains pos(s))
private def pos(s: String) = s stripPrefix "-"
+ private def isPos(s: String) = !(s startsWith "-")
- /**
- * This override takes care of including all possible choices in case the "_" argument was
- * passed. It adds the choices that have not explicitly been enabled or disabled. This ensures
- * that "this contains x" is consistent with "this.value contains x".
- *
- * The explicitly enabled / disabled options are stored in the underlying value [[v]], disabled
- * ones are stored as "-arg".
- *
- * The fact that value and v are not the same leaks in some cases. For example, you should never
- * use "value += arg", because that expands to "value = value + arg". In case sawAll is true,
- * this would propagate all choices enabled by sawAll into the underlying v.
- *
- * Instead of "value += arg", you should use "this.add(arg)". I haven't found a good way to
- * enforce that.
- */
- override def value: List[String] = {
- if (!sawAll) v
- else {
- // add only those choices which have not explicitly been enabled or disabled.
- val fromAll = choices.filterNot(c => v.exists(pos(_) == c))
- v ++ fromAll
+ override val choices: List[String] = domain.values.toList map {
+ case ChoiceOrVal(name, _, _) => name
+ }
+
+ def descriptions: List[String] = domain.values.toList map {
+ case ChoiceOrVal(_, "", x :: xs) => "Enables the options "+ (x :: xs).map(_.name).mkString(", ")
+ case ChoiceOrVal(_, descr, _) => descr
+ case _ => ""
+ }
+
+ /** (Re)compute from current yeas, nays, wildcard status. */
+ def compute() = {
+ def nonExpanding(vs: domain.ValueSet) = vs filter {
+ case ChoiceOrVal(_, _, others) => others.isEmpty
+ }
+
+ /**
+ * Expand an option, if necessary recursively. Expanding options are not included in the
+ * result (consistent with "_", which is not in the values either). Explicitly excluded
+ * options (in nays) are not added.
+ *
+ * Note: by precondition, options in nays are not expanding, they can only be leaves.
+ */
+ def expand(vs: domain.ValueSet): domain.ValueSet = vs flatMap {
+ // expand
+ case c @ ChoiceOrVal(_, _, others) if others.nonEmpty => expand(domain.ValueSet(others: _*))
+ case c @ ChoiceOrVal(_, _, _) if !nays(c) => domain.ValueSet(c)
+ case _ => domain.ValueSet.empty
}
+ val expandedYeas = expand(yeas)
+
+
+ // we include everything, except those explicitly disabled.
+ val expandedAll = if (sawAll) nonExpanding(domain.values) &~ nays
+ else domain.ValueSet.empty
+
+ value = nonExpanding(yeas) | expandedYeas | expandedAll
}
- /**
- * Add an argument to the list of values.
- */
- def add(arg: String) = {
- if (choosing && !isChoice(arg)) badChoice(arg, name)
- if (arg == "_") {
+ /** Add a named choice to the multichoice value. */
+ def add(arg: String) = arg match {
+ case _ if !isChoice(arg) =>
+ badChoice(arg)
+ case "_" =>
sawAll = true
- value = v // the value_= setter has side effects, make sure to execute them.
- } else {
- val posArg = pos(arg)
- if (arg == posArg) {
- // positive overrides existing negative. so we filter existing (pos or neg), and add the arg
- value = v.filterNot(pos(_) == posArg) :+ arg
- } else {
- // negative arg is only added if the arg doesn't exist yet (pos or neg)
- if (!v.exists(pos(_) == posArg)) value = v :+ arg // not value += arg, see doc of the "value" getter
+ compute()
+ case _ if isPos(arg) =>
+ yeas += domain withName arg
+ compute()
+ case _ =>
+ val choice = domain withName pos(arg)
+ choice match {
+ case ChoiceOrVal(_, _, _ :: _) => errorFn(s"'${pos(arg)}' cannot be negated, it enables other arguments")
+ case _ =>
}
- }
+ nays += choice
+ compute()
}
- override protected def tts(args: List[String], halting: Boolean) = {
+ def tryToSet(args: List[String]) = tryToSetArgs(args, halting = true)
+ override def tryToSetColon(args: List[String]) = tryToSetArgs(args, halting = false)
+ override def tryToSetFromPropertyValue(s: String) = tryToSet(s.trim.split(',').toList) // used from ide
+
+ /** Try to set args, handling "help" and default.
+ * The "halting" parameter means args were "-option a b c -else" so halt
+ * on "-else" or other non-choice. Otherwise, args were "-option:a,b,c,d",
+ * so process all and report non-choices as errors.
+ * @param args args to process
+ * @param halting stop on non-arg
+ */
+ private def tryToSetArgs(args: List[String], halting: Boolean) = {
val added = collection.mutable.ListBuffer.empty[String]
def tryArg(arg: String) = arg match {
- case "help" if choosing => sawHelp = true
- case s if !choosing || isChoice(s) => added += s // this case also adds "_"
- case s => badChoice(s, name)
+ case "help" => sawHelp = true
+ case s if isChoice(s) => added += s // this case also adds "_"
+ case s => badChoice(s)
}
-
- // if "halting" is true, the args were not specified as , separated after a :
- // but space separated after a space. we stop consuming args when seeing
- // - an arg starting with a "-", that is a new option
- // - if the choices are known (choosing), on the first non-choice
- def stoppingAt(arg: String) = (arg startsWith "-") || (choosing && !isChoice(arg))
-
def loop(args: List[String]): List[String] = args match {
- case arg :: _ if halting && stoppingAt(arg) => args
- case arg :: rest => tryArg(arg) ; loop(rest)
- case Nil => Nil
+ case arg :: _ if halting && (!isPos(arg) || !isChoice(arg)) => args
+ case arg :: rest => tryArg(arg) ; loop(rest)
+ case Nil => Nil
}
-
val rest = loop(args)
- if (rest.size == args.size) default match { // if no arg consumed, use defaults or error
+
+ // if no arg consumed, use defaults or error; otherwise, add what they added
+ if (rest.size == args.size) default match {
case Some(defaults) => defaults foreach add
case None => errorFn(s"'$name' requires an option. See '$name:help'.")
} else {
- added.toList foreach add
+ added foreach add
}
Some(rest)
}
+ def contains(choice: domain.Value): Boolean = value contains choice
+
def isHelping: Boolean = sawHelp
def help: String = {
@@ -678,6 +735,16 @@ class MutableSettings(val errorFn: String => Unit)
case (arg, descr) => formatStr.format(arg, descr)
} mkString (f"$descr%n", f"%n", "")
}
+
+ def clear(): Unit = {
+ v = domain.ValueSet.empty
+ yeas = domain.ValueSet.empty
+ nays = domain.ValueSet.empty
+ sawAll = false
+ sawHelp = false
+ }
+ def unparse: List[String] = value.toList map (s => s"$name:$s")
+ def contains(s: String) = value contains (domain withName s)
}
/** A setting that accumulates all strings supplied to it,
@@ -693,15 +760,15 @@ class MutableSettings(val errorFn: String => Unit)
def appendToValue(str: String) = value ++= List(str)
// try to set. halting means halt at first non-arg
- protected def tts(args: List[String], halting: Boolean) = {
+ protected def tryToSetArgs(args: List[String], halting: Boolean) = {
def loop(args: List[String]): List[String] = args match {
case arg :: rest => if (halting && (arg startsWith "-")) args else { appendToValue(arg) ; loop(rest) }
case Nil => Nil
}
Some(loop(args))
}
- def tryToSet(args: List[String]) = tts(args, halting = true)
- override def tryToSetColon(args: List[String]) = tts(args, halting = false)
+ def tryToSet(args: List[String]) = tryToSetArgs(args, halting = true)
+ override def tryToSetColon(args: List[String]) = tryToSetArgs(args, halting = false)
override def tryToSetFromPropertyValue(s: String) = tryToSet(s.trim.split(',').toList) // used from ide
def clear(): Unit = (v = Nil)
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 1609aa5ff7..91b03869e5 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -45,7 +45,7 @@ trait ScalaSettings extends AbsScalaSettings
def infoSettings = List[Setting](version, help, Xhelp, Yhelp, showPlugins, showPhases, genPhaseGraph)
/** Any -multichoice:help? Nicer if any option could report that it had help to offer. */
- private def multihelp = allSettings exists { case s: MultiChoiceSetting => s.isHelping case _ => false }
+ private def multihelp = allSettings exists { case s: MultiChoiceSetting[_] => s.isHelping case _ => false }
/** Is an info setting set? */
def isInfo = (infoSettings exists (_.isSetByUser)) || multihelp
@@ -69,23 +69,22 @@ trait ScalaSettings extends AbsScalaSettings
// Would be nice to build this dynamically from scala.languageFeature.
// The two requirements: delay error checking until you have symbols, and let compiler command build option-specific help.
+ object languageFeatures extends MultiChoiceEnumeration {
+ val dynamics = Choice("dynamics", "Allow direct or indirect subclasses of scala.Dynamic")
+ val postfixOps = Choice("postfixOps", "Allow postfix operator notation, such as `1 to 10 toList'")
+ val reflectiveCalls = Choice("reflectiveCalls", "Allow reflective access to members of structural types")
+ val implicitConversions = Choice("implicitConversions", "Allow definition of implicit functions called views")
+ val higherKinds = Choice("higherKinds", "Allow higher-kinded types")
+ val existentials = Choice("existentials", "Existential types (besides wildcard types) can be written and inferred")
+ val macros = Choice("experimental.macros", "Allow macro defintion (besides implementation and application)")
+ }
val language = {
- val features = List(
- "dynamics" -> "Allow direct or indirect subclasses of scala.Dynamic",
- "postfixOps" -> "Allow postfix operator notation, such as `1 to 10 toList'",
- "reflectiveCalls" -> "Allow reflective access to members of structural types",
- "implicitConversions" -> "Allow definition of implicit functions called views",
- "higherKinds" -> "Allow higher-kinded types", // "Ask Adriaan, but if you have to ask..."
- "existentials" -> "Existential types (besides wildcard types) can be written and inferred",
- "experimental.macros" -> "Allow macro defintion (besides implementation and application)"
- )
val description = "Enable or disable language features"
MultiChoiceSetting(
name = "-language",
helpArg = "feature",
descr = description,
- choices = features map (_._1),
- descriptions = features map (_._2)
+ domain = languageFeatures
)
}
@@ -212,19 +211,19 @@ trait ScalaSettings extends AbsScalaSettings
private def removalIn212 = "This flag is scheduled for removal in 2.12. If you have a case where you need this flag then please report a bug."
- val YstatisticsPhases = {
- val phases = List("parser", "typer", "patmat", "erasure", "cleanup")
+ object YstatisticsPhases extends MultiChoiceEnumeration { val parser, typer, patmat, erasure, cleanup = Value }
+ val Ystatistics = {
val description = "Print compiler statistics for specific phases"
MultiChoiceSetting(
- name = "-Ystatistics",
+ name = "-Ystatistics",
helpArg = "phase",
- descr = description,
- choices = phases,
- descriptions = Nil,
- default = Some(List("_"))) withPostSetHook { _ => scala.reflect.internal.util.Statistics.enabled = true }
+ descr = description,
+ domain = YstatisticsPhases,
+ default = Some(List("_"))
+ ) withPostSetHook { _ => scala.reflect.internal.util.Statistics.enabled = true }
}
- def YstatisticsEnabled = YstatisticsPhases.value.nonEmpty
+ def YstatisticsEnabled = Ystatistics.value.nonEmpty
/** Area-specific debug output.
*/
diff --git a/src/compiler/scala/tools/nsc/settings/Warnings.scala b/src/compiler/scala/tools/nsc/settings/Warnings.scala
index 771543ec77..574825874d 100644
--- a/src/compiler/scala/tools/nsc/settings/Warnings.scala
+++ b/src/compiler/scala/tools/nsc/settings/Warnings.scala
@@ -38,21 +38,45 @@ trait Warnings {
// Lint warnings
- def warnAdaptedArgs = lint contains "adapted-args"
- def warnNullaryUnit = lint contains "nullary-unit"
- def warnInaccessible = lint contains "inaccessible"
- def warnNullaryOverride = lint contains "nullary-override"
- def warnInferAny = lint contains "infer-any"
- def warnMissingInterpolator = lint contains "missing-interpolator"
- def warnDocDetached = lint contains "doc-detached"
- def warnPrivateShadow = lint contains "private-shadow"
- def warnTypeParameterShadow = lint contains "type-parameter-shadow"
- def warnPolyImplicitOverload = lint contains "poly-implicit-overload"
- def warnOptionImplicit = lint contains "option-implicit"
- def warnDelayedInit = lint contains "delayedinit-select"
- def warnByNameRightAssociative = lint contains "by-name-right-associative"
- def warnPackageObjectClasses = lint contains "package-object-classes"
- def warnUnsoundMatch = lint contains "unsound-match"
+ object LintWarnings extends MultiChoiceEnumeration {
+ class LintWarning(name: String, help: String, val yAliased: Boolean) extends Choice(name, help)
+ def LintWarning(name: String, help: String, yAliased: Boolean = false) = new LintWarning(name, help, yAliased)
+
+ val AdaptedArgs = LintWarning("adapted-args", "Warn if an argument list is modified to match the receiver.", true)
+ val NullaryUnit = LintWarning("nullary-unit", "Warn when nullary methods return Unit.", true)
+ val Inaccessible = LintWarning("inaccessible", "Warn about inaccessible types in method signatures.", true)
+ val NullaryOverride = LintWarning("nullary-override", "Warn when non-nullary `def f()' overrides nullary `def f'.", true)
+ val InferAny = LintWarning("infer-any", "Warn when a type argument is inferred to be `Any`.", true)
+ val MissingInterpolator = LintWarning("missing-interpolator", "A string literal appears to be missing an interpolator id.")
+ val DocDetached = LintWarning("doc-detached", "A ScalaDoc comment appears to be detached from its element.")
+ val PrivateShadow = LintWarning("private-shadow", "A private field (or class parameter) shadows a superclass field.")
+ val TypeParameterShadow = LintWarning("type-parameter-shadow", "A local type parameter shadows a type already in scope.")
+ val PolyImplicitOverload = LintWarning("poly-implicit-overload", "Parameterized overloaded implicit methods are not visible as view bounds.")
+ val OptionImplicit = LintWarning("option-implicit", "Option.apply used implicit view.")
+ val DelayedInitSelect = LintWarning("delayedinit-select", "Selecting member of DelayedInit")
+ val ByNameRightAssociative = LintWarning("by-name-right-associative", "By-name parameter of right associative operator.")
+ val PackageObjectClasses = LintWarning("package-object-classes", "Class or object defined in package object.")
+ val UnsoundMatch = LintWarning("unsound-match", "Pattern match may not be typesafe.")
+
+ def allWarnings = values.toSeq.asInstanceOf[Seq[LintWarning]]
+ }
+ import LintWarnings._
+
+ def warnAdaptedArgs = lint contains AdaptedArgs
+ def warnNullaryUnit = lint contains NullaryUnit
+ def warnInaccessible = lint contains Inaccessible
+ def warnNullaryOverride = lint contains NullaryOverride
+ def warnInferAny = lint contains InferAny
+ def warnMissingInterpolator = lint contains MissingInterpolator
+ def warnDocDetached = lint contains DocDetached
+ def warnPrivateShadow = lint contains PrivateShadow
+ def warnTypeParameterShadow = lint contains TypeParameterShadow
+ def warnPolyImplicitOverload = lint contains PolyImplicitOverload
+ def warnOptionImplicit = lint contains OptionImplicit
+ def warnDelayedInit = lint contains DelayedInitSelect
+ def warnByNameRightAssociative = lint contains ByNameRightAssociative
+ def warnPackageObjectClasses = lint contains PackageObjectClasses
+ def warnUnsoundMatch = lint contains UnsoundMatch
// Lint warnings that are currently -Y, but deprecated in that usage
@deprecated("Use warnAdaptedArgs", since="2.11.2")
@@ -67,41 +91,23 @@ trait Warnings {
def YwarnInferAny = warnInferAny
// The Xlint warning group.
- val lint: MultiChoiceSetting = {
- val description = "Enable or disable specific warnings"
-
- val choices = List(
- ("adapted-args", "Warn if an argument list is modified to match the receiver.", true),
- ("nullary-unit", "Warn when nullary methods return Unit.", true),
- ("inaccessible", "Warn about inaccessible types in method signatures.", true),
- ("nullary-override", "Warn when non-nullary `def f()' overrides nullary `def f'.", true),
- ("infer-any", "Warn when a type argument is inferred to be `Any`.", true),
- ("missing-interpolator", "A string literal appears to be missing an interpolator id.", false),
- ("doc-detached", "A ScalaDoc comment appears to be detached from its element.", false),
- ("private-shadow", "A private field (or class parameter) shadows a superclass field.", false),
- ("type-parameter-shadow", "A local type parameter shadows a type already in scope.", false),
- ("poly-implicit-overload", "Parameterized overloaded implicit methods are not visible as view bounds.", false),
- ("option-implicit", "Option.apply used implicit view.", false),
- ("delayedinit-select", "Selecting member of DelayedInit", false),
- ("by-name-right-associative", "By-name parameter of right associative operator.", false),
- ("package-object-classes", "Class or object defined in package object.", false),
- ("unsound-match", "Pattern match may not be typesafe.", false)
- ).sorted
-
- for (c <- choices.filter(_._3)) {
- BooleanSetting("-Ywarn-"+ c._1, c._2) withPostSetHook { s =>
- if (s) lint.add(c._1)
- else lint.add("-" + c._1)
- } // withDeprecationMessage s"Enable -Xlint:${c._1}"
+ val lint: MultiChoiceSetting[LintWarnings.type] = {
+ import LintWarnings._
+
+ allWarnings.sortBy(_.name) foreach {
+ case l: LintWarning if l.yAliased =>
+ BooleanSetting(s"-Ywarn-${l.name}", {l.help}) withPostSetHook { s =>
+ lint.add(if (s) l.name else s"-${l.name}")
+ } // withDeprecationMessage s"Enable -Xlint:${c._1}"
+ case _ =>
}
MultiChoiceSetting(
- name = "-Xlint",
- helpArg = "warning",
- descr = description,
- choices = choices map (_._1),
- descriptions = choices map (_._2),
- default = Some(List("_"))
+ name = "-Xlint",
+ helpArg = "warning",
+ descr = "Enable or disable specific warnings",
+ domain = LintWarnings,
+ default = Some(List("_"))
)
}
diff --git a/src/compiler/scala/tools/nsc/util/StatisticsInfo.scala b/src/compiler/scala/tools/nsc/util/StatisticsInfo.scala
index a5d579dc37..be245347a8 100644
--- a/src/compiler/scala/tools/nsc/util/StatisticsInfo.scala
+++ b/src/compiler/scala/tools/nsc/util/StatisticsInfo.scala
@@ -17,7 +17,7 @@ abstract class StatisticsInfo {
val retainedCount = Statistics.newCounter("#retained tree nodes")
val retainedByType = Statistics.newByClass("#retained tree nodes by type")(Statistics.newCounter(""))
- def print(phase: Phase) = if (settings.YstatisticsPhases contains phase.name) {
+ def print(phase: Phase) = if (settings.Ystatistics contains phase.name) {
inform("*** Cumulative statistics at phase " + phase)
retainedCount.value = 0
for (c <- retainedByType.keys)
diff --git a/test/junit/scala/tools/nsc/settings/SettingsTest.scala b/test/junit/scala/tools/nsc/settings/SettingsTest.scala
index a0e015be32..0b8029326e 100644
--- a/test/junit/scala/tools/nsc/settings/SettingsTest.scala
+++ b/test/junit/scala/tools/nsc/settings/SettingsTest.scala
@@ -96,7 +96,7 @@ class SettingsTest {
// make sure that lint.contains and lint.value.contains are consistent
def t(s: MutableSettings, v: String) = {
val r = s.lint.contains(v)
- assertSame(r, s.lint.value.contains(v))
+ assertSame(r, s.lint.value.contains((s.LintWarnings withName v).asInstanceOf[s.lint.domain.Value]))
r
}
@@ -118,4 +118,48 @@ class SettingsTest {
assertFalse(check("-Ywarn-adapted-args:false", "-Xlint:_,-adapted-args")(_.warnAdaptedArgs))
assertTrue(check("-Ywarn-adapted-args:false", "-Xlint:_,adapted-args")(_.warnAdaptedArgs))
}
+
+ @Test def expandingMultichoice(): Unit = {
+ val s = new MutableSettings(msg => throw new IllegalArgumentException(msg))
+ object mChoices extends s.MultiChoiceEnumeration {
+ val a = Choice("a")
+ val b = Choice("b")
+ val c = Choice("c")
+ val d = Choice("d")
+
+ val ab = Choice("ab", expandsTo = List(a, b))
+ val ac = Choice("ac", expandsTo = List(a, c))
+ val uber = Choice("uber", expandsTo = List(ab, d))
+ }
+ val m = s.MultiChoiceSetting("-m", "args", "magic sauce", mChoices, Some(List("ac")))
+
+ def check(args: String*)(t: s.MultiChoiceSetting[mChoices.type] => Boolean): Boolean = {
+ m.clear()
+ val (ok, rest) = s.processArguments(args.toList, processAll = true)
+ assert(rest.isEmpty)
+ t(m)
+ }
+
+ import mChoices._
+
+ assertTrue(check("-m")(_.value == Set(a,c)))
+ assertTrue(check("-m:a,-b,c")(_.value == Set(a,c)))
+
+ // expanding options don't end up in the value set, only the terminal ones
+ assertTrue(check("-m:ab,ac")(_.value == Set(a,b,c)))
+ assertTrue(check("-m:_")(_.value == Set(a,b,c,d)))
+ assertTrue(check("-m:uber,ac")(_.value == Set(a,b,c,d))) // recursive expansion of uber
+
+ // explicit nays
+ assertTrue(check("-m:_,-b")(_.value == Set(a,c,d)))
+ assertTrue(check("-m:b,_,-b")(_.value == Set(a,b,c,d)))
+ assertTrue(check("-m:ac,-c")(_.value == Set(a)))
+ assertTrue(check("-m:ac,-a,-c")(_.value == Set()))
+ assertTrue(check("-m:-d,ac")(_.value == Set(a,c)))
+ assertTrue(check("-m:-b,ac,uber")(_.value == Set(a,c,d)))
+
+ assertThrows[IllegalArgumentException](check("-m:-_")(_ => true), _ contains "'-_' is not a valid choice")
+ assertThrows[IllegalArgumentException](check("-m:a,b,-ab")(_ => true), _ contains "'ab' cannot be negated")
+ assertThrows[IllegalArgumentException](check("-m:a,ac,-uber,uber")(_ => true), _ contains "'uber' cannot be negated")
+ }
}