diff options
author | Antonio Cunei <antonio.cunei@epfl.ch> | 2011-03-22 16:12:34 +0000 |
---|---|---|
committer | Antonio Cunei <antonio.cunei@epfl.ch> | 2011-03-22 16:12:34 +0000 |
commit | b40373367e6803349470ecabc3ef646f50353139 (patch) | |
tree | 46ffca136ba3e12a0a80f2e93c8c2f05d7b7ad5b /src | |
parent | cf2ad5308cd095521f45aa88d9fe8981ff4717a6 (diff) | |
download | scala-b40373367e6803349470ecabc3ef646f50353139.tar.gz scala-b40373367e6803349470ecabc3ef646f50353139.tar.bz2 scala-b40373367e6803349470ecabc3ef646f50353139.zip |
Merged revisions 24525-24539 via svnmerge from
https://lampsvn.epfl.ch/svn-repos/scala/scala/trunk
........
r24525 | kzys | 2011-03-21 13:24:48 +0100 (Mon, 21 Mar 2011) | 1 line
[scaladoc] Add HtmlFactoryTest and reorganize directory structure.
Reviewed by pedrofurla. ........ r24526 | kzys | 2011-03-21 13:44:20
+0100 (Mon, 21 Mar 2011) | 2 lines
[scaladoc] Add a test for #4361.
........
r24527 | plocinic | 2011-03-21 14:37:53 +0100 (Mon, 21 Mar 2011) | 1 line
Closes #4202 again, closes #4363. if someone can enlighten me why we
actually had that exclusion for companion objects in the first place I
would be grateful. review by odersky ........ r24528 | kzys | 2011-03-21
14:47:57 +0100 (Mon, 21 Mar 2011) | 2 lines
[scaladoc] Add a test for #4306. Review by pedrofurla. ........ r24529
| extempore | 2011-03-21 17:19:33 +0100 (Mon, 21 Mar 2011) | 2 lines
One hundred! One hundred times slower on windows! Ah, ha, ha! Adjusted
test case, no review. ........ r24530 | cunei | 2011-03-21 18:08:00
+0100 (Mon, 21 Mar 2011) | 2 lines
license files
........
r24531 | cunei | 2011-03-21 18:13:20 +0100 (Mon, 21 Mar 2011) | 2 lines
license files.
........
r24532 | cunei | 2011-03-21 18:47:44 +0100 (Mon, 21 Mar 2011) | 5 lines
removed gpl
Some javascript utils are dual licensed under gpl and mit. We already
include the mit ones. ........ r24533 | extempore | 2011-03-21 23:25:40
+0100 (Mon, 21 Mar 2011) | 20 lines
[I'm laptop only so there's some chance this will incur temporary
breakage, but it needs committing.]
Heading off gratuitous complications which haven't yet shipped, I
eliminated the -jar startup option in favor of doing what we already
do, figuring it out. So now all these things work.
scala foo/bar.scala // if file is a script or has one main method
scala foo.Bar // if it has a legal main method scala foo.jar // if
it has a legal MainClass attribute
Also changed "-savecompiled" to "-save" and given scala source called
foo.scala, generate foo.jar rather than foo.scala.jar. Cleaned up a
bunch of related code and further polished the scala startup message.
And unbroke choice settings and improved that error too, which closes
#3849.
While trying to write a test for the choice setting, was reminded that
partest just discards invalid flags files. Made it fail instead, which
closes #3712. Fixed the new failures that revealed. No review. ........
r24534 | extempore | 2011-03-21 23:46:53 +0100 (Mon, 21 Mar 2011) | 2
lines
We need a successful build, not sure why this hasn't been disabled
yet. Disabled failing coder test, no review. ........ r24535 | extempore
| 2011-03-22 01:06:44 +0100 (Tue, 22 Mar 2011) | 3 lines
Oh the irony, disabling the failing test made the build fail, because
another test is hardcoded to use its paths. Disabled that test too.
We'll put humpty back together again. No review. ........ r24536 |
extempore | 2011-03-22 05:28:21 +0100 (Tue, 22 Mar 2011) | 6 lines
Not yet learned my lesson about partest and empty directories. Rather
than reapply that bandaid, went after partest. Attempts to make partest
ignore empty directories. Discover directory tests aren't run when
the command line tool is used, make them run like everyone else. Find
more tests which due to misplacement are silently ignored, move them
into tested locations. No review. ........ r24537 | kzys | 2011-03-22
15:10:25 +0100 (Tue, 22 Mar 2011) | 2 lines
[scaladoc] Closes #4366. Review by pedrofurla.
........
r24538 | moors | 2011-03-22 15:31:36 +0100 (Tue, 22 Mar 2011) | 1 line
closes #4205: quick&dirty fix to force loading of info's and thus
avoid order-dependency until we fix unsafeTypeParams for good. no review
........ r24539 | moors | 2011-03-22 16:43:28 +0100 (Tue, 22 Mar 2011) |
1 line
closes #4345. skip variance checks for calls to super accessor. no
review ........
Diffstat (limited to 'src')
26 files changed, 262 insertions, 182 deletions
diff --git a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala index 68689a4109..86ab76b59c 100644 --- a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala +++ b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala @@ -5,6 +5,8 @@ package scala.tools.nsc +import GenericRunnerCommand._ + /** A command for ScriptRunner */ class GenericRunnerCommand( args: List[String], @@ -24,30 +26,31 @@ extends CompilerCommand(args, settings) { // change CompilerCommand behavior override def shouldProcessArguments: Boolean = false - /** thingToRun: What to run. If it is None, then the interpreter should be started - * arguments: Arguments to pass to the object or script to run - */ - val (_ok, thingToRun, arguments) = { - val (ok, remaining) = settings.processArguments(args, false) - val mainClass = - if (settings.jarfile.isDefault) None - else new io.Jar(settings.jarfile.value).mainClass - - // If there is a jar with a main class, the remaining args are passed to that. - // Otherwise, the first remaining argument is the program to run, and the rest - // of the arguments go to it. If remaining is empty, we'll start the repl. - mainClass match { - case Some(name) => (ok, Some(name), remaining) - case _ => (ok, remaining.headOption, remaining drop 1) + private lazy val (_ok, targetAndArguments) = settings.processArguments(args, false) + override def ok = _ok + private def guessHowToRun(target: String): GenericRunnerCommand.HowToRun = { + if (!ok) Error + else if (io.Jar.isJarOrZip(target)) AsJar + else if (util.ScalaClassLoader.classExists(settings.classpathURLs, target)) AsObject + else { + val f = io.File(target) + if (!f.hasExtension("class", "jar", "zip") && f.canRead) AsScript + else sys.error("Cannot figure out how to run target: " + target) } } - override def ok = _ok - + /** String with either the jar file, class name, or script file name. */ + def thingToRun = targetAndArguments.headOption getOrElse "" + /** Arguments to thingToRun. */ + def arguments = targetAndArguments drop 1 + + val howToRun = targetAndArguments match { + case Nil => AsRepl + case hd :: _ => waysToRun find (_.name == settings.howtorun.value) getOrElse guessHowToRun(hd) + } private def interpolate(s: String) = s.trim.replaceAll("@cmd@", cmdName).replaceAll("@compileCmd@", compCmdName) + "\n" def shortUsageMsg = interpolate(""" -Usage: @cmd@ <options> [<script|class|object> <arguments>] - or @cmd@ <options> [-jar <jarfile> <arguments>] +Usage: @cmd@ <options> [<script|class|object|jar> <arguments>] or @cmd@ -help All options to @compileCmd@ are also allowed. See @compileCmd@ -help. @@ -59,26 +62,37 @@ what to run. Runnable targets are: - a file containing scala source - the name of a compiled class - - a runnable jar file with a Main-Class attribute (if -jar is given) - - if no argument is given, the repl (interactive shell) is started + - a runnable jar file with a valid Main-Class attribute + - or if no argument is given, the repl (interactive shell) is started -Options to the runner which reach the java runtime: +Options to @cmd@ which reach the java runtime: -Dname=prop passed directly to java to set system properties -J<arg> -J is stripped and <arg> passed to java as-is -nobootcp do not put the scala jars on the boot classpath (slower) -Other scala startup options: +Other startup options: - -howtorun specify what to run <script|object|guess> (default: guess) - -i <file> preload <file> before starting the repl - -e <string> execute <string> as if entered in the repl - -nc no compilation daemon: do not use the fsc offline compiler - -savecompiled save the compiled script in a jar for future use + -howtorun what to run <script|object|jar|guess> (default: guess) + -i <file> preload <file> before starting the repl + -e <string> execute <string> as if entered in the repl + -save save the compiled script in a jar for future use + -nc no compilation daemon: do not use the fsc offline compiler -A file argument will be run as a scala script unless it contains only top -level classes and objects, and exactly one runnable main method. In that -case the file will be compiled and the main method invoked. This provides -a bridge between scripts and standard scala source. +A file argument will be run as a scala script unless it contains only +self-contained compilation units (classes and objects) and exactly one +runnable main method. In that case the file will be compiled and the +main method invoked. This provides a bridge between scripts and standard +scala source. """) + "\n" } + +object GenericRunnerCommand { + sealed abstract class HowToRun(val name: String) { } + case object AsJar extends HowToRun("jar") + case object AsObject extends HowToRun("object") + case object AsScript extends HowToRun("script") + case object AsRepl extends HowToRun("repl") + case object Error extends HowToRun("<error>") + val waysToRun = List(AsJar, AsObject, AsScript, AsRepl) +} diff --git a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala index bd0ea4a4ba..45f8d1af5f 100644 --- a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala +++ b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala @@ -5,24 +5,17 @@ package scala.tools.nsc +import scala.tools.util.PathResolver + class GenericRunnerSettings(error: String => Unit) extends Settings(error) { - // A -jar option means the remainder of the command line should be - // passed to the main program in the jar. If -jar is given, jarfile - // will be set, but we also need to prepend the jar to the classpath - // since it may not be there. - val jarfile = - StringSetting( - "-jar", - "jar", - "Specify the jarfile in which to look for the main class", - "").stopProcessing() withPostSetHook (classpath prepend _.value) + def classpathURLs = new PathResolver(this) asURLs val howtorun = ChoiceSetting( "-howtorun", "how", "how to run the specified code", - List("guess", "object", "script"), + List("object", "script", "jar", "guess"), "guess") val loadfiles = @@ -38,14 +31,15 @@ class GenericRunnerSettings(error: String => Unit) extends Settings(error) { "execute a single command", "") - val savecompiled = + val save = BooleanSetting( - "-savecompiled", - "save the compiled script (assumes the code is a script)") + "-save", + "save the compiled script (assumes the code is a script)") withAbbreviation "-savecompiled" val nc = BooleanSetting( "-nc", "do not use the fsc compilation daemon") withAbbreviation "-nocompdaemon" @deprecated("Use `nc` instead") def nocompdaemon = nc + @deprecated("Use `save` instead") def savecompiled = save } diff --git a/src/compiler/scala/tools/nsc/MainGenericRunner.scala b/src/compiler/scala/tools/nsc/MainGenericRunner.scala index e40fdea3b9..7ead4cce4a 100644 --- a/src/compiler/scala/tools/nsc/MainGenericRunner.scala +++ b/src/compiler/scala/tools/nsc/MainGenericRunner.scala @@ -13,6 +13,7 @@ import io.{ File } import util.{ ClassPath, ScalaClassLoader } import Properties.{ versionString, copyrightString } import interpreter.{ ILoop } +import GenericRunnerCommand._ /** An object that runs Scala code. It has three possible * sources for the code to run: pre-compiled code, a script file, @@ -35,7 +36,7 @@ object MainGenericRunner { def process(args: Array[String]): Boolean = { val command = new GenericRunnerCommand(args.toList, (x: String) => errorFn(x)) - import command.settings + import command.{ settings, howToRun, thingToRun } def sampleCompiler = new Global(settings) // def so its not created unless needed if (!command.ok) return errorFn("\n" + command.shortUsageMsg) @@ -55,44 +56,35 @@ object MainGenericRunner { files ++ str mkString "\n\n" } - val classpath: List[URL] = new PathResolver(settings) asURLs + def runTarget(): Either[Throwable, Boolean] = howToRun match { + case AsObject => + ObjectRunner.runAndCatch(settings.classpathURLs, thingToRun, command.arguments) + case AsScript => + ScriptRunner.runScriptAndCatch(settings, thingToRun, command.arguments) + case AsJar => + ObjectRunner.runAndCatch( + File(thingToRun).toURL +: settings.classpathURLs, + new io.Jar(thingToRun).mainClass getOrElse sys.error("Cannot find main class for jar: " + thingToRun), + command.arguments + ) + case _ => + // We start the repl when no arguments are given. + Right(new ILoop process settings) + } - /** Was code given in a -e argument? */ + /** If -e and -i were both given, we want to execute the -e code after the + * -i files have been included, so they are read into strings and prepended to + * the code given in -e. The -i option is documented to only make sense + * interactively so this is a pretty reasonable assumption. + * + * This all needs a rewrite though. + */ if (isE) { - /** If a -i argument was also given, we want to execute the code after the - * files have been included, so they are read into strings and prepended to - * the code given in -e. The -i option is documented to only make sense - * interactively so this is a pretty reasonable assumption. - * - * This all needs a rewrite though. - */ - val fullArgs = command.thingToRun.toList ::: command.arguments - - return ScriptRunner.runCommand(settings, combinedCode, fullArgs) + ScriptRunner.runCommand(settings, combinedCode, thingToRun +: command.arguments) } - else command.thingToRun match { - case None => - // We start the repl when no arguments are given. - new ILoop process settings - - case Some(thingToRun) => - val isObjectName = - settings.howtorun.value match { - case "object" => true - case "script" => false - case "guess" => ScalaClassLoader.classExists(classpath, thingToRun) - } - - val result = try { - if (isObjectName) ObjectRunner.runAndCatch(classpath, thingToRun, command.arguments) - else ScriptRunner.runScriptAndCatch(settings, thingToRun, command.arguments) - } - catch { case ex => Left(ex) } - - result match { - case Left(ex) => errorFn(ex) - case Right(b) => b - } + else runTarget() match { + case Left(ex) => errorFn(ex) + case Right(b) => b } } } diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala index 07aa62d164..96b7bce885 100644 --- a/src/compiler/scala/tools/nsc/ScriptRunner.scala +++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala @@ -61,13 +61,10 @@ class ScriptRunner extends HasCompileSocket { def isScript(settings: Settings) = settings.script.value != "" /** Choose a jar filename to hold the compiled version of a script. */ - private def jarFileFor(scriptFile: String): File = { - val name = - if (scriptFile endsWith ".jar") scriptFile - else scriptFile + ".jar" - - File(name) - } + private def jarFileFor(scriptFile: String)= File( + if (scriptFile endsWith ".jar") scriptFile + else scriptFile.stripSuffix(".scala") + ".jar" + ) /** Read the entire contents of a file as a String. */ private def contentsOfFile(filename: String) = File(filename).slurp() @@ -140,7 +137,7 @@ class ScriptRunner extends HasCompileSocket { * not take place until there are no non-daemon threads running. Tickets #1955, #2006. */ waitingForThreads { - if (settings.savecompiled.value) { + if (settings.save.value) { val jarFile = jarFileFor(scriptFile) def jarOK = jarFile.canRead && (jarFile isFresher File(scriptFile)) @@ -179,10 +176,8 @@ class ScriptRunner extends HasCompileSocket { compiledLocation: String, scriptArgs: List[String]): Boolean = { - val pr = new PathResolver(settings) - val classpath = File(compiledLocation).toURL +: pr.asURLs - - ObjectRunner.runAndCatch(classpath, scriptMain(settings), scriptArgs) match { + val cp = File(compiledLocation).toURL +: settings.classpathURLs + ObjectRunner.runAndCatch(cp, scriptMain(settings), scriptArgs) match { case Left(ex) => ex.printStackTrace() ; false case _ => true } diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala index 199c184bfc..a14bacb267 100644 --- a/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/html/HtmlFactory.scala @@ -64,20 +64,24 @@ class HtmlFactory(val universe: doc.Universe, index: doc.Index) { new page.Index(universe, index) writeFor this + writeTemplates(page => page.writeFor(this)) + + for(letter <- index.firstLetterIndex) { + new html.page.ReferenceIndex(letter._1, index, universe) writeFor this + } + } + + def writeTemplates(writeForThis: HtmlPage => Unit): Unit = { val written = mutable.HashSet.empty[DocTemplateEntity] def writeTemplate(tpl: DocTemplateEntity): Unit = if (!(written contains tpl)) { - new page.Template(tpl) writeFor this + writeForThis(new page.Template(tpl)) written += tpl tpl.templates map (writeTemplate(_)) } writeTemplate(universe.rootPackage) - - for(letter <- index.firstLetterIndex) { - new html.page.ReferenceIndex(letter._1, index, universe) writeFor this - } } } diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala index 95016099ff..21d6ba91a9 100644 --- a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala +++ b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala @@ -34,7 +34,7 @@ abstract class HtmlPage { thisPage => protected def headers: NodeSeq /** The body of this page. */ - protected def body: NodeSeq + def body: NodeSeq /** Writes this page as a file. The file's location is relative to the generator's site root, and the encoding is * also defined by the generator. diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala b/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala index dd2093a88e..52ef154325 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala @@ -67,7 +67,18 @@ final case class Link(target: String, title: Inline) extends Inline final case class EntityLink(target: TemplateEntity) extends Inline final case class Monospace(text: String) extends Inline final case class Text(text: String) extends Inline -final case class HtmlTag(data: String) extends Inline +final case class HtmlTag(data: String) extends Inline { + def canClose(open: HtmlTag) = { + open.data.stripPrefix("<") == data.stripPrefix("</") + } + + def close = { + if (data.indexOf("</") == -1) + Some(HtmlTag("</" + data.stripPrefix("<"))) + else + None + } +} /** The summary of a comment, usually its first sentence. There must be exactly one summary per body. */ final case class Summary(text: Inline) extends Inline diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala b/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala index e39907ac55..b3033188e9 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/Comment.scala @@ -18,8 +18,41 @@ abstract class Comment { /** The main body of the comment that describes what the entity does and is. */ def body: Body + private def closeHtmlTags(inline: Inline) = { + val stack = mutable.ListBuffer.empty[HtmlTag] + def scan(i: Inline): Unit = { + i match { + case Chain(list) => + list.foreach(scan) + case tag: HtmlTag => { + if (stack.length > 0 && tag.canClose(stack.last)) { + stack.remove(stack.length-1) + } else { + tag.close match { + case Some(t) => + stack += t + case None => + ; + } + } + } + case _ => + ; + } + } + scan(inline) + Chain(List(inline) ++ stack.reverse) + } + /** A shorter version of the body. Usually, this is the first sentence of the body. */ - def short: Inline = body.summary getOrElse Text("") + def short: Inline = { + body.summary match { + case Some(s) => + closeHtmlTags(s) + case _ => + Text("") + } + } /** A list of authors. The empty list is used when no author is defined. */ def authors: List[Body] diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala index d82d5bfa5a..7485533641 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala @@ -172,7 +172,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => /** Safe HTML tags that can be kept. */ protected val SafeTags = - new Regex("""((&\w+;)|(&#\d+;)|(<code( [^>]*)?>.*</code>)|(</?(abbr|acronym|address|area|a|bdo|big|blockquote|br|button|b|caption|cite|col|colgroup|dd|del|dfn|em|fieldset|form|hr|img|input|ins|i|kbd|label|legend|link|map|object|optgroup|option|param|pre|q|samp|select|small|span|strong|sub|sup|table|tbody|td|textarea|tfoot|th|thead|tr|tt|var)( [^>]*)?/?>))""") + new Regex("""((&\w+;)|(&#\d+;)|(<code( [^>]*)?>.*?</code>)|(</?(abbr|acronym|address|area|a|bdo|big|blockquote|br|button|b|caption|cite|col|colgroup|dd|del|dfn|em|fieldset|form|hr|img|input|ins|i|kbd|label|legend|link|map|object|optgroup|option|param|pre|q|samp|select|small|span|strong|sub|sup|table|tbody|td|textarea|tfoot|th|thead|tr|tt|var)( [^>]*)?/?>))""") protected val safeTagMarker = '\u000E' diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala index 3d4ff7a20b..584b8867b2 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala @@ -38,7 +38,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: PrintWriter) with LoopCommands { def this(in0: BufferedReader, out: PrintWriter) = this(Some(in0), out) - def this() = this(None, new PrintWriter(Console.out)) + def this() = this(None, new PrintWriter(Console.out, true)) var in: InteractiveReader = _ // the input stream from which commands come var settings: Settings = _ @@ -162,8 +162,9 @@ class ILoop(in0: Option[BufferedReader], protected val out: PrintWriter) |Type in expressions to have them evaluated. |Type :help for more information.""" . stripMargin.format(versionString, javaVmName, javaVersion) + val addendum = if (isReplDebug) "\n" + new java.util.Date else "" - plushln(welcomeMsg) + plushln(welcomeMsg + addendum) } /** Show the history */ @@ -748,7 +749,12 @@ class ILoop(in0: Option[BufferedReader], protected val out: PrintWriter) } @deprecated("Use `process` instead") - def main(args: Array[String]): Unit = process(args) + def main(args: Array[String]): Unit = { + if (isReplDebug) + System.out.println(new java.util.Date) + + process(args) + } @deprecated("Use `process` instead") def main(settings: Settings): Unit = process(settings) } @@ -765,7 +771,7 @@ object ILoop { stringFromStream { ostream => Console.withOut(ostream) { val input = new BufferedReader(new StringReader(code)) - val output = new PrintWriter(new OutputStreamWriter(ostream)) + val output = new PrintWriter(new OutputStreamWriter(ostream), true) val repl = new ILoop(input, output) val settings = new Settings settings.classpath.value = sys.props("java.class.path") diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index 527a9b153a..d74aa5e6df 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -87,6 +87,8 @@ class IMain(val settings: Settings, protected val out: PrintWriter) { // not sure if we have some motivation to print directly to console private def echo(msg: String) { Console println msg } + // protected def defaultImports: List[String] = List("_root_.scala.sys.exit") + /** We're going to go to some trouble to initialize the compiler asynchronously. * It's critical that nothing call into it until it's been initialized or we will * run into unrecoverable issues, but the perceived repl startup time goes @@ -114,6 +116,7 @@ class IMain(val settings: Settings, protected val out: PrintWriter) { // Can't use printMessage here, it deadlocks Console.println("Repl compiler initialized.") } + // addImports(defaultImports: _*) true } catch { @@ -609,6 +612,10 @@ class IMain(val settings: Settings, protected val out: PrintWriter) { quietRun("val %s = %s".format(tempName, name)) quietRun("val %s = %s.asInstanceOf[%s]".format(name, tempName, newType)) } + def quietImport(ids: String*): IR.Result = beQuietDuring(addImports(ids: _*)) + def addImports(ids: String*): IR.Result = + if (ids.isEmpty) IR.Success + else interpret("import " + ids.mkString(", ")) def quietBind(p: NamedParam): IR.Result = beQuietDuring(bind(p)) def bind(p: NamedParam): IR.Result = bind(p.name, p.tpe, p.value) diff --git a/src/compiler/scala/tools/nsc/io/Jar.scala b/src/compiler/scala/tools/nsc/io/Jar.scala index 0796742fb6..a9f0acaa00 100644 --- a/src/compiler/scala/tools/nsc/io/Jar.scala +++ b/src/compiler/scala/tools/nsc/io/Jar.scala @@ -65,8 +65,29 @@ class JarWriter(file: File, val manifest: Manifest = new Manifest()) { } object Jar { - // CLASS_PATH - // CONTENT_TYPE + // See http://download.java.net/jdk7/docs/api/java/nio/file/Path.html + // for some ideas. + private val ZipMagicNumber = List[Byte](80, 75, 3, 4) + private def magicNumberIsZip(f: Path) = f.isFile && (f.toFile.bytes().take(4).toList == ZipMagicNumber) + + def isJarOrZip(f: Path): Boolean = isJarOrZip(f, true) + def isJarOrZip(f: Path, examineFile: Boolean): Boolean = + f.hasExtension("zip", "jar") || (examineFile && magicNumberIsZip(f)) + + def locateByClass(clazz: Class[_]): Option[File] = { + try Some(File(clazz.getProtectionDomain().getCodeSource().getLocation().toURI().getPath())) + catch { case _: Exception => None } + } + /** Walks upward from wherever the scala library jar is searching for + * the given jar name. This approach finds the scala library jar in the + * release layout and in trunk builds going up from pack. + */ + def locateByName(name: String): Option[File] = { + def toSrc(d: Directory) = d.dirs.toList map (_ / name) + def walk(d: Directory) = d.parents flatMap toSrc find (_.isFile) map (_.toFile) + + locateByClass(classOf[ScalaObject]) flatMap (x => walk(x.parent)) + } def create(file: File, sourceDir: Directory, mainClass: String): File = { val writer = new Jar(file).jarWriter() diff --git a/src/compiler/scala/tools/nsc/io/Path.scala b/src/compiler/scala/tools/nsc/io/Path.scala index 68e9867dd7..3cfab55aaa 100644 --- a/src/compiler/scala/tools/nsc/io/Path.scala +++ b/src/compiler/scala/tools/nsc/io/Path.scala @@ -28,37 +28,12 @@ import scala.util.Random.alphanumeric */ object Path { - // See http://download.java.net/jdk7/docs/api/java/nio/file/Path.html - // for some ideas. - private val ZipMagicNumber = List[Byte](80, 75, 3, 4) - private def magicNumberIsZip(f: Path) = f.isFile && (f.toFile.bytes().take(4).toList == ZipMagicNumber) - - /** If examineFile is true, it will look at the first four bytes of the file - * and see if the magic number indicates it may be a jar or zip. - */ - def isJarOrZip(f: Path): Boolean = isJarOrZip(f, true) - def isJarOrZip(f: Path, examineFile: Boolean): Boolean = - f.hasExtension("zip", "jar") || (examineFile && magicNumberIsZip(f)) + def isJarOrZip(f: Path, examineFile: Boolean = true) = Jar.isJarOrZip(f, examineFile) // not certain these won't be problematic, but looks good so far implicit def string2path(s: String): Path = apply(s) implicit def jfile2path(jfile: JFile): Path = apply(jfile) - def locateJarByClass(clazz: Class[_]): Option[File] = { - try Some(File(clazz.getProtectionDomain().getCodeSource().getLocation().toURI().getPath())) - catch { case _: Exception => None } - } - /** Walks upward from wherever the scala library jar is searching for - * the given jar name. This approach finds the scala library jar in the - * release layout and in trunk builds going up from pack. - */ - def locateJarByName(name: String): Option[File] = { - def toSrc(d: Directory) = d.dirs.toList map (_ / name) - def walk(d: Directory) = d.parents flatMap toSrc find (_.isFile) map (_.toFile) - - locateJarByClass(classOf[ScalaObject]) flatMap (x => walk(x.parent)) - } - // java 7 style, we don't use it yet // object AccessMode extends Enumeration("AccessMode") { // val EXECUTE, READ, WRITE = Value diff --git a/src/compiler/scala/tools/nsc/io/Sources.scala b/src/compiler/scala/tools/nsc/io/Sources.scala index 48682e4ad4..c763b04511 100644 --- a/src/compiler/scala/tools/nsc/io/Sources.scala +++ b/src/compiler/scala/tools/nsc/io/Sources.scala @@ -4,7 +4,7 @@ package io import util.ClassPath import java.util.concurrent.{ Future, ConcurrentHashMap, ExecutionException } import java.util.zip.ZipException -import Path.{ isJarOrZip, locateJarByName } +import Jar.{ isJarOrZip, locateByClass } import collection.JavaConverters._ import Properties.{ envOrElse, propOrElse } @@ -62,7 +62,6 @@ trait LowPrioritySourcesImplicits { implicit def fallbackSources: Sources = defaultSources } - object Sources extends LowPrioritySourcesImplicits { // Examples of what libraryJar might be, each of which we'd like to find // the source files automatically: @@ -70,7 +69,7 @@ object Sources extends LowPrioritySourcesImplicits { // /scala/trunk/build/pack/lib/scala-library.jar // /scala/trunk/build/quick/classes/library // /scala/inst/scala-2.9.0.r24213-b20110206233447/lib/scala-library.jar - private def libraryJar = Path.locateJarByClass(classOf[ScalaObject]) map (_.toAbsolute.path) + private def libraryJar = locateByClass(classOf[ScalaObject]) map (_.toAbsolute.path) private def autoSourcePaths: List[String] = libraryJar.toList flatMap { lib => val markers = List("build/pack/lib", "build/quick/classes", "scala-library.jar") markers filter (lib contains _) flatMap { m => diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala index 6a357cc08a..b485d4725a 100644 --- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala @@ -527,10 +527,14 @@ class MutableSettings(val errorFn: String => Unit) extends AbsSettings with Scal protected var v: String = default def indexOfChoice: Int = choices indexOf value - def tryToSet(args: List[String]) = { value = default ; Some(args) } + private def usageErrorMessage = { + "Usage: %s:<%s>\n where <%s> choices are %s (default: %s)\n".format( + name, helpArg, helpArg, choices mkString ", ", default) + } + def tryToSet(args: List[String]) = errorAndValue(usageErrorMessage, None) override def tryToSetColon(args: List[String]) = args match { - case Nil => errorAndValue("missing " + helpArg, None) + case Nil => errorAndValue(usageErrorMessage, None) case List(x) if choices contains x => value = x ; Some(Nil) case List(x) => errorAndValue("'" + x + "' is not a valid choice for '" + name + "'", None) case xs => errorAndValue("'" + name + "' does not accept multiple arguments.", None) diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 0240e80816..d7f9063ec6 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -1309,7 +1309,7 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable => * class Foo . companionModule --> object Foo */ final def companionModule: Symbol = - if (isClass && !isAnonOrRefinementClass) companionModule0 + if (isClass && !isRefinementClass) companionModule0 else NoSymbol /** For a module: its linked class diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index fd86fb7345..3e41df45f8 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -5618,6 +5618,7 @@ A type's typeSymbol should never be inspected directly. val errors = new ListBuffer[(Type, Symbol, List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)])] (tparams zip targs).foreach{ case (tparam, targ) if (targ.isHigherKinded || !tparam.typeParams.isEmpty) => // @M must use the typeParams of the type targ, not the typeParams of the symbol of targ!! + targ.typeSymbolDirect.info // force symbol load for #4205 val tparamsHO = targ.typeParams val (arityMismatches, varianceMismatches, stricterBounds) = diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 05224ae37b..caba8f9bd1 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -574,10 +574,9 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { private def staticRef(sym: Symbol): Tree = { sym.owner.info //todo: needed? sym.owner.owner.info //todo: needed? - if (sym.owner.sourceModule == NoSymbol) { + if (sym.owner.sourceModule == NoSymbol) assert(false, "" + sym + " in " + sym.owner + " in " + sym.owner.owner + " " + sym.owner.owner.info.decls.toList)//debug - } REF(sym.owner.sourceModule) DOT sym } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 3d769f6cfd..63542e6dd5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -688,7 +688,7 @@ abstract class RefChecks extends InfoTransform { !(tvar.isTypeParameterOrSkolem && sym.isTypeParameterOrSkolem && tvar.owner == sym.owner)) state = -state; else if (!sym.owner.isClass || - sym.isTerm && ((sym.isPrivateLocal || sym.isProtectedLocal) && !(escapedPrivateLocals contains sym))) { + sym.isTerm && ((sym.isPrivateLocal || sym.isProtectedLocal || sym.isSuperAccessor /* super accessors are implicitly local #4345*/) && !(escapedPrivateLocals contains sym))) { // return AnyVariance if `sym` is local to a term // or is private[this] or protected[this] state = AnyVariance diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index 1e29dd4fae..bb404480a9 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -83,6 +83,7 @@ object ClassPath { /** Join the paths as a classpath */ def fromPaths(paths: Path*): String = join(paths map (_.path): _*) + def fromURLs(urls: URL*): String = fromPaths(urls map (x => Path(x.getPath)) : _*) /** Split the classpath and map them into URLs */ def toURLs(cp: String): List[URL] = toPaths(cp) map (_.toURL) diff --git a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala index ee71d04827..be69c39547 100644 --- a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala +++ b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala @@ -93,13 +93,20 @@ object ScalaClassLoader { with ScalaClassLoader { private var classloaderURLs = urls.toList + private def classpathString = ClassPath.fromURLs(urls: _*) /** Override to widen to public */ override def addURL(url: URL) = { classloaderURLs +:= url super.addURL(url) } - + override def run(objectName: String, arguments: Seq[String]) { + try super.run(objectName, arguments) + catch { case x: ClassNotFoundException => + throw new ClassNotFoundException(objectName + + " (args = %s, classpath = %s)".format(arguments mkString ", ", classpathString)) + } + } override def toString = urls.mkString("URLClassLoader(\n ", "\n ", "\n)\n") } diff --git a/src/partest/scala/tools/partest/PartestTask.scala b/src/partest/scala/tools/partest/PartestTask.scala index 551500e626..f1b3ea496d 100644 --- a/src/partest/scala/tools/partest/PartestTask.scala +++ b/src/partest/scala/tools/partest/PartestTask.scala @@ -14,7 +14,6 @@ package partest import scala.actors.Actor._ import scala.util.Properties.setProp import scala.tools.nsc.io.{ Directory, Path => SPath } -import nsc.Settings import nsc.util.ClassPath import util.PathResolver import scala.tools.ant.sabbus.CompilationPathProperty diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala index 42e4d02934..fbf758d5a5 100644 --- a/src/partest/scala/tools/partest/nest/CompileManager.scala +++ b/src/partest/scala/tools/partest/nest/CompileManager.scala @@ -10,10 +10,9 @@ package nest import scala.tools.nsc.{ Global, Settings, CompilerCommand, FatalError, io } import scala.tools.nsc.reporters.{ Reporter, ConsoleReporter } -import scala.tools.nsc.util.ClassPath +import scala.tools.nsc.util.{ ClassPath, FakePos } import scala.tools.util.PathResolver import io.Path - import java.io.{ File, BufferedReader, PrintWriter, FileReader, Writer, FileWriter, StringWriter } import File.pathSeparator @@ -95,7 +94,13 @@ class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler { case "presentation" => PresentationTestFile.apply } val test: TestFile = testFileFn(files.head, fileManager) - test.defineSettings(command.settings, out.isEmpty) + if (!test.defineSettings(command.settings, out.isEmpty)) { + testRep.error(FakePos("partest"), test.flags match { + case Some(flags) => "bad flags: " + flags + case _ => "bad settings: " + command.settings + }) + } + val toCompile = files map (_.getPath) try { @@ -106,8 +111,8 @@ class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler { testRep.error(null, "fatal error: " + msg) } - testRep.printSummary - testRep.writer.close + testRep.printSummary() + testRep.writer.close() } finally logWriter.close() diff --git a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala index b79c2bbbdb..e2afc5644f 100644 --- a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala +++ b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala @@ -21,22 +21,23 @@ class ConsoleRunner extends DirectRunner { import PathSettings.{ srcDir, testRoot } case class TestSet(kind: String, filter: Path => Boolean, msg: String) + def stdFilter(p: Path) = p.isDirectory || (p hasExtension "scala") val testSets = { - val pathFilter: Path => Boolean = _ hasExtension "scala" + val pathFilter: Path => Boolean = x => x.isDirectory || (x hasExtension "scala") List( - TestSet("pos", pathFilter, "Testing compiler (on files whose compilation should succeed)"), - TestSet("neg", pathFilter, "Testing compiler (on files whose compilation should fail)"), - TestSet("run", pathFilter, "Testing interpreter and backend"), - TestSet("jvm", pathFilter, "Testing JVM backend"), + TestSet("pos", stdFilter, "Testing compiler (on files whose compilation should succeed)"), + TestSet("neg", stdFilter, "Testing compiler (on files whose compilation should fail)"), + TestSet("run", stdFilter, "Testing interpreter and backend"), + TestSet("jvm", stdFilter, "Testing JVM backend"), TestSet("res", x => x.isFile && (x hasExtension "res"), "Testing resident compiler"), TestSet("buildmanager", _.isDirectory, "Testing Build Manager"), - TestSet("shootout", pathFilter, "Testing shootout tests"), - TestSet("script", pathFilter, "Testing script tests"), - TestSet("scalacheck", x => pathFilter(x) || x.isDirectory, "Testing ScalaCheck tests"), + TestSet("shootout", stdFilter, "Testing shootout tests"), + TestSet("script", stdFilter, "Testing script tests"), + TestSet("scalacheck", stdFilter, "Testing ScalaCheck tests"), TestSet("scalap", _.isDirectory, "Run scalap decompiler tests"), - TestSet("specialized", pathFilter, "Testing specialized tests"), + TestSet("specialized", stdFilter, "Testing specialized tests"), TestSet("presentation", _.isDirectory, "Testing presentation compiler tests.") ) } @@ -49,10 +50,7 @@ class ConsoleRunner extends DirectRunner { private val testSetArgs = testSets map ("--" + _.kind) private val testSetArgMap = testSetArgs zip testSets toMap - def denotesTestSet(arg: String) = testSetArgs contains arg - def denotesTestFile(arg: String) = (arg endsWith ".scala") || (arg endsWith ".res") - def denotesTestDir(arg: String) = Path(arg).isDirectory - def denotesTestPath(arg: String) = denotesTestDir(arg) || denotesTestFile(arg) + def denotesTestSet(arg: String) = testSetArgs contains arg private def printVersion { NestUI outline (versionMsg + "\n") } @@ -72,22 +70,17 @@ class ConsoleRunner extends DirectRunner { (path.isFile && pred(path)) || (path.isDirectory && srcs.exists(pred)) || - (pred(Path(path.toAbsolute.stripExtension + ".check"))) + (pred(path changeExtension "check")) } def main(argstr: String) { val parsed = CommandLineParser(argstr) withUnaryArgs unaryArgs withBinaryArgs binaryArgs - val args = parsed.residualArgs + val args = onlyValidTestPaths(parsed.residualArgs) /** Early return on no args, version, or invalid args */ if (argstr == "") return NestUI.usage() if (parsed isSet "--version") return printVersion if (parsed isSet "--help") return NestUI.usage() - if (args exists (x => !denotesTestPath(x))) { - val invalid = (args filterNot denotesTestPath).head - NestUI.failure("Invalid argument '%s'\n" format invalid) - return NestUI.usage() - } parsed get "--srcpath" foreach (x => setProp("partest.srcdir", x)) @@ -97,7 +90,7 @@ class ConsoleRunner extends DirectRunner { else if (parsed isSet "--pack") new ConsoleFileManager("build/pack") else new ConsoleFileManager // auto detection, see ConsoleFileManager.findLatest - def argNarrowsTests(x: String) = denotesTestSet(x) || denotesTestFile(x) || denotesTestDir(x) + def argNarrowsTests(x: String) = denotesTestSet(x) || denotesTestPath(x) NestUI._verbose = parsed isSet "--verbose" fileManager.showDiff = true @@ -126,7 +119,7 @@ class ConsoleRunner extends DirectRunner { val grepOption = parsed get "--grep" val grepPaths = grepOption.toList flatMap { expr => val subjectDirs = testSetKinds map (srcDir / _ toDirectory) - val testPaths = subjectDirs flatMap (_.files filter (x => x.hasExtension("scala") || x.isDirectory)) + val testPaths = subjectDirs flatMap (_.files filter stdFilter) val paths = testPaths filter (p => pathMatchesExpr(p, expr)) if (paths.isEmpty) @@ -168,7 +161,7 @@ class ConsoleRunner extends DirectRunner { "Java options are: " + vmOpts, "Source directory is: " + srcDir, "" - ) foreach (x => NestUI outline (x + "\n")) + ) foreach (x => NestUI verbose (x + "\n")) NestUI.verbose("available processors: " + Runtime.getRuntime().availableProcessors()) diff --git a/src/partest/scala/tools/partest/nest/DirectRunner.scala b/src/partest/scala/tools/partest/nest/DirectRunner.scala index 96b0c5bea6..d4b1c8dcb1 100644 --- a/src/partest/scala/tools/partest/nest/DirectRunner.scala +++ b/src/partest/scala/tools/partest/nest/DirectRunner.scala @@ -26,6 +26,20 @@ trait DirectRunner { import PartestDefaults.numActors + def denotesTestFile(arg: String) = Path(arg).hasExtension("scala", "res") + def denotesTestDir(arg: String) = Path(arg).ifDirectory(_.files.nonEmpty) exists (x => x) + def denotesTestPath(arg: String) = denotesTestDir(arg) || denotesTestFile(arg) + + /** No duplicate, no empty directories, don't mess with this unless + * you like partest hangs. + */ + def onlyValidTestPaths[T](args: List[T]): List[T] = { + args.distinct filter (arg => denotesTestPath("" + arg) || { + NestUI.warning("Discarding invalid test path '%s'\n" format arg) + false + }) + } + def setProperties() { if (isPartestDebug) scala.actors.Debug.level = 3 @@ -37,8 +51,7 @@ trait DirectRunner { } def runTestsForFiles(_kindFiles: List[File], kind: String): immutable.Map[String, Int] = { - /** NO DUPLICATES, or partest will blow the count and hang forever. */ - val kindFiles = _kindFiles.distinct + val kindFiles = onlyValidTestPaths(_kindFiles) val groupSize = (kindFiles.length / numActors) + 1 val consFM = new ConsoleFileManager diff --git a/src/partest/scala/tools/partest/nest/TestFile.scala b/src/partest/scala/tools/partest/nest/TestFile.scala index 9bfb4a992a..a00b94eba9 100644 --- a/src/partest/scala/tools/partest/nest/TestFile.scala +++ b/src/partest/scala/tools/partest/nest/TestFile.scala @@ -24,13 +24,18 @@ abstract class TestFile(kind: String) { def setOutDirTo = objectDir - def defineSettings(settings: Settings, setOutDir: Boolean) = { + def defineSettings(settings: Settings, setOutDir: Boolean): Boolean = { settings.classpath append dir.path if (setOutDir) settings.outdir.value = setOutDirTo.path - flags foreach (settings processArgumentString _) + // have to catch bad flags somewhere + flags foreach { f => + if (!settings.processArgumentString(f)._1) + return false + } settings.classpath append fileManager.CLASSPATH + true } override def toString(): String = "%s %s".format(kind, file) @@ -49,10 +54,12 @@ case class ScalapTestFile(file: JFile, fileManager: FileManager) extends TestFil override def setOutDirTo = file.parent } case class SpecializedTestFile(file: JFile, fileManager: FileManager) extends TestFile("specialized") { - override def defineSettings(settings: Settings, setOutDir: Boolean) = { - super.defineSettings(settings, setOutDir) - // add the instrumented library version to classpath - settings.classpath.value = ClassPath.join(PathSettings.srcSpecLib.toString, settings.classpath.value) + override def defineSettings(settings: Settings, setOutDir: Boolean): Boolean = { + super.defineSettings(settings, setOutDir) && { + // add the instrumented library version to classpath + settings.classpath prepend PathSettings.srcSpecLib.toString + true + } } } case class PresentationTestFile(file: JFile, fileManager: FileManager) extends TestFile("presentation") |