diff options
19 files changed, 509 insertions, 236 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/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 82ffb35c3f..452081cff1 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1372,7 +1372,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) runCheckers() // output collected statistics - if (settings.Ystatistics) + if (settings.YstatisticsEnabled) statistics.print(phase) advancePhase() diff --git a/src/compiler/scala/tools/nsc/MainBench.scala b/src/compiler/scala/tools/nsc/MainBench.scala index 03190a63f3..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.Ystatistics.value = true + theCompiler.settings.Ystatistics.default.get foreach theCompiler.settings.Ystatistics.add Statistics.enabled = true } process(args) diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala index c2d62db558..7d5c6f6fff 100644 --- a/src/compiler/scala/tools/nsc/ScriptRunner.scala +++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala @@ -6,7 +6,7 @@ package scala package tools.nsc -import io.{ Directory, File, Path } +import io.{ AbstractFile, Directory, File, Path } import java.io.IOException import scala.tools.nsc.reporters.{Reporter,ConsoleReporter} import util.Exceptional.unwrap @@ -111,6 +111,12 @@ class ScriptRunner extends HasCompileSocket { else None } + def hasClassToRun(d: Directory): Boolean = { + import util.ClassPath.{ DefaultJavaContext => ctx } + val cp = ctx.newClassPath(AbstractFile.getDirectory(d)) + cp.findClass(mainClass).isDefined + } + /* The script runner calls sys.exit to communicate a return value, but this must * not take place until there are no non-daemon threads running. Tickets #1955, #2006. */ @@ -124,15 +130,21 @@ class ScriptRunner extends HasCompileSocket { compile match { case Some(compiledPath) => - try io.Jar.create(jarFile, compiledPath, mainClass) - catch { case _: Exception => jarFile.delete() } - - if (jarOK) { - compiledPath.deleteRecursively() - handler(jarFile.toAbsolute.path) + if (!hasClassToRun(compiledPath)) { + // it compiled ok, but there is nothing to run; + // running an empty script should succeed + true + } else { + try io.Jar.create(jarFile, compiledPath, mainClass) + catch { case _: Exception => jarFile.delete() } + + if (jarOK) { + compiledPath.deleteRecursively() + handler(jarFile.toAbsolute.path) + } + // jar failed; run directly from the class files + else handler(compiledPath.path) } - // jar failed; run directly from the class files - else handler(compiledPath.path) case _ => false } } @@ -140,8 +152,8 @@ class ScriptRunner extends HasCompileSocket { if (jarOK) handler(jarFile.toAbsolute.path) // pre-compiled jar is current else recompile() // jar old - recompile the script. } - // don't use a cache jar at all--just use the class files - else compile exists (cp => handler(cp.path)) + // don't use a cache jar at all--just use the class files, if they exist + else compile exists (cp => !hasClassToRun(cp) || handler(cp.path)) } } diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index 8df3969c49..351eb23c4c 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -283,7 +283,7 @@ abstract class Inliners extends SubComponent { } val tfa = new analysis.MTFAGrowable() - tfa.stat = global.settings.Ystatistics.value + tfa.stat = global.settings.YstatisticsEnabled val staleOut = new mutable.ListBuffer[BasicBlock] val splicedBlocks = mutable.Set.empty[BasicBlock] val staleIn = mutable.Set.empty[BasicBlock] diff --git a/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala index d0b8fd70ed..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], default: Option[() => Unit])(helper: MultiChoiceSetting => 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 f26192f88a..bbe21477cb 100644 --- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala @@ -209,12 +209,11 @@ class MutableSettings(val errorFn: String => Unit) def BooleanSetting(name: String, descr: String) = add(new BooleanSetting(name, descr)) def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String) = add(new ChoiceSetting(name, helpArg, descr, choices, default)) - 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 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], default: Option[() => Unit] = None)( - helper: MultiChoiceSetting => String = _ => choices.mkString(f"$descr:%n", f"%n ", f"%n") - ) = - add(new MultiChoiceSetting(name, helpArg, descr, choices, default, helper)) + 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)) @@ -367,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,57 +552,193 @@ class MutableSettings(val errorFn: String => Unit) } } - /** A setting that receives any combination of enumerated values, - * including "_" to mean all values and "help" for verbose info. - * In non-colonated mode, stops consuming args at the first - * non-value, instead of at the next option, as for a multi-string. + /** + * Each [[MultiChoiceSetting]] takes a MultiChoiceEnumeration as domain. The enumeration may + * use the Choice class to define values, or simply use the default `Value` constructor: + * + * object SettingDomain extends MultiChoiceEnumeration { val arg1, arg2 = Value } + * + * Or + * + * object SettingDomain extends MultiChoiceEnumeration { + * val arg1 = Choice("arg1", "help") + * val arg2 = Choice("arg2", "help") + * } + * + * Choices with a non-empty `expandsTo` enable other options. Note that expanding choices are + * not present in the multiChoiceSetting.value set, only their expansion. + */ + 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 private[nsc]( + class MultiChoiceSetting[E <: MultiChoiceEnumeration] private[nsc]( name: String, - arg: String, + helpArg: String, descr: String, - override val choices: List[String], - val default: Option[() => Unit], - helper: MultiChoiceSetting => String - ) extends MultiStringSetting(name, s"_,$arg,-$arg", s"$descr: `_' for all, `$name:help' to list") { + val domain: E, + val default: Option[List[String]] + ) extends Setting(name, s"$descr: `_' for all, `$name:help' to list") with Clearable { - private def badChoice(s: String, n: String) = errorFn(s"'$s' is not a valid choice for '$name'") - private def choosing = choices.nonEmpty - private def isChoice(s: String) = (s == "_") || (choices contains (s stripPrefix "-")) + withHelpSyntax(s"$name:<_,$helpArg,-$helpArg>") - private var sawHelp = false - private var sawAll = false - private val adderAll = () => sawAll = true - private val noargs = () => errorFn(s"'$name' requires an option. See '$name:help'.") + object ChoiceOrVal { + def unapply(a: domain.Value): 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)) + } + } + + 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 "-") + + 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 _ => "" + } - override protected def tts(args: List[String], halting: Boolean) = { + /** (Re)compute from current yeas, nays, wildcard status. */ + def compute() = { + def simple(v: domain.Value) = v match { + case ChoiceOrVal(_, _, Nil) => true + case _ => false + } + + /** + * Expand an expanding option, if necessary recursively. Expanding options are not included in + * the result (consistent with "_", which is not in `value` either). + * + * Note: by precondition, options in nays are not expanding, they can only be leaves. + */ + def expand(vs: domain.ValueSet): domain.ValueSet = vs flatMap { + case c @ ChoiceOrVal(_, _, Nil) => domain.ValueSet(c) + case ChoiceOrVal(_, _, others) => expand(domain.ValueSet(others: _*)) + } + + // yeas from _ or expansions are weak: an explicit nay will disable them + val weakYeas = if (sawAll) domain.values filter simple else expand(yeas filterNot simple) + value = (yeas filter simple) | (weakYeas &~ nays) + } + + /** Add a named choice to the multichoice value. */ + def add(arg: String) = arg match { + case _ if !isChoice(arg) => + badChoice(arg) + case "_" => + sawAll = true + 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() + } + + 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 "_" if choosing => addAll() - case "help" if choosing => sawHelp = true - case s if !choosing || isChoice(s) => added += s - case s => badChoice(s, name) + case "help" => sawHelp = true + case s if isChoice(s) => added += s // this case also adds "_" + case s => badChoice(s) } - 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 getOrElse noargs)() // if no arg consumed, trigger default action or error - else - value ++= added.toList // update all new settings at once + + // 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 foreach add + } + Some(rest) } + def contains(choice: domain.Value): Boolean = value contains choice + def isHelping: Boolean = sawHelp - def help: String = helper(this) - def addAll(): Unit = (default getOrElse adderAll)() - // the semantics is: s is enabled, i.e., either s or (_ but not -s) - override def contains(s: String) = isChoice(s) && (value contains s) || (sawAll && !(value contains s"-$s")) + def help: String = { + val choiceLength = choices.map(_.length).max + 1 + val formatStr = s" %-${choiceLength}s %s" + choices.zipAll(descriptions, "", "").map { + 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) = domain.values.find(_.toString == s).exists(value.contains) } /** A setting that accumulates all strings supplied to it, @@ -619,15 +754,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 8e69598614..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,28 +69,23 @@ 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) - ) { s => - val helpline: ((String, String)) => String = { - case (name, text) => f" $name%-25s $text%n" - } - features map helpline mkString (f"$description:%n", "", f"%n") - } + domain = languageFeatures + ) } /* @@ -193,7 +188,6 @@ trait ScalaSettings extends AbsScalaSettings val Ygenjavap = StringSetting ("-Ygen-javap", "dir", "Generate a parallel output directory of .javap files.", "") val Ygenasmp = StringSetting ("-Ygen-asmp", "dir", "Generate a parallel output directory of .asmp files (ie ASM Textifier output).", "") val Ydumpclasses = StringSetting ("-Ydump-classes", "dir", "Dump the generated bytecode to .class files (useful for reflective compilation that utilizes in-memory classloaders).", "") - val Ystatistics = BooleanSetting ("-Ystatistics", "Print compiler statistics.") andThen (scala.reflect.internal.util.Statistics.enabled = _) val stopAfter = PhasesSetting ("-Ystop-after", "Stop after") withAbbreviation ("-stop") // backward compat val stopBefore = PhasesSetting ("-Ystop-before", "Stop before") val Yrangepos = BooleanSetting ("-Yrangepos", "Use range positions for syntax trees.") @@ -217,6 +211,20 @@ 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." + object YstatisticsPhases extends MultiChoiceEnumeration { val parser, typer, patmat, erasure, cleanup = Value } + val Ystatistics = { + val description = "Print compiler statistics for specific phases" + MultiChoiceSetting( + name = "-Ystatistics", + helpArg = "phase", + descr = description, + domain = YstatisticsPhases, + default = Some(List("_")) + ) withPostSetHook { _ => scala.reflect.internal.util.Statistics.enabled = true } + } + + def YstatisticsEnabled = Ystatistics.value.nonEmpty + /** Area-specific debug output. */ val Ydocdebug = BooleanSetting("-Ydoc-debug", "Trace all scaladoc activity.") diff --git a/src/compiler/scala/tools/nsc/settings/Warnings.scala b/src/compiler/scala/tools/nsc/settings/Warnings.scala index 4c37633301..c400e8c29c 100644 --- a/src/compiler/scala/tools/nsc/settings/Warnings.scala +++ b/src/compiler/scala/tools/nsc/settings/Warnings.scala @@ -17,145 +17,94 @@ trait Warnings { // Warning semantics. val fatalWarnings = BooleanSetting("-Xfatal-warnings", "Fail the compilation if there are any warnings.") - // These additional warnings are all so noisy as to be useless in their - // present form, but have the potential to offer useful info. - protected def allWarnings = lintWarnings ++ List( - warnDeadCode, - warnValueDiscard, - warnNumericWiden, - warnUnused, // SI-7712, SI-7707 warnUnused not quite ready for prime-time - warnUnusedImport, // currently considered too noisy for general use - warnValueOverrides // currently turned off as experimental - ) - // These warnings should be pretty quiet unless you're doing - // something inadvisable. - protected def lintWarnings = List( - warnInaccessible, - warnNullaryOverride, - warnNullaryUnit, - warnAdaptedArgs, - warnInferAny, - warnMissingInterpolator, - warnDocDetached, - warnPrivateShadow, - warnTypeParameterShadow, - warnPolyImplicitOverload, - warnOptionImplicit, - warnDelayedInit, - warnByNameRightAssociative, - warnPackageObjectClasses, - warnUnsoundMatch - ) - - // Individual warnings. They can be set with -Ywarn. - private def nonlintflag(name: String, text: String): BooleanSetting = BooleanSetting(name, text) - - val warnDeadCode = nonlintflag("-Ywarn-dead-code", - "Warn when dead code is identified.") - val warnValueDiscard = nonlintflag("-Ywarn-value-discard", - "Warn when non-Unit expression results are unused.") - val warnNumericWiden = nonlintflag("-Ywarn-numeric-widen", - "Warn when numerics are widened.") - val warnUnused = nonlintflag("-Ywarn-unused", - "Warn when local and private vals, vars, defs, and types are are unused") - val warnUnusedImport = nonlintflag("-Ywarn-unused-import", - "Warn when imports are unused") - - // Lint warnings that have no -Y avatar, created with new instead of the autoregistering factory method. - // They evaluate true if set to true or else are unset but -Xlint is true - private def lintflag(name: String, text: String): BooleanSetting = - new BooleanSetting(name, text) { - override def value = if (isSetByUser) super.value else xlint - } - - val warnAdaptedArgs = lintflag("adapted-args", - "Warn if an argument list is modified to match the receiver.") - val warnNullaryUnit = lintflag("nullary-unit", - "Warn when nullary methods return Unit.") - val warnInaccessible = lintflag("inaccessible", - "Warn about inaccessible types in method signatures.") - val warnNullaryOverride = lintflag("nullary-override", - "Warn when non-nullary `def f()' overrides nullary `def f'.") - val warnInferAny = lintflag("infer-any", - "Warn when a type argument is inferred to be `Any`.") - val warnMissingInterpolator = lintflag("missing-interpolator", - "A string literal appears to be missing an interpolator id.") - val warnDocDetached = lintflag("doc-detached", - "A ScalaDoc comment appears to be detached from its element.") - val warnPrivateShadow = lintflag("private-shadow", - "A private field (or class parameter) shadows a superclass field.") - val warnTypeParameterShadow = lintflag("type-parameter-shadow", - "A local type parameter shadows a type already in scope.") - val warnPolyImplicitOverload = lintflag("poly-implicit-overload", - "Parameterized overloaded implicit methods are not visible as view bounds") - val warnOptionImplicit = lintflag("option-implicit", - "Option.apply used implicit view.") - val warnDelayedInit = lintflag("delayedinit-select", - "Selecting member of DelayedInit") - val warnByNameRightAssociative = lintflag("by-name-right-associative", - "By-name parameter of right associative operator") - val warnPackageObjectClasses = lintflag("package-object-classes", - "Class or object defined in package object") - val warnUnsoundMatch = lintflag("unsound-match", - "Pattern match may not be typesafe") + // Non-lint warnings + + val warnDeadCode = BooleanSetting("-Ywarn-dead-code", "Warn when dead code is identified.") + val warnValueDiscard = BooleanSetting("-Ywarn-value-discard", "Warn when non-Unit expression results are unused.") + val warnNumericWiden = BooleanSetting("-Ywarn-numeric-widen", "Warn when numerics are widened.") + // SI-7712, SI-7707 warnUnused not quite ready for prime-time + val warnUnused = BooleanSetting("-Ywarn-unused", "Warn when local and private vals, vars, defs, and types are are unused.") + // currently considered too noisy for general use + val warnUnusedImport = BooleanSetting("-Ywarn-unused-import", "Warn when imports are unused.") // Experimental lint warnings that are turned off, but which could be turned on programmatically. // These warnings are said to blind those who dare enable them. // They are not activated by -Xlint and can't be enabled on the command line. - val warnValueOverrides = { - val flag = lintflag("value-overrides", "Generated value class method overrides an implementation") + val warnValueOverrides = { // currently turned off as experimental. creaded using constructor (new BS), so not available on the command line. + val flag = new BooleanSetting("value-overrides", "Generated value class method overrides an implementation") flag.value = false flag } - // The Xlint warning group. - private val xlint = new BooleanSetting("-Zunused", "True if -Xlint or -Xlint:_") - // On -Xlint or -Xlint:_, set xlint, otherwise set the lint warning unless already set true - val lint = { - val description = "Enable or disable specific warnings" - val choices = (lintWarnings map (_.name)).sorted - MultiChoiceSetting( - name = "-Xlint", - helpArg = "warning", - descr = description, - choices = choices, - default = Some(() => xlint.value = true) - ) { s => - def helpline(n: String) = lintWarnings.find(_.name == n).map(w => f" ${w.name}%-25s ${w.helpDescription}%n") - choices flatMap (helpline(_)) mkString (f"$description:%n", "", f"%n") - } withPostSetHook { x => - val Neg = "-" - def setPolitely(b: BooleanSetting, v: Boolean) = if (!b.isSetByUser || !b) b.value = v - def set(w: String, v: Boolean) = lintWarnings find (_.name == w) foreach (setPolitely(_, v)) - def propagate(ss: List[String]): Unit = ss match { - case w :: rest => if (w startsWith Neg) set(w stripPrefix Neg, false) else set(w, true) ; propagate(rest) - case Nil => () - } - propagate(x.value) - } + // Lint warnings + + 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 allLintWarnings = 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") - val YwarnAdaptedArgs = BooleanSetting("-Ywarn-adapted-args", - "Warn if an argument list is modified to match the receiver.") enabling List(warnAdaptedArgs) - //withDeprecationMessage "Enable -Xlint:adapted-args" + def YwarnAdaptedArgs = warnAdaptedArgs @deprecated("Use warnNullaryUnit", since="2.11.2") - val YwarnNullaryUnit = BooleanSetting("-Ywarn-nullary-unit", - "Warn when nullary methods return Unit.") enabling List(warnNullaryUnit) - //withDeprecationMessage "Enable -Xlint:nullary-unit" + def YwarnNullaryUnit = warnNullaryUnit @deprecated("Use warnInaccessible", since="2.11.2") - val YwarnInaccessible = BooleanSetting("-Ywarn-inaccessible", - "Warn about inaccessible types in method signatures.") enabling List(warnInaccessible) - //withDeprecationMessage "Enable -Xlint:inaccessible" + def YwarnInaccessible = warnInaccessible @deprecated("Use warnNullaryOverride", since="2.11.2") - val YwarnNullaryOverride = BooleanSetting("-Ywarn-nullary-override", - "Warn when non-nullary `def f()' overrides nullary `def f'.") enabling List(warnNullaryOverride) - //withDeprecationMessage "Enable -Xlint:nullary-override" + def YwarnNullaryOverride = warnNullaryOverride @deprecated("Use warnInferAny", since="2.11.2") - val YwarnInferAny = BooleanSetting("-Ywarn-infer-any", - "Warn when a type argument is inferred to be `Any`.") enabling List(warnInferAny) - //withDeprecationMessage "Enable -Xlint:infer-any" + def YwarnInferAny = warnInferAny + + // The Xlint warning group. + val lint = MultiChoiceSetting( + name = "-Xlint", + helpArg = "warning", + descr = "Enable or disable specific warnings", + domain = LintWarnings, + default = Some(List("_"))) + + allLintWarnings foreach { + case w if w.yAliased => + BooleanSetting(s"-Ywarn-${w.name}", {w.help}) withPostSetHook { s => + lint.add(if (s) w.name else s"-${w.name}") + } // withDeprecationMessage s"Enable -Xlint:${c._1}" + case _ => + } private lazy val warnSelectNullable = BooleanSetting("-Xcheck-null", "This option is obsolete and does nothing.") diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index fb7651ffd6..421021163e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -552,7 +552,7 @@ trait Infer extends Checkable { } case _ => context.tree.pos } - if (settings.warnInferAny.value && context.reportErrors && canWarnAboutAny) { + if (settings.warnInferAny && context.reportErrors && canWarnAboutAny) { foreachWithIndex(targs) ((targ, idx) => targ.typeSymbol match { case sym @ (AnyClass | AnyValClass) => diff --git a/src/compiler/scala/tools/nsc/util/StatisticsInfo.scala b/src/compiler/scala/tools/nsc/util/StatisticsInfo.scala index 225f6ca68e..be245347a8 100644 --- a/src/compiler/scala/tools/nsc/util/StatisticsInfo.scala +++ b/src/compiler/scala/tools/nsc/util/StatisticsInfo.scala @@ -14,12 +14,10 @@ abstract class StatisticsInfo { import global._ import scala.reflect.internal.TreesStats.nodeByType - val phasesShown = List("parser", "typer", "patmat", "erasure", "cleanup") - val retainedCount = Statistics.newCounter("#retained tree nodes") val retainedByType = Statistics.newByClass("#retained tree nodes by type")(Statistics.newCounter("")) - def print(phase: Phase) = if (phasesShown 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/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index f6f46e158f..660cc5a42a 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -1088,6 +1088,9 @@ trait Iterator[+A] extends TraversableOnce[A] { } /** Returns this iterator with patched values. + * Patching at negative indices is the same as patching starting at 0. + * Patching at indices at or larger than the length of the original iterator appends the patch to the end. + * If more values are replaced than actually exist, the excess is ignored. * * @param from The start index from which to patch * @param patchElems The iterator of patch values @@ -1096,18 +1099,33 @@ trait Iterator[+A] extends TraversableOnce[A] { */ def patch[B >: A](from: Int, patchElems: Iterator[B], replaced: Int): Iterator[B] = new AbstractIterator[B] { private var origElems = self - private var i = 0 - def hasNext: Boolean = - if (i < from) origElems.hasNext - else patchElems.hasNext || origElems.hasNext + private var i = (if (from > 0) from else 0) // Counts down, switch to patch on 0, -1 means use patch first + def hasNext: Boolean = { + if (i == 0) { + origElems = origElems drop replaced + i = -1 + } + origElems.hasNext || patchElems.hasNext + } def next(): B = { - // We have to do this *first* just in case from = 0. - if (i == from) origElems = origElems drop replaced - val result: B = - if (i < from || !patchElems.hasNext) origElems.next() - else patchElems.next() - i += 1 - result + if (i == 0) { + origElems = origElems drop replaced + i = -1 + } + if (i < 0) { + if (patchElems.hasNext) patchElems.next() + else origElems.next() + } + else { + if (origElems.hasNext) { + i -= 1 + origElems.next() + } + else { + i = -1 + patchElems.next() + } + } } } diff --git a/src/library/scala/collection/SeqViewLike.scala b/src/library/scala/collection/SeqViewLike.scala index 5e31ac4a53..e719f19c78 100644 --- a/src/library/scala/collection/SeqViewLike.scala +++ b/src/library/scala/collection/SeqViewLike.scala @@ -154,17 +154,27 @@ trait SeqViewLike[+A, } } + // Note--for this to work, must ensure 0 <= from and 0 <= replaced + // Must also take care to allow patching inside an infinite stream + // (patching in an infinite stream is not okay) trait Patched[B >: A] extends Transformed[B] { protected[this] val from: Int protected[this] val patch: GenSeq[B] protected[this] val replaced: Int private lazy val plen = patch.length override def iterator: Iterator[B] = self.iterator patch (from, patch.iterator, replaced) - def length: Int = self.length + plen - replaced - def apply(idx: Int): B = - if (idx < from) self.apply(idx) - else if (idx < from + plen) patch.apply(idx - from) + def length: Int = { + val len = self.length + val pre = math.min(from, len) + val post = math.max(0, len - pre - replaced) + pre + plen + post + } + def apply(idx: Int): B = { + val actualFrom = if (self.lengthCompare(from) < 0) self.length else from + if (idx < actualFrom) self.apply(idx) + else if (idx < actualFrom + plen) patch.apply(idx - actualFrom) else self.apply(idx - plen + replaced) + } final override protected[this] def viewIdentifier = "P" } @@ -210,7 +220,10 @@ trait SeqViewLike[+A, override def reverse: This = newReversed.asInstanceOf[This] override def patch[B >: A, That](from: Int, patch: GenSeq[B], replaced: Int)(implicit bf: CanBuildFrom[This, B, That]): That = { - newPatched(from, patch, replaced).asInstanceOf[That] + // Be careful to not evaluate the entire sequence! Patch should work (slowly, perhaps) on infinite streams. + val nonNegFrom = math.max(0,from) + val nonNegRep = math.max(0,replaced) + newPatched(nonNegFrom, patch, nonNegRep).asInstanceOf[That] // was: val b = bf(repr) // if (b.isInstanceOf[NoBuilder[_]]) newPatched(from, patch, replaced).asInstanceOf[That] // else super.patch[B, That](from, patch, replaced)(bf) diff --git a/test/junit/scala/tools/nsc/ScriptRunnerTest.scala b/test/junit/scala/tools/nsc/ScriptRunnerTest.scala new file mode 100644 index 0000000000..9bae7a0487 --- /dev/null +++ b/test/junit/scala/tools/nsc/ScriptRunnerTest.scala @@ -0,0 +1,23 @@ +package scala.tools.nsc + +import org.junit.Assert._ +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(classOf[JUnit4]) +class ScriptRunnerTest { + @Test + def testEmptyScriptSucceeds: Unit = { + val s = new GenericRunnerSettings(s => ()) + s.nc.value = true + s.usejavacp.value = true + + // scala -nc -e '' + assertTrue(ScriptRunner.runCommand(s, "", Nil)) + + // scala -nc -save -e '' + s.save.value = true + assertTrue(ScriptRunner.runCommand(s, "", Nil)) + } +} diff --git a/test/junit/scala/tools/nsc/settings/SettingsTest.scala b/test/junit/scala/tools/nsc/settings/SettingsTest.scala index 960d7f8ac1..eda0c27834 100644 --- a/test/junit/scala/tools/nsc/settings/SettingsTest.scala +++ b/test/junit/scala/tools/nsc/settings/SettingsTest.scala @@ -39,7 +39,7 @@ class SettingsTest { } // for the given args, select the desired setting - private def check(args: String*)(b: MutableSettings => MutableSettings#BooleanSetting): MutableSettings#BooleanSetting = { + private def check(args: String*)(b: MutableSettings => Boolean): Boolean = { val s = new MutableSettings(msg => throw new IllegalArgumentException(msg)) val (ok, residual) = s.processArguments(args.toList, processAll = true) assert(residual.isEmpty) @@ -54,7 +54,114 @@ class SettingsTest { @Test def anonymousLintersCanBeNamed() { assertTrue(check("-Xlint")(_.warnMissingInterpolator)) // among Xlint assertFalse(check("-Xlint:-missing-interpolator")(_.warnMissingInterpolator)) + + // positive overrides negative, but not the other way around + assertTrue(check("-Xlint:-missing-interpolator,missing-interpolator")(_.warnMissingInterpolator)) + assertTrue(check("-Xlint:-missing-interpolator", "-Xlint:missing-interpolator")(_.warnMissingInterpolator)) + + assertTrue(check("-Xlint:missing-interpolator,-missing-interpolator")(_.warnMissingInterpolator)) + assertTrue(check("-Xlint:missing-interpolator", "-Xlint:-missing-interpolator")(_.warnMissingInterpolator)) + + // -Xlint:_ adds all possible choices, but explicit negative settings will override + assertFalse(check("-Xlint:-missing-interpolator,_")(_.warnMissingInterpolator)) + assertFalse(check("-Xlint:-missing-interpolator", "-Xlint:_")(_.warnMissingInterpolator)) + assertFalse(check("-Xlint:_", "-Xlint:-missing-interpolator")(_.warnMissingInterpolator)) + assertFalse(check("-Xlint:_,-missing-interpolator")(_.warnMissingInterpolator)) + + // -Xlint is the same as -Xlint:_ assertFalse(check("-Xlint:-missing-interpolator", "-Xlint")(_.warnMissingInterpolator)) assertFalse(check("-Xlint", "-Xlint:-missing-interpolator")(_.warnMissingInterpolator)) + + // combination of positive, negative and _ + assertTrue(check("-Xlint:_,-missing-interpolator,missing-interpolator")(_.warnMissingInterpolator)) + assertTrue(check("-Xlint:-missing-interpolator,_,missing-interpolator")(_.warnMissingInterpolator)) + assertTrue(check("-Xlint:-missing-interpolator,missing-interpolator,_")(_.warnMissingInterpolator)) + assertTrue(check("-Xlint:missing-interpolator,-missing-interpolator,_")(_.warnMissingInterpolator)) + assertTrue(check("-Xlint:missing-interpolator,_,-missing-interpolator")(_.warnMissingInterpolator)) + } + + @Test def xLintInvalidChoices(): Unit = { + assertThrows[IllegalArgumentException](check("-Xlint:-_")(_.warnAdaptedArgs)) + assertThrows[IllegalArgumentException](check("-Xlint:-warn-adapted-args")(_.warnAdaptedArgs)) // "warn-" should not be there + } + + @Test def xLintNonColonated(): Unit = { + assertTrue(check("-Xlint", "adapted-args", "-deprecation")(_.warnAdaptedArgs)) + assertFalse(check("-Xlint", "adapted-args", "-deprecation")(_.warnMissingInterpolator)) + assertTrue(check("-Xlint", "adapted-args", "missing-interpolator", "-deprecation")(s => s.warnMissingInterpolator && s.warnAdaptedArgs)) + assertThrows[IllegalArgumentException](check("-Xlint", "adapted-args", "-missing-interpolator")(_.warnAdaptedArgs)) // non-colonated: cannot provide negative args + } + + @Test def xLintContainsValues(): Unit = { + // 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((s.LintWarnings withName v).asInstanceOf[s.lint.domain.Value])) + r + } + + assertTrue(check("-Xlint")(t(_, "adapted-args"))) + assertTrue(check("-Xlint:_")(t(_, "adapted-args"))) + assertFalse(check("-Xlint:_,-adapted-args")(t(_, "adapted-args"))) + assertFalse(check("-Xlint:-adapted-args,_")(t(_, "adapted-args"))) + assertTrue(check("-Xlint:-adapted-args,_,adapted-args")(t(_, "adapted-args"))) + } + + @Test def xLintDeprecatedAlias(): Unit = { + assertTrue(check("-Ywarn-adapted-args")(_.warnAdaptedArgs)) + assertTrue(check("-Xlint:_,-adapted-args", "-Ywarn-adapted-args")(_.warnAdaptedArgs)) + assertTrue(check("-Xlint:-adapted-args", "-Ywarn-adapted-args")(_.warnAdaptedArgs)) + assertTrue(check("-Ywarn-adapted-args", "-Xlint:-adapted-args,_")(_.warnAdaptedArgs)) + + assertFalse(check("-Ywarn-adapted-args:false")(_.warnAdaptedArgs)) + assertFalse(check("-Ywarn-adapted-args:false", "-Xlint:_")(_.warnAdaptedArgs)) + 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))) + + assertFalse(check("-m:uber")(_.contains("i-m-not-an-option"))) + + 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") } } diff --git a/test/junit/scala/tools/nsc/symtab/CannotHaveAttrsTest.scala b/test/junit/scala/tools/nsc/symtab/CannotHaveAttrsTest.scala index 355771bf04..d424f12710 100644 --- a/test/junit/scala/tools/nsc/symtab/CannotHaveAttrsTest.scala +++ b/test/junit/scala/tools/nsc/symtab/CannotHaveAttrsTest.scala @@ -47,7 +47,7 @@ class CannotHaveAttrsTest { assertEquals(t.tpe, NoType) } - @Test + @Test @org.junit.Ignore // SI-8816 def nonDefaultPosAssignmentFails = { val pos = new OffsetPosition(null, 0) attrlessTrees.foreach { t => @@ -56,7 +56,7 @@ class CannotHaveAttrsTest { } } - @Test + @Test @org.junit.Ignore // SI-8816 def nonDefaultTpeAssignmentFails = { val tpe = typeOf[Int] attrlessTrees.foreach { t => diff --git a/test/junit/scala/tools/nsc/symtab/FreshNameExtractorTest.scala b/test/junit/scala/tools/nsc/symtab/FreshNameExtractorTest.scala index cf09abdfff..effbfb2f7c 100644 --- a/test/junit/scala/tools/nsc/symtab/FreshNameExtractorTest.scala +++ b/test/junit/scala/tools/nsc/symtab/FreshNameExtractorTest.scala @@ -36,7 +36,7 @@ class FreshNameExtractorTest { } } - @Test + @Test @org.junit.Ignore // SI-8818 def extractionsFailsIfNameDoesntEndWithNumber = { val Creator = new FreshNameCreator(prefixes.head) val Extractor = new FreshNameExtractor(prefixes.head) @@ -44,4 +44,4 @@ class FreshNameExtractorTest { val Extractor(_) = TermName(Creator.newName("foo") + "bar") } } -}
\ No newline at end of file +} diff --git a/test/junit/scala/tools/nsc/symtab/StdNamesTest.scala b/test/junit/scala/tools/nsc/symtab/StdNamesTest.scala index 4a39cf9d48..524d2e45e0 100644 --- a/test/junit/scala/tools/nsc/symtab/StdNamesTest.scala +++ b/test/junit/scala/tools/nsc/symtab/StdNamesTest.scala @@ -15,12 +15,16 @@ class StdNamesTest { @Test def testNewTermNameInvalid(): Unit = { - assertThrows[IllegalArgumentException](newTermName("foo".toCharArray, 0, -1)) - assertThrows[IllegalArgumentException](newTermName("foo".toCharArray, 0, 0)) assertThrows[IllegalArgumentException](newTermName("foo".toCharArray, -1, 1)) } @Test + def testNewTermNameNegativeLenght(): Unit = { + assertEquals(nme.EMPTY, newTermName("foo".toCharArray, 0, -1)) + assertEquals(nme.EMPTY, newTermName("foo".toCharArray, 0, 0)) + } + + @Test def testUnspecializedName(): Unit = { def test(expected: Name, nme: Name) { assertEquals(expected, unspecializedName(nme)) diff --git a/test/junit/scala/tools/testing/AssertUtil.scala b/test/junit/scala/tools/testing/AssertUtil.scala index 9a97c5114f..9b4833d46b 100644 --- a/test/junit/scala/tools/testing/AssertUtil.scala +++ b/test/junit/scala/tools/testing/AssertUtil.scala @@ -19,6 +19,8 @@ object AssertUtil { val clazz = manifest.runtimeClass if (!clazz.isAssignableFrom(e.getClass)) throw e + else return } + throw new AssertionError("Expression did not throw!") } } |