diff options
Diffstat (limited to 'src/compiler')
206 files changed, 960 insertions, 990 deletions
diff --git a/src/compiler/scala/tools/ant/FastScalac.scala b/src/compiler/scala/tools/ant/FastScalac.scala index 1badd3047b..8c8363a321 100644 --- a/src/compiler/scala/tools/ant/FastScalac.scala +++ b/src/compiler/scala/tools/ant/FastScalac.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.ant diff --git a/src/compiler/scala/tools/ant/Same.scala b/src/compiler/scala/tools/ant/Same.scala index d5cba4a0bf..4f7173e68b 100644 --- a/src/compiler/scala/tools/ant/Same.scala +++ b/src/compiler/scala/tools/ant/Same.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.ant diff --git a/src/compiler/scala/tools/ant/ScalaBazaar.scala b/src/compiler/scala/tools/ant/ScalaBazaar.scala index f560883a2d..1c1b0ccb46 100644 --- a/src/compiler/scala/tools/ant/ScalaBazaar.scala +++ b/src/compiler/scala/tools/ant/ScalaBazaar.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.ant { diff --git a/src/compiler/scala/tools/ant/ScalaTool.scala b/src/compiler/scala/tools/ant/ScalaTool.scala index 90f1fcaeda..db53224b4f 100644 --- a/src/compiler/scala/tools/ant/ScalaTool.scala +++ b/src/compiler/scala/tools/ant/ScalaTool.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.ant diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala index 4ecfc3dc85..6cda588419 100644 --- a/src/compiler/scala/tools/ant/Scalac.scala +++ b/src/compiler/scala/tools/ant/Scalac.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.ant diff --git a/src/compiler/scala/tools/ant/Scaladoc.scala b/src/compiler/scala/tools/ant/Scaladoc.scala index 03dc99be68..3d96b959f5 100644 --- a/src/compiler/scala/tools/ant/Scaladoc.scala +++ b/src/compiler/scala/tools/ant/Scaladoc.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.ant diff --git a/src/compiler/scala/tools/ant/sabbus/Break.scala b/src/compiler/scala/tools/ant/sabbus/Break.scala index e6c89dccf7..95bc5cc14e 100644 --- a/src/compiler/scala/tools/ant/sabbus/Break.scala +++ b/src/compiler/scala/tools/ant/sabbus/Break.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.ant.sabbus diff --git a/src/compiler/scala/tools/ant/sabbus/CompilationFailure.scala b/src/compiler/scala/tools/ant/sabbus/CompilationFailure.scala index 618350d91f..94e2ceffd2 100644 --- a/src/compiler/scala/tools/ant/sabbus/CompilationFailure.scala +++ b/src/compiler/scala/tools/ant/sabbus/CompilationFailure.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.ant.sabbus diff --git a/src/compiler/scala/tools/ant/sabbus/Compiler.scala b/src/compiler/scala/tools/ant/sabbus/Compiler.scala index 2daf664b2e..6d8473ef7d 100644 --- a/src/compiler/scala/tools/ant/sabbus/Compiler.scala +++ b/src/compiler/scala/tools/ant/sabbus/Compiler.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.ant.sabbus diff --git a/src/compiler/scala/tools/ant/sabbus/Compilers.scala b/src/compiler/scala/tools/ant/sabbus/Compilers.scala index 6f6986a118..91a8580475 100644 --- a/src/compiler/scala/tools/ant/sabbus/Compilers.scala +++ b/src/compiler/scala/tools/ant/sabbus/Compilers.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.ant.sabbus diff --git a/src/compiler/scala/tools/ant/sabbus/ForeignCompiler.scala b/src/compiler/scala/tools/ant/sabbus/ForeignCompiler.scala index 2263196af4..697ec44bd0 100644 --- a/src/compiler/scala/tools/ant/sabbus/ForeignCompiler.scala +++ b/src/compiler/scala/tools/ant/sabbus/ForeignCompiler.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.ant.sabbus diff --git a/src/compiler/scala/tools/ant/sabbus/Make.scala b/src/compiler/scala/tools/ant/sabbus/Make.scala index d1579670ac..9173745472 100644 --- a/src/compiler/scala/tools/ant/sabbus/Make.scala +++ b/src/compiler/scala/tools/ant/sabbus/Make.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.ant.sabbus diff --git a/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala b/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala index 353499ddb3..689df48a88 100644 --- a/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala +++ b/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.ant package sabbus diff --git a/src/compiler/scala/tools/ant/sabbus/Settings.scala b/src/compiler/scala/tools/ant/sabbus/Settings.scala index 2719196095..2304c31a0b 100644 --- a/src/compiler/scala/tools/ant/sabbus/Settings.scala +++ b/src/compiler/scala/tools/ant/sabbus/Settings.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.ant.sabbus diff --git a/src/compiler/scala/tools/ant/sabbus/TaskArgs.scala b/src/compiler/scala/tools/ant/sabbus/TaskArgs.scala index 20a6791648..977bfee3d4 100644 --- a/src/compiler/scala/tools/ant/sabbus/TaskArgs.scala +++ b/src/compiler/scala/tools/ant/sabbus/TaskArgs.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.ant.sabbus diff --git a/src/compiler/scala/tools/ant/sabbus/Use.scala b/src/compiler/scala/tools/ant/sabbus/Use.scala index fa17c48b63..a466d7b18a 100644 --- a/src/compiler/scala/tools/ant/sabbus/Use.scala +++ b/src/compiler/scala/tools/ant/sabbus/Use.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.ant.sabbus diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index fb62c7d46c..a9300ff304 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -2,13 +2,11 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc -import scala.tools.nsc.util.{FreshNameCreator,OffsetPosition,Position,NoPosition,SourceFile} -import scala.tools.nsc.io.AbstractFile -import scala.collection.mutable.{LinkedHashSet, HashSet, HashMap, ListBuffer} +import util.{ FreshNameCreator,Position,NoPosition,SourceFile } +import scala.collection.mutable.{ LinkedHashSet, HashSet, HashMap, ListBuffer } trait CompilationUnits { self: Global => diff --git a/src/compiler/scala/tools/nsc/CompileClient.scala b/src/compiler/scala/tools/nsc/CompileClient.scala index b672a616c3..c3307cba77 100644 --- a/src/compiler/scala/tools/nsc/CompileClient.scala +++ b/src/compiler/scala/tools/nsc/CompileClient.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/CompileServer.scala b/src/compiler/scala/tools/nsc/CompileServer.scala index c4f9b1d9f1..832f1e5aef 100644 --- a/src/compiler/scala/tools/nsc/CompileServer.scala +++ b/src/compiler/scala/tools/nsc/CompileServer.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/CompileSocket.scala b/src/compiler/scala/tools/nsc/CompileSocket.scala index d4697b69e6..d57016c4e9 100644 --- a/src/compiler/scala/tools/nsc/CompileSocket.scala +++ b/src/compiler/scala/tools/nsc/CompileSocket.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/CompilerCommand.scala b/src/compiler/scala/tools/nsc/CompilerCommand.scala index c8c7482811..54ef6bb8be 100644 --- a/src/compiler/scala/tools/nsc/CompilerCommand.scala +++ b/src/compiler/scala/tools/nsc/CompilerCommand.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/CompilerRun.scala b/src/compiler/scala/tools/nsc/CompilerRun.scala index 63ed4382af..9cac12d896 100644 --- a/src/compiler/scala/tools/nsc/CompilerRun.scala +++ b/src/compiler/scala/tools/nsc/CompilerRun.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/ConsoleWriter.scala b/src/compiler/scala/tools/nsc/ConsoleWriter.scala index 95adc47fb8..3c7d10767c 100644 --- a/src/compiler/scala/tools/nsc/ConsoleWriter.scala +++ b/src/compiler/scala/tools/nsc/ConsoleWriter.scala @@ -2,7 +2,6 @@ * Copyright 2006-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/EvalLoop.scala b/src/compiler/scala/tools/nsc/EvalLoop.scala index 388bcf8ccc..d8aa7799cb 100644 --- a/src/compiler/scala/tools/nsc/EvalLoop.scala +++ b/src/compiler/scala/tools/nsc/EvalLoop.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/FatalError.scala b/src/compiler/scala/tools/nsc/FatalError.scala index f9a801e611..145eb4c9ee 100644 --- a/src/compiler/scala/tools/nsc/FatalError.scala +++ b/src/compiler/scala/tools/nsc/FatalError.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala index f3ac556d4f..c088bb9303 100644 --- a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala +++ b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala @@ -3,7 +3,6 @@ * @author Lex Spoon */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala index 6697146a5a..5d272b06ae 100644 --- a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala +++ b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala @@ -3,7 +3,6 @@ * @author Lex Spoon */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 0ec36cf9ab..7efd8ad2a0 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc @@ -12,7 +11,7 @@ import compat.Platform.currentTime import io.{ SourceReader, AbstractFile, Path } import reporters.{ Reporter, ConsoleReporter } -import util.{ ClassPath, SourceFile, Statistics, BatchSourceFile } +import util.{ ClassPath, SourceFile, Statistics, BatchSourceFile, ScriptSourceFile, returning } import collection.mutable.{ HashSet, HashMap, ListBuffer } import reflect.generic.{ PickleBuffer } @@ -220,8 +219,13 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable if (settings.verbose.value || settings.Ylogcp.value) inform("[Classpath = " + classPath.asClasspathString + "]") + /** True if -Xscript has been set, indicating a script run. + */ + def isScriptRun = settings.script.value != "" + def getSourceFile(f: AbstractFile): BatchSourceFile = - new BatchSourceFile(f, reader.read(f)) + if (isScriptRun) ScriptSourceFile(f, reader read f) + else new BatchSourceFile(f, reader read f) def getSourceFile(name: String): SourceFile = { val f = AbstractFile.getFile(name) @@ -796,21 +800,15 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable /** Compile list of abstract files */ def compileFiles(files: List[AbstractFile]) { - try { - compileSources(files map getSourceFile) - } catch { - case ex: IOException => error(ex.getMessage()) - } + try compileSources(files map getSourceFile) + catch { case ex: IOException => error(ex.getMessage()) } } /** Compile list of files given by their names */ def compile(filenames: List[String]) { - val scriptMain = settings.script.value - def sources: List[SourceFile] = scriptMain match { - case "" => filenames map getSourceFile - case main if filenames.length == 1 => List(ScriptRunner.wrappedScript(main, filenames.head, getSourceFile)) - case _ => error("can only compile one script at a time") ; Nil - } + val sources: List[SourceFile] = + if (isScriptRun && filenames.size > 1) returning(Nil)(_ => error("can only compile one script at a time")) + else filenames map getSourceFile try compileSources(sources) catch { case ex: IOException => error(ex.getMessage()) } diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala index 556a3107cd..128c378e23 100644 --- a/src/compiler/scala/tools/nsc/Interpreter.scala +++ b/src/compiler/scala/tools/nsc/Interpreter.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc @@ -27,7 +26,7 @@ import scala.util.control.Exception.{ Catcher, catching, ultimately, unwrapping import io.{ PlainFile, VirtualDirectory } import reporters.{ ConsoleReporter, Reporter } import symtab.{ Flags, Names } -import util.{ SourceFile, BatchSourceFile, ClassPath, Chars } +import util.{ SourceFile, BatchSourceFile, ScriptSourceFile, ClassPath, Chars, stringFromWriter } import scala.reflect.NameTransformer import scala.tools.nsc.{ InterpreterResults => IR } import interpreter._ @@ -76,6 +75,11 @@ import Interpreter._ class Interpreter(val settings: Settings, out: PrintWriter) { repl => + def println(x: Any) = { + out.println(x) + out.flush() + } + /** construct an interpreter that reports to Console */ def this(settings: Settings) = this(settings, new NewLinePrintWriter(new ConsoleWriter, true)) def this() = this(new Settings()) @@ -109,28 +113,37 @@ class Interpreter(val settings: Settings, out: PrintWriter) { |} |""".stripMargin - val run = new _compiler.Run() - run compileSources List(new BatchSourceFile("<init>", source)) - if (settings.debug.value) { - out println "Repl compiler initialized." - out.flush() + try { + new _compiler.Run() compileSources List(new BatchSourceFile("<init>", source)) + if (isReplDebug || settings.debug.value) + println("Repl compiler initialized.") + true + } + catch { + case MissingRequirementError(msg) => println(""" + |Failed to initialize compiler: %s not found. + |** Note that as of 2.8 scala does not assume use of the java classpath. + |** For the old behavior pass -usejavacp to scala, or if using a Settings + |** object programatically, settings.usejavacp.value = true.""".stripMargin.format(msg) + ) + false } - true } // set up initialization future - private var _isInitialized: () => Boolean = () => false + private var _isInitialized: () => Boolean = null def initialize() = synchronized { - if (!_isInitialized()) + if (_isInitialized == null) _isInitialized = scala.concurrent.ops future _initialize() } /** the public, go through the future compiler */ lazy val compiler: Global = { initialize() - _isInitialized() // blocks until it is - _compiler + // blocks until it is ; false means catastrophic failure + if (_isInitialized()) _compiler + else null } import compiler.{ Traverser, CompilationUnit, Symbol, Name, Type } @@ -174,16 +187,6 @@ class Interpreter(val settings: Settings, out: PrintWriter) { /** interpreter settings */ lazy val isettings = new InterpreterSettings(this) - /** Heuristically strip interpreter wrapper prefixes - * from an interpreter output string. - */ - def stripWrapperGunk(str: String): String = - if (isettings.unwrapStrings) { - val wrapregex = """(line[0-9]+\$object[$.])?(\$iw[$.])*""" - str.replaceAll(wrapregex, "") - } - else str - /** Instantiate a compiler. Subclasses can override this to * change the compiler class used by this interpreter. */ protected def newCompiler(settings: Settings, reporter: Reporter) = { @@ -237,6 +240,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { private val usedNameMap = new HashMap[Name, Request]() private val boundNameMap = new HashMap[Name, Request]() private def allHandlers = prevRequests.toList flatMap (_.handlers) + private def allReqAndHandlers = prevRequests.toList flatMap (req => req.handlers map (req -> _)) def printAllTypeOf = { prevRequests foreach { req => @@ -322,15 +326,6 @@ class Interpreter(val settings: Settings, out: PrintWriter) { def getVarName = varNameCreator() def getSynthVarName = synthVarNameCreator() - /** generate a string using a routine that wants to write on a stream */ - private def stringFrom(writer: PrintWriter => Unit): String = { - val stringWriter = new StringWriter() - val stream = new NewLinePrintWriter(stringWriter) - writer(stream) - stream.close - stringWriter.toString - } - /** Truncate a string if it is longer than isettings.maxPrintString */ private def truncPrintString(str: String): String = { val maxpr = isettings.maxPrintString @@ -341,7 +336,10 @@ class Interpreter(val settings: Settings, out: PrintWriter) { } /** Clean up a string for output */ - private def clean(str: String) = truncPrintString(stripWrapperGunk(str)) + private def clean(str: String) = truncPrintString( + if (isettings.unwrapStrings) stripWrapperGunk(str) + else str + ) /** Indent some code by the width of the scala> prompt. * This way, compiler error messages read better. @@ -350,7 +348,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { def indentCode(code: String) = { /** Heuristic to avoid indenting and thereby corrupting """-strings and XML literals. */ val noIndent = (code contains "\n") && (List("\"\"\"", "</", "/>") exists (code contains _)) - stringFrom(str => + stringFromWriter(str => for (line <- code.lines) { if (!noIndent) str.print(spaces) @@ -419,10 +417,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { } /** Flatten the handlers out and pair each with the original request */ - val rhpairs = prevRequests.reverse.toList flatMap { req => - req.handlers map (ReqAndHandler(req, _)) - } - select(rhpairs, wanted).reverse + select(allReqAndHandlers reverseMap { case (r, h) => ReqAndHandler(r, h) }, wanted).reverse } val code, trailingBraces, accessPath = new StringBuffer @@ -579,26 +574,28 @@ class Interpreter(val settings: Settings, out: PrintWriter) { */ def interpret(line: String): IR.Result = interpret(line, false) def interpret(line: String, synthetic: Boolean): IR.Result = { - val req = requestFromLine(line, synthetic) match { - case Left(result) => return result - case Right(req) => req - } - // null indicates a disallowed statement type; otherwise compile and - // fail if false (implying e.g. a type error) - if (req == null || !req.compile) - return IR.Error + def loadAndRunReq(req: Request) = { + val (result, succeeded) = req.loadAndRun + if (printResults || !succeeded) + out print clean(result) - val (result, succeeded) = req.loadAndRun - if (printResults || !succeeded) - out print clean(result) + // book-keeping + if (succeeded && !synthetic) + recordRequest(req) - if (succeeded) { - if (!synthetic) - recordRequest(req) // book-keeping + if (succeeded) IR.Success + else IR.Error + } - IR.Success + if (compiler == null) IR.Error + else requestFromLine(line, synthetic) match { + case Left(result) => result + case Right(req) => + // null indicates a disallowed statement type; otherwise compile and + // fail if false (implying e.g. a type error) + if (req == null || !req.compile) IR.Error + else loadAndRunReq(req) } - else IR.Error } /** A name creator used for objects created by <code>bind()</code>. */ @@ -682,7 +679,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { def extraCodeToEvaluate(req: Request, code: PrintWriter) { } def resultExtractionCode(req: Request, code: PrintWriter) { } - override def toString = "%s(usedNames = %s)".format(this.getClass, usedNames) + override def toString = "%s(used = %s)".format(this.getClass.toString split '.' last, usedNames) } private class GenericHandler(member: Tree) extends MemberHandler(member) @@ -840,7 +837,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { def toCompute = line /** generate the source code for the object that computes this request */ - def objectSourceCode: String = stringFrom { code => + def objectSourceCode: String = stringFromWriter { code => val preamble = """ |object %s { | %s%s @@ -854,7 +851,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { /** generate source code for the object that retrieves the result from objectSourceCode */ - def resultObjectSourceCode: String = stringFrom { code => + def resultObjectSourceCode: String = stringFromWriter { code => /** We only want to generate this code when the result * is a value which can be referred to as-is. */ @@ -975,7 +972,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { case t: Throwable if bindLastException => withoutBindingLastException { quietBind("lastException", "java.lang.Throwable", t) - (stringFrom(t.printStackTrace(_)), false) + (stringFromWriter(t.printStackTrace(_)), false) } } @@ -985,6 +982,8 @@ class Interpreter(val settings: Settings, out: PrintWriter) { } } } + + override def toString = "Request(line=%s, %s trees)".format(line, trees.size) } /** A container class for methods to be injected into the repl diff --git a/src/compiler/scala/tools/nsc/InterpreterCommand.scala b/src/compiler/scala/tools/nsc/InterpreterCommand.scala index 45e139194e..0ac2ef9617 100644 --- a/src/compiler/scala/tools/nsc/InterpreterCommand.scala +++ b/src/compiler/scala/tools/nsc/InterpreterCommand.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/InterpreterLoop.scala b/src/compiler/scala/tools/nsc/InterpreterLoop.scala index 4e8a04de44..f68ce4a5b4 100644 --- a/src/compiler/scala/tools/nsc/InterpreterLoop.scala +++ b/src/compiler/scala/tools/nsc/InterpreterLoop.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Alexander Spoon */ -// $Id$ package scala.tools.nsc @@ -246,31 +245,18 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite case _ => true } - // this is about the illusion of snappiness. We call initialize() - // which spins off a separate thread, then print the prompt and try - // our best to look ready. Ideally the user will spend a - // couple seconds saying "wow, it starts so fast!" and by the time - // they type a command the compiler is ready to roll. - interpreter.initialize() - while (processLine(readOneLine)) { } } /** interpret all lines from a specified file */ - def interpretAllFrom(filename: String) { - val fileIn = File(filename) - if (!fileIn.exists) - return out.println("Error opening file: " + filename) - + def interpretAllFrom(file: File) { val oldIn = in val oldReplay = replayCommandStack - try { - fileIn applyReader { reader => - in = new SimpleReader(reader, out, false) - plushln("Loading " + filename + "...") - repl - } + try file applyReader { reader => + in = new SimpleReader(reader, out, false) + plushln("Loading " + file + "...") + repl() } finally { in = oldIn @@ -303,8 +289,10 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite List(("stdout", p.stdout), ("stderr", p.stderr)) foreach (add _).tupled } - def withFile(filename: String)(action: String => Unit) { - if (File(filename).exists) action(filename) + def withFile(filename: String)(action: File => Unit) { + val f = File(filename) + + if (f.exists) action(f) else out.println("That file does not exist") } @@ -367,10 +355,13 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite def ambiguous(cmds: List[Command]) = "Ambiguous: did you mean " + cmds.map(":" + _.name).mkString(" or ") + "?" // not a command - if (!line.startsWith(":")) - return Result(true, interpretStartingWith(line)) + if (!line.startsWith(":")) { + // Notice failure to create compiler + if (interpreter.compiler == null) return Result(false, None) + else return Result(true, interpretStartingWith(line)) + } - val tokens = line.substring(1).split("""\s+""").toList + val tokens = (line drop 1 split """\s+""").toList if (tokens.isEmpty) return withError(ambiguous(commands)) @@ -477,20 +468,25 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite // signal completion non-completion input has been received in.completion foreach (_.resetVerbosity()) - def reallyInterpret = { - interpreter.interpret(code) match { - case IR.Error => None - case IR.Success => Some(code) - case IR.Incomplete => - if (in.interactive && code.endsWith("\n\n")) { - out.println("You typed two blank lines. Starting a new command.") + def reallyInterpret = interpreter.interpret(code) match { + case IR.Error => None + case IR.Success => Some(code) + case IR.Incomplete => + if (in.interactive && code.endsWith("\n\n")) { + out.println("You typed two blank lines. Starting a new command.") + None + } + else in.readLine(CONTINUATION_STRING) match { + case null => + // we know compilation is going to fail since we're at EOF and the + // parser thinks the input is still incomplete, but since this is + // a file being read non-interactively we want to fail. So we send + // it straight to the compiler for the nice error message. + interpreter.compileString(code) None - } - else in.readLine(CONTINUATION_STRING) match { - case null => None // end of file - case line => interpretStartingWith(code + "\n" + line) - } - } + + case line => interpretStartingWith(code + "\n" + line) + } } /** Here we place ourselves between the user and the interpreter and examine @@ -552,8 +548,16 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite if (interpreter.reporter.hasErrors) return printWelcome() + + // this is about the illusion of snappiness. We call initialize() + // which spins off a separate thread, then print the prompt and try + // our best to look ready. Ideally the user will spend a + // couple seconds saying "wow, it starts so fast!" and by the time + // they type a command the compiler is ready to roll. + interpreter.initialize() repl() - } finally closeInterpreter() + } + finally closeInterpreter() } private def objClass(x: Any) = x.asInstanceOf[AnyRef].getClass diff --git a/src/compiler/scala/tools/nsc/InterpreterResults.scala b/src/compiler/scala/tools/nsc/InterpreterResults.scala index 76657a2125..fad3fb653f 100644 --- a/src/compiler/scala/tools/nsc/InterpreterResults.scala +++ b/src/compiler/scala/tools/nsc/InterpreterResults.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/InterpreterSettings.scala b/src/compiler/scala/tools/nsc/InterpreterSettings.scala index a5e1c1e729..b53a6f6955 100644 --- a/src/compiler/scala/tools/nsc/InterpreterSettings.scala +++ b/src/compiler/scala/tools/nsc/InterpreterSettings.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Alexander Spoon */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/Main.scala b/src/compiler/scala/tools/nsc/Main.scala index eaa2970dda..948c5f6fb8 100644 --- a/src/compiler/scala/tools/nsc/Main.scala +++ b/src/compiler/scala/tools/nsc/Main.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/MainGenericRunner.scala b/src/compiler/scala/tools/nsc/MainGenericRunner.scala index fdc5fe82dd..936ee3c1db 100644 --- a/src/compiler/scala/tools/nsc/MainGenericRunner.scala +++ b/src/compiler/scala/tools/nsc/MainGenericRunner.scala @@ -3,7 +3,6 @@ * @author Lex Spoon */ -// $Id$ package scala.tools.nsc @@ -39,14 +38,23 @@ object MainGenericRunner { else if (settings.version.value) return errorFn("Scala code runner %s -- %s".format(versionString, copyrightString)) else if (command.shouldStopWithInfo) return errorFn(command getInfoMessage sampleCompiler) + def isE = !settings.execute.isDefault def dashe = settings.execute.value + + def isI = !settings.loadfiles.isDefault def dashi = settings.loadfiles.value - def slurp = dashi map (file => File(file).slurp()) mkString "\n" + + def combinedCode = { + val files = if (isI) dashi map (file => File(file).slurp()) else Nil + val str = if (isE) List(dashe) else Nil + + files ++ str mkString "\n\n" + } val classpath: List[URL] = new PathResolver(settings) asURLs /** Was code given in a -e argument? */ - if (!settings.execute.isDefault) { + 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 @@ -55,11 +63,8 @@ object MainGenericRunner { * This all needs a rewrite though. */ val fullArgs = command.thingToRun.toList ::: command.arguments - val code = - if (settings.loadfiles.isDefault) dashe - else slurp + "\n" + dashe - exitCond(ScriptRunner.runCommand(settings, code, fullArgs)) + exitCond(ScriptRunner.runCommand(settings, combinedCode, fullArgs)) } else command.thingToRun match { case None => diff --git a/src/compiler/scala/tools/nsc/MainInterpreter.scala b/src/compiler/scala/tools/nsc/MainInterpreter.scala index 568705aff1..0a0d1e4a33 100644 --- a/src/compiler/scala/tools/nsc/MainInterpreter.scala +++ b/src/compiler/scala/tools/nsc/MainInterpreter.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Lex Spoon */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/MainTokenMetric.scala b/src/compiler/scala/tools/nsc/MainTokenMetric.scala index 9c123922d6..fc0ea67051 100644 --- a/src/compiler/scala/tools/nsc/MainTokenMetric.scala +++ b/src/compiler/scala/tools/nsc/MainTokenMetric.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/NewLinePrintWriter.scala b/src/compiler/scala/tools/nsc/NewLinePrintWriter.scala index ecb436d8a9..4ced491a8d 100644 --- a/src/compiler/scala/tools/nsc/NewLinePrintWriter.scala +++ b/src/compiler/scala/tools/nsc/NewLinePrintWriter.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc import java.io.{Writer, PrintWriter} diff --git a/src/compiler/scala/tools/nsc/NoPhase.scala b/src/compiler/scala/tools/nsc/NoPhase.scala index a6907ddf58..8f5e3e440c 100644 --- a/src/compiler/scala/tools/nsc/NoPhase.scala +++ b/src/compiler/scala/tools/nsc/NoPhase.scala @@ -2,7 +2,6 @@ * Copyright 2007-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/ObjectRunner.scala b/src/compiler/scala/tools/nsc/ObjectRunner.scala index 210f9a1785..f2ddc84445 100644 --- a/src/compiler/scala/tools/nsc/ObjectRunner.scala +++ b/src/compiler/scala/tools/nsc/ObjectRunner.scala @@ -3,7 +3,6 @@ * @author Lex Spoon */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala b/src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala index b011f88f2b..ae56941633 100644 --- a/src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala +++ b/src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/Phase.scala b/src/compiler/scala/tools/nsc/Phase.scala index 98f0f840ff..882b96d84d 100644 --- a/src/compiler/scala/tools/nsc/Phase.scala +++ b/src/compiler/scala/tools/nsc/Phase.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/PhaseAssembly.scala b/src/compiler/scala/tools/nsc/PhaseAssembly.scala index b3300a1ff9..e0cc91cb80 100644 --- a/src/compiler/scala/tools/nsc/PhaseAssembly.scala +++ b/src/compiler/scala/tools/nsc/PhaseAssembly.scala @@ -3,7 +3,6 @@ * @author Anders Bach Nielsen * @version 1.0 */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/Properties.scala b/src/compiler/scala/tools/nsc/Properties.scala index 4601a1ca64..4d488e65cf 100644 --- a/src/compiler/scala/tools/nsc/Properties.scala +++ b/src/compiler/scala/tools/nsc/Properties.scala @@ -3,7 +3,6 @@ * @author Stephane Micheloud */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/ScalaDoc.scala b/src/compiler/scala/tools/nsc/ScalaDoc.scala index b7e416e121..b539b800b3 100644 --- a/src/compiler/scala/tools/nsc/ScalaDoc.scala +++ b/src/compiler/scala/tools/nsc/ScalaDoc.scala @@ -3,7 +3,6 @@ * @author Martin Odersky * @author Geoffrey Washburn */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala index a096efb749..a7d67a3af9 100644 --- a/src/compiler/scala/tools/nsc/ScriptRunner.scala +++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc @@ -17,11 +16,9 @@ import io.{ Directory, File, Path, PlainFile } import java.lang.reflect.InvocationTargetException import java.net.URL import java.util.jar.{ JarEntry, JarOutputStream } -import java.util.regex.Pattern import scala.tools.util.PathResolver import scala.tools.nsc.reporters.{Reporter,ConsoleReporter} -import scala.tools.nsc.util.{ClassPath, CompoundSourceFile, BatchSourceFile, SourceFile, SourceFileFragment} /** An object that runs Scala code in script files. * @@ -49,8 +46,7 @@ import scala.tools.nsc.util.{ClassPath, CompoundSourceFile, BatchSourceFile, Sou * @todo It would be better if error output went to stderr instead * of stdout... */ -object ScriptRunner -{ +object ScriptRunner { /* While I'm chasing down the fsc and script bugs. */ def DBG(msg: Any) { System.err.println(msg.toString) @@ -69,6 +65,8 @@ object ScriptRunner case x => x } + 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 = @@ -119,22 +117,6 @@ object ScriptRunner /** Read the entire contents of a file as a String. */ private def contentsOfFile(filename: String) = File(filename).slurp() - /** Find the length of the header in the specified file, if - * there is one. The header part starts with "#!" or "::#!" - * and ends with a line that begins with "!#" or "::!#". - */ - private def headerLength(filename: String): Int = { - val headerPattern = Pattern.compile("""^(::)?!#.*(\r|\n|\r\n)""", Pattern.MULTILINE) - val fileContents = contentsOfFile(filename) - def isValid = List("#!", "::#!") exists (fileContents startsWith _) - - if (!isValid) 0 else { - val matcher = headerPattern matcher fileContents - if (matcher.find) matcher.end - else throw new IOException("script file does not close its header with !# or ::!#") - } - } - /** Split a fully qualified object name into a * package and an unqualified object name */ private def splitObjectName(fullname: String): (Option[String], String) = @@ -143,48 +125,6 @@ object ScriptRunner case idx => (Some(fullname take idx), fullname drop (idx + 1)) } - /** Code that is added to the beginning of a script file to make - * it a complete Scala compilation unit. - */ - protected def preambleCode(objectName: String): String = { - val (maybePack, objName) = splitObjectName(objectName) - val packageDecl = maybePack map ("package %s\n" format _) getOrElse ("") - - return """| - | object %s { - | def main(argv: Array[String]): Unit = { - | val args = argv - | new AnyRef { - |""".stripMargin.format(objName) - } - - /** Code that is added to the end of a script file to make - * it a complete Scala compilation unit. - */ - val endCode = """ - | } - | } - | } - |""".stripMargin - - /** Wrap a script file into a runnable object named - * <code>scala.scripting.Main</code>. - */ - def wrappedScript( - objectName: String, - filename: String, - getSourceFile: PlainFile => BatchSourceFile): SourceFile = - { - val preamble = new BatchSourceFile("<script preamble>", preambleCode(objectName).toCharArray) - val middle = { - val bsf = getSourceFile(PlainFile fromPath filename) - new SourceFileFragment(bsf, headerLength(filename), bsf.length) - } - val end = new BatchSourceFile("<script trailer>", endCode.toCharArray) - - new CompoundSourceFile(preamble, middle, end) - } - /** Compile a script using the fsc compilation daemon. * * @param settings ... @@ -243,12 +183,15 @@ object ScriptRunner settings.outdir.value = compiledPath.path if (settings.nocompdaemon.value) { + /** Setting settings.script.value informs the compiler this is not a + * self contained compilation unit. + */ + settings.script.value = scriptMain(settings) val reporter = new ConsoleReporter(settings) val compiler = newGlobal(settings, reporter) val cr = new compiler.Run - val wrapped = wrappedScript(scriptMain(settings), scriptFile, compiler getSourceFile _) - cr compileSources List(wrapped) + cr compile List(scriptFile) if (reporter.hasErrors) None else Some(compiledPath) } else if (compileWithDaemon(settings, scriptFile)) Some(compiledPath) @@ -295,10 +238,7 @@ object ScriptRunner val classpath = pr.asURLs :+ File(compiledLocation).toURL try { - ObjectRunner.run( - classpath, - scriptMain(settings), - scriptArgs) + ObjectRunner.run(classpath, scriptMain(settings), scriptArgs) true } catch { diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala index cd4626c0c6..8765ad3686 100644 --- a/src/compiler/scala/tools/nsc/Settings.scala +++ b/src/compiler/scala/tools/nsc/Settings.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/SubComponent.scala b/src/compiler/scala/tools/nsc/SubComponent.scala index 425f5e4aff..445021f22a 100644 --- a/src/compiler/scala/tools/nsc/SubComponent.scala +++ b/src/compiler/scala/tools/nsc/SubComponent.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala index ddf4fb0a23..48c2536324 100755 --- a/src/compiler/scala/tools/nsc/ast/DocComments.scala +++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id: Unapplies.scala 19206 2009-10-21 20:57:27Z extempore $ package scala.tools.nsc package ast diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala index ccab6423cf..111bf48a45 100644 --- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package ast diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala index e5a49f8358..0555f6c035 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package ast diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala index fd13958053..34d3423401 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala @@ -7,6 +7,8 @@ package scala.tools.nsc package ast +import PartialFunction._ + /** A DSL for generating scala code. The goal is that the * code generating code should look a lot like the code it * generates. @@ -18,22 +20,20 @@ trait TreeDSL { import global._ import definitions._ import gen.{ scalaDot } - import PartialFunction._ object CODE { // Add a null check to a Tree => Tree function def nullSafe[T](f: Tree => Tree, ifNull: Tree): Tree => Tree = tree => IF (tree MEMBER_== NULL) THEN ifNull ELSE f(tree) - // Applies a function to a value and then returns the value. - def returning[T](f: T => Unit)(x: T): T = { f(x) ; x } - // strip bindings to find what lies beneath final def unbind(x: Tree): Tree = x match { case Bind(_, y) => unbind(y) case y => y } + def returning[T](x: T)(f: T => Unit): T = util.returning(x)(f) + object LIT extends (Any => Literal) { def apply(x: Any) = Literal(Constant(x)) def unapply(x: Any) = condOpt(x) { case Literal(Constant(value)) => value } @@ -93,6 +93,7 @@ trait TreeDSL { def INT_| (other: Tree) = fn(target, getMember(IntClass, nme.OR), other) def INT_& (other: Tree) = fn(target, getMember(IntClass, nme.AND), other) + def INT_>= (other: Tree) = fn(target, getMember(IntClass, nme.GE), other) def INT_== (other: Tree) = fn(target, getMember(IntClass, nme.EQ), other) def INT_!= (other: Tree) = fn(target, getMember(IntClass, nme.NE), other) diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index cc3581c3f8..1327781d31 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package ast diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala index 430967298c..f21b1b20ff 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package ast diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala index cb899a2560..ddc1c3169a 100644 --- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package ast diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index b40f286680..8db6958d07 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package ast diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala index e918489446..60df523d92 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Burak Emir */ -// $Id$ package scala.tools.nsc package ast.parser diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 43e515d31e..182ae6c21c 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ //todo: allow infix type patterns @@ -10,7 +9,7 @@ package scala.tools.nsc package ast.parser import scala.collection.mutable.ListBuffer -import scala.tools.nsc.util.{OffsetPosition, BatchSourceFile} +import util.{ OffsetPosition, BatchSourceFile } import symtab.Flags import Tokens._ @@ -64,6 +63,13 @@ self => def this(unit: global.CompilationUnit) = this(unit, List()) + /** The parse starting point depends on whether the source file is self-contained: + * if not, the AST will be supplemented. + */ + def parseStartRule = + if (unit.source.isSelfContained) () => compilationUnit() + else () => scriptBody() + val in = new UnitScanner(unit, patches) in.init() @@ -170,14 +176,66 @@ self => */ var classContextBounds: List[Tree] = Nil - /** this is the general parse method + def parseStartRule: () => Tree + + /** This is the general parse entry point. */ def parse(): Tree = { - val t = compilationUnit() + val t = parseStartRule() accept(EOF) t } + /** This is the parse entry point for code which is not self-contained, e.g. + * a script which is a series of template statements. They will be + * swaddled in Trees until the AST is equivalent to the one returned + * by compilationUnit(). + */ + def scriptBody(): Tree = { + val stmts = templateStatSeq(false)._2 + accept(EOF) + + /** Here we are building an AST representing the following source fiction, + * where <moduleName> is from -Xscript (defaults to "Main") and <stmts> are + * the result of parsing the script file. + * + * object <moduleName> { + * def main(argv: Array[String]): Unit = { + * val args = argv + * new AnyRef { + * <stmts> + * } + * } + * } + */ + import definitions._ + + def emptyPkg = atPos(0, 0, 0) { Ident(nme.EMPTY_PACKAGE_NAME) } + def emptyInit = DefDef( + NoMods, + nme.CONSTRUCTOR, + Nil, + List(Nil), + TypeTree(), + Block(List(Apply(Select(Super("", ""), nme.CONSTRUCTOR), Nil)), Literal(Constant(()))) + ) + + // def main + def mainParamType = AppliedTypeTree(Ident("Array".toTypeName), List(Ident("String".toTypeName))) + def mainParameter = List(ValDef(Modifiers(Flags.PARAM), "argv", mainParamType, EmptyTree)) + def mainSetArgv = List(ValDef(NoMods, "args", TypeTree(), Ident("argv"))) + def mainNew = makeNew(Nil, emptyValDef, stmts, List(Nil), NoPosition, NoPosition) + def mainDef = DefDef(NoMods, "main", Nil, List(mainParameter), scalaDot(nme.Unit.toTypeName), Block(mainSetArgv, mainNew)) + + // object Main + def moduleName = ScriptRunner scriptMain settings + def moduleBody = Template(List(scalaScalaObjectConstr), emptyValDef, List(emptyInit, mainDef)) + def moduleDef = ModuleDef(NoMods, moduleName, moduleBody) + + // package <empty> { ... } + makePackaging(0, emptyPkg, List(moduleDef)) + } + /* --------------- PLACEHOLDERS ------------------------------------------- */ /** The implicit parameters introduced by `_' in the current expression. @@ -1407,7 +1465,7 @@ self => else accept(LARROW) val rhs = expr() enums += makeGenerator(r2p(start, point, in.lastOffset), pat, tok == EQUALS, rhs) - if (in.token == IF) enums += makeFilter(in.offset, guard()) + while (in.token == IF) enums += makeFilter(in.offset, guard()) } def makeFilter(start: Int, tree: Tree) = Filter(r2p(start, tree.pos.point, tree.pos.endOrPoint), tree) @@ -1487,7 +1545,9 @@ self => def pattern3(seqOK: Boolean): Tree = { val base = opstack var top = simplePattern(seqOK) - if (seqOK && isIdent && in.name == STAR) + // See ticket #3189 for the motivation for the null check. + // TODO: dredge out the remnants of regexp patterns. + if (seqOK && isIdent && in.name == STAR && in.prev.name != null) return atPos(top.pos.startOrPoint, in.skipToken())(Star(stripParens(top))) while (isIdent && in.name != BAR) { @@ -1727,8 +1787,11 @@ self => mods = mods withPosition (in.token, tokenRange(in)) mods |= Flags.MUTABLE in.nextToken() - } else if (!caseParam) { - mods |= Flags.PRIVATE | Flags.LOCAL + } else { + if (mods.flags != Flags.PARAMACCESSOR) accept(VAL) + if (!caseParam) { + mods |= Flags.PRIVATE | Flags.LOCAL + } } if (caseParam) { mods |= Flags.CASEACCESSOR diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index eeb3fb6e7a..5e9cc3f46e 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package ast.parser diff --git a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala index 049c8aa2ff..86c79eb733 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Burak Emir */ -// $Id$ package scala.tools.nsc package ast.parser diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala index fb97587ec4..b3c3c7dfe9 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package ast.parser diff --git a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala index 2146fa0fe6..00347c3a9e 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package ast.parser diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index bea52b1153..9f20a70de5 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package ast.parser diff --git a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala index b95e3335ba..0af482912d 100644 --- a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala +++ b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend diff --git a/src/compiler/scala/tools/nsc/backend/WorklistAlgorithm.scala b/src/compiler/scala/tools/nsc/backend/WorklistAlgorithm.scala index 1cb5cfb051..27f5b27303 100644 --- a/src/compiler/scala/tools/nsc/backend/WorklistAlgorithm.scala +++ b/src/compiler/scala/tools/nsc/backend/WorklistAlgorithm.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala index e5afa84c82..bab3652f69 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend diff --git a/src/compiler/scala/tools/nsc/backend/icode/CheckerException.scala b/src/compiler/scala/tools/nsc/backend/icode/CheckerException.scala index 9d102eef28..a2ba0554da 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/CheckerException.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/CheckerException.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend diff --git a/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala b/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala index c34cefdc12..6067dc6e42 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend diff --git a/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala index 8168cc2c6e..e5b94076e8 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index b357dff25a..9136bffcda 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala index 0810a64f5d..dc90a438b9 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala @@ -7,7 +7,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend diff --git a/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala b/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala index d090454129..701e5d3815 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala index 82e99d50ac..95cd15711b 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala index c0255cda65..ed76e66aa0 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala b/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala index 826ecc18ec..8624bb5aff 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend diff --git a/src/compiler/scala/tools/nsc/backend/icode/Printers.scala b/src/compiler/scala/tools/nsc/backend/icode/Printers.scala index 0c81759c18..9aaeeb2e8b 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Printers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Printers.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend diff --git a/src/compiler/scala/tools/nsc/backend/icode/Repository.scala b/src/compiler/scala/tools/nsc/backend/icode/Repository.scala index 5d08b40557..78a47e129c 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Repository.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Repository.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala index 4b53a5e2ae..65a5291f36 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala index 6872f56c39..d334af525f 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/CompleteLattice.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/CompleteLattice.scala index 95f4418759..4efefe89f9 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CompleteLattice.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CompleteLattice.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend.icode.analysis diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala index 1fbbc10c3d..289fae6fe3 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend.icode.analysis diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala index df3dd1a060..39405cd84e 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend.icode.analysis diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala index 46771feeee..101bb81503 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend.icode.analysis diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/LubException.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/LubException.scala index 0474d12a8b..6cdee7ef4b 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/LubException.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/LubException.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend.icode.analysis diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/ProgramPoint.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/ProgramPoint.scala index e875ced036..a9a09a71a0 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/ProgramPoint.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/ProgramPoint.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend.icode.analysis diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala index 3aa0ddfdbf..f3dd6dd93b 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend.icode.analysis diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala index 858512c9b1..9b145c9fbc 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package backend.icode.analysis diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 2b4878a93b..21d1246cc4 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -3,7 +3,6 @@ * @author Iulian Dragos */ -// $Id$ package scala.tools.nsc package backend.jvm @@ -815,7 +814,10 @@ abstract class GenJVM extends SubComponent { import JAccessFlags._ val moduleName = javaName(module) // + "$" val mirrorName = moduleName.substring(0, moduleName.length() - 1) - val paramJavaTypes = m.info.paramTypes map toTypeKind + + val methodInfo = module.thisType.memberInfo(m) + + val paramJavaTypes = methodInfo.paramTypes map toTypeKind val paramNames: Array[String] = new Array[String](paramJavaTypes.length); for (i <- 0 until paramJavaTypes.length) @@ -823,7 +825,7 @@ abstract class GenJVM extends SubComponent { val mirrorMethod = jclass.addNewMethod(ACC_PUBLIC | ACC_FINAL | ACC_STATIC, javaName(m), - javaType(m.info.resultType), + javaType(methodInfo.resultType), javaTypes(paramJavaTypes), paramNames); val mirrorCode = mirrorMethod.getCode().asInstanceOf[JExtendedCode]; @@ -839,7 +841,7 @@ abstract class GenJVM extends SubComponent { i += 1 } - mirrorCode.emitINVOKEVIRTUAL(moduleName, mirrorMethod.getName(), mirrorMethod.getType().asInstanceOf[JMethodType]) + mirrorCode.emitINVOKEVIRTUAL(moduleName, mirrorMethod.getName(), javaType(m).asInstanceOf[JMethodType]) mirrorCode.emitRETURN(mirrorMethod.getReturnType()) addRemoteException(mirrorMethod, m) @@ -1701,7 +1703,7 @@ abstract class GenJVM extends SubComponent { def indexOf(local: Local): Int = { assert(local.index >= 0, - "Invalid index for: " + local + "{" + local.hashCode + "}: ") + "Invalid index for: " + local + "{" + local.## + "}: ") local.index } @@ -1716,7 +1718,7 @@ abstract class GenJVM extends SubComponent { for (l <- m.locals) { if (settings.debug.value) - log("Index value for " + l + "{" + l.hashCode + "}: " + idx) + log("Index value for " + l + "{" + l.## + "}: " + idx) l.index = idx idx += sizeOf(l.kind) } diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala index 554dcd4e6d..92ba50e88e 100644 --- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala +++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala @@ -3,7 +3,6 @@ * @author Nikolay Mihaylov */ -// $Id$ package scala.tools.nsc package backend.msil diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala index fedf0d4143..9470078507 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala @@ -3,7 +3,6 @@ * @author Iulian Dragos */ -// $Id$ package scala.tools.nsc package backend.opt; diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala index 29d0c37c84..e365b3bc08 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala @@ -3,7 +3,6 @@ * @author Iulian Dragos */ -// $Id$ package scala.tools.nsc package backend.opt diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index dc1ac8e844..9c1489a637 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -3,7 +3,6 @@ * @author Iulian Dragos */ -// $Id$ package scala.tools.nsc package backend.opt @@ -444,6 +443,15 @@ abstract class Inliners extends SubComponent { case Some(b) => callsNonPublic = b case None => + // Avoiding crashing the compiler if there are open blocks. + callee.code.blocks filterNot (_.closed) foreach { b => + currentIClazz.cunit.warning(callee.symbol.pos, + "Encountered open block in isSafeToInline: this indicates a bug in the optimizer!\n" + + " caller = " + caller + ", callee = " + callee + ) + return false + } + breakable { for (b <- callee.code.blocks; i <- b) i match { diff --git a/src/compiler/scala/tools/nsc/doc/DocFactory.scala b/src/compiler/scala/tools/nsc/doc/DocFactory.scala index 7fd6538566..42aab918f7 100644 --- a/src/compiler/scala/tools/nsc/doc/DocFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/DocFactory.scala @@ -1,6 +1,5 @@ /* NSC -- new Scala compiler -- Copyright 2007-2010 LAMP/EPFL */ -// $Id$ package scala.tools.nsc package doc diff --git a/src/compiler/scala/tools/nsc/doc/Settings.scala b/src/compiler/scala/tools/nsc/doc/Settings.scala index 4897d78488..f3fe8c384b 100644 --- a/src/compiler/scala/tools/nsc/doc/Settings.scala +++ b/src/compiler/scala/tools/nsc/doc/Settings.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package doc diff --git a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala index 31b932ac53..66e2ba2260 100644 --- a/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala +++ b/src/compiler/scala/tools/nsc/doc/html/HtmlPage.scala @@ -10,7 +10,7 @@ package html import model._ import comment._ -import xml.{Unparsed, XML, NodeSeq} +import xml.{XML, NodeSeq} import xml.dtd.{DocType, PublicID} import scala.collection._ import scala.reflect.NameTransformer @@ -128,12 +128,12 @@ abstract class HtmlPage { thisPage => body.blocks flatMap (blockToHtml(_)) def blockToHtml(block: Block): NodeSeq = block match { - case Title(in, 1) => <h1>{ inlineToHtml(in) }</h1> - case Title(in, 2) => <h2>{ inlineToHtml(in) }</h2> - case Title(in, 3) => <h3>{ inlineToHtml(in) }</h3> - case Title(in, _) => <h4>{ inlineToHtml(in) }</h4> + case Title(in, 1) => <h3>{ inlineToHtml(in) }</h3> + case Title(in, 2) => <h4>{ inlineToHtml(in) }</h4> + case Title(in, 3) => <h5>{ inlineToHtml(in) }</h5> + case Title(in, _) => <h6>{ inlineToHtml(in) }</h6> case Paragraph(in) => <p>{ inlineToHtml(in) }</p> - case Code(data) => <pre>{ Unparsed(data) }</pre> + case Code(data) => <pre>{ xml.Text(data) }</pre> case UnorderedList(items) => <ul>{ listItemsToHtml(items) }</ul> case OrderedList(items, listStyle) => @@ -165,9 +165,10 @@ abstract class HtmlPage { thisPage => case Subscript(in) => <sub>{ inlineToHtml(in) }</sub> case Link(raw, title) => <a href={ raw }>{ inlineToHtml(title) }</a> case EntityLink(entity) => templateToHtml(entity) - case Monospace(text) => <code>{ Unparsed(text) }</code> - case Text(text) => Unparsed(text) + case Monospace(text) => <code>{ xml.Text(text) }</code> + case Text(text) => xml.Text(text) case Summary(in) => inlineToHtml(in) + case HtmlTag(tag) => xml.Unparsed(tag) } def typeToHtml(tpe: model.TypeEntity, hasLinks: Boolean): NodeSeq = { diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css b/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css index 92de97f619..0c17d9fa2a 100644 --- a/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css +++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.css @@ -81,6 +81,7 @@ a:hover { } #comment { + padding-right: 8px; padding-left: 8px; } @@ -193,17 +194,56 @@ div.members > ol > li { .cmt {} .cmt p { - margin: 2px 0 2px 0; + margin-bottom: 0.4em; + margin-top: 0.4em; } -.cmt code { - font-family: monospace; +.cmt h3 { + margin-bottom: 1em; + margin-top: 1em; + display: block; + text-align: left; + font-weight: bold; + font-size: x-large; +} + +.cmt h4 { + margin-bottom: 0.6em; + margin-top: 0.6em; + display: block; + text-align: left; + font-weight: bold; + font-size: large; +} + +.cmt h5 { + margin-bottom: 0.4em; + margin-top: 0.4em; + display: block; + text-align: left; + font-weight: bold; +} + +.cmt h6 { + margin-bottom: 0.4em; + margin-top: 0.4em; + display: block; + text-align: left; + font-style: italic; } .cmt pre { + padding: 0.4em; + border-color: #ddd; + border-style: solid; + border-width: 1px; + margin-left: 0; + margin-bottom: 0.4em; + margin-right: 0; + margin-top: 0.4em; + background-color: #eee; display: block; font-family: monospace; - margin: 2px 0 2px 0; } .cmt ul { @@ -241,20 +281,24 @@ div.members > ol > li { display:list-item; } +.cmt code { + font-family: monospace; +} + .cmt a { - text-decoration: underline; + font-style: bold; } /* Comments structured layout */ p.comment { display: block; - margin-left: 8.7em; + margin-left: 8.7em; } p.shortcomment { display: block; - margin-left: 8.7em; + margin-left: 8.7em; cursor: help; } @@ -264,7 +308,7 @@ div.fullcomment { } #template div.fullcomment { - margin: 6px 0 6px 8.7em; + margin: 6px 0 6px 8.7em; } div.fullcomment .block { 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 29e47fa578..255c61095e 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/Body.scala @@ -67,6 +67,7 @@ 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 /** 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/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala index f067555cc3..475fbf584e 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala @@ -57,21 +57,31 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => new Regex("""(?:\s*\*\s?)?(.*)""") /** Dangerous HTML tags that should be replaced by something safer, such as wiki syntax, or that should be dropped. */ - protected val DangerousHtml = - new Regex("""<(/?(?:p|div|pre|ol|ul|li|h[1-6]|code))[^>]*>""") + protected val DangerousTags = + new Regex("""<(/?(div|ol|ul|li|h[1-6]|p))( [^>]*)?/?>|<!--.*-->""") /** Maps a dangerous HTML tag to a safe wiki replacement, or an empty string if it cannot be salvaged. */ - protected def htmlReplacement(mtch: Regex.Match): String = mtch.matched match { + protected def htmlReplacement(mtch: Regex.Match): String = mtch.group(1) match { case "p" | "div" => "\n\n" - case "h1" | "h2" | "h3" | "h4" | "h5" | "h6" => "\n= " - case "/h1" | "/h2" | "/h3" | "/h4" | "/h5" | "/h6" => " =\n" - case "pre" => "{{{" - case "/pre" => "}}}" + case "h1" => "\n= " + case "/h1" => " =\n" + case "h2" => "\n== " + case "/h2" => " ==\n" + case "h3" => "\n=== " + case "/h3" => " ===\n" + case "h4" | "h5" | "h6" => "\n==== " + case "/h4" | "/h5" | "/h6" => " ====\n" case "code" | "/code" => "`" - case "li" => "\n - " + case "li" => "\n * - " case _ => "" } + /** Safe HTML tags that can be kept. */ + protected val SafeTags = + new Regex("""(</?(abbr|acronym|address|area|a|bdo|big|blockquote|br|button|b|caption|code|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' + /** A Scaladoc tag not linked to a symbol. Returns the name of the tag, and the rest of the line. */ protected val SimpleTag = new Regex("""\s*@(\S+)\s+(.*)""") @@ -114,8 +124,12 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => } } val strippedComment = comment.trim.stripPrefix("/*").stripSuffix("*/") - val safeComment = DangerousHtml.replaceAllIn(strippedComment, { htmlReplacement(_) }) - safeComment.lines.toList map (cleanLine(_)) + val safeComment = DangerousTags.replaceAllIn(strippedComment, { htmlReplacement(_) }) + val markedTagComment = + SafeTags.replaceAllIn(safeComment, { mtch => + java.util.regex.Matcher.quoteReplacement(safeTagMarker + mtch.matched + safeTagMarker) + }) + markedTagComment.lines.toList map (cleanLine(_)) } /** Parses a comment (in the form of a list of lines) to a Comment instance, recursively on lines. To do so, it @@ -251,17 +265,6 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => var summaryParsed = false - /** listStyle ::= '-' spc | '1.' spc | 'I.' spc | 'i.' spc | 'A.' spc | 'a.' spc - * Characters used to build lists and their constructors */ - protected val listStyles = Map[String, (Seq[Block] => Block)]( // TODO Should this be defined at some list companion? - "- " -> ( UnorderedList(_) ), - "1. " -> ( OrderedList(_,"decimal") ), - "I. " -> ( OrderedList(_,"upperRoman") ), - "i. " -> ( OrderedList(_,"lowerRoman") ), - "A. " -> ( OrderedList(_,"upperAlpha") ), - "a. " -> ( OrderedList(_,"lowerAlpha") ) - ) - def document(): Body = { nextChar() val blocks = new mutable.ListBuffer[Block] @@ -287,9 +290,20 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => } } + /** listStyle ::= '-' spc | '1.' spc | 'I.' spc | 'i.' spc | 'A.' spc | 'a.' spc + * Characters used to build lists and their constructors */ + protected val listStyles = Map[String, (Seq[Block] => Block)]( // TODO Should this be defined at some list companion? + "- " -> ( UnorderedList(_) ), + "1. " -> ( OrderedList(_,"decimal") ), + "I. " -> ( OrderedList(_,"upperRoman") ), + "i. " -> ( OrderedList(_,"lowerRoman") ), + "A. " -> ( OrderedList(_,"upperAlpha") ), + "a. " -> ( OrderedList(_,"lowerAlpha") ) + ) + /** Checks if the current line is formed with more than one space and one the listStyles */ def checkList = - countWhitespace > 0 && listStyles.keysIterator.indexWhere(checkSkipInitWhitespace(_)) >= 0 + (countWhitespace > 0) && (listStyles.keys exists { checkSkipInitWhitespace(_) }) /** {{{ * nListBlock ::= nLine { mListBlock } @@ -297,42 +311,39 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => * }}} * Where n and m stand for the number of spaces. When m > n, a new list is nested. */ def listBlock: Block = { - /** consumes one line of a list block */ - def listLine(indentedListStyle: String): Block = { - // deals with mixed lists in the same nesting level by skipping it - if(!jump(indentedListStyle)) { // TODO show warning when jump is false - nextChar(); - nextChar() - } - val p = Paragraph(inline(check(Array(endOfLine)))) - blockEnded("end of list line ") - p - } - def listLevel(leftSide: String, listStyle: String, constructor: (Seq[Block] => Block)): Block = { - val blocks = mutable.ListBuffer.empty[Block] - val length = leftSide.length - val indentedListStyle = leftSide + listStyle - - var index = 1 - var line = listLine(indentedListStyle) - - while (index > -1) { - blocks += line - if (countWhitespace > length) { // nesting-in - blocks += listBlock // TODO is tailrec really needed here? - } - index = listStyles.keysIterator.indexWhere(x => check(leftSide)) - if (index > -1) { line = listLine(indentedListStyle) } + + /** Consumes one list item block and returns it, or None if the block is not a list or a different list. */ + def listLine(indent: Int, style: String): Option[Block] = + if (countWhitespace > indent && checkList) + Some(listBlock) + else if (countWhitespace != indent || !checkSkipInitWhitespace(style)) + None + else { + jumpWhitespace() + jump(style) + val p = Paragraph(inline(false)) + blockEnded("end of list line ") + Some(p) } - constructor(blocks) + /** Consumes all list item blocks (possibly with nested lists) of the same list and returns the list block. */ + def listLevel(indent: Int, style: String): Block = { + val lines = mutable.ListBuffer.empty[Block] + var line: Option[Block] = listLine(indent, style) + while (line.isDefined) { + lines += line.get + line = listLine(indent, style) + } + val constructor = listStyles(style) + constructor(lines) } - val indentation = countWhitespace - val indentStr = " " * indentation - val style = listStyles.keysIterator.find( x => check(indentStr + x) ).getOrElse(listStyles.keysIterator.next) - val constructor = listStyles(style) - listLevel(indentStr, style, constructor) + + val indent = countWhitespace + val style = (listStyles.keys find { checkSkipInitWhitespace(_) }).getOrElse(listStyles.keys.head) + listLevel(indent, style) + } + def code(): Block = { jumpWhitespace() jump("{{{") @@ -387,7 +398,8 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => def inline(isInlineEnd: => Boolean): Inline = { def inline0(): Inline = { - if (check("'''")) bold() + if (char == safeTagMarker) htmlTag() + else if (check("'''")) bold() else if (check("''")) italic() else if (check("`")) monospace() else if (check("__")) underline() @@ -395,7 +407,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => else if (check(",,")) subscript() else if (check("[[")) link() else { - readUntil { check("''") || char == '`' || check("__") || char == '^' || check(",,") || check("[[") || isInlineEnd || checkParaEnded || char == endOfLine } + readUntil { char == safeTagMarker || check("''") || char == '`' || check("__") || char == '^' || check(",,") || check("[[") || isInlineEnd || checkParaEnded || char == endOfLine } Text(getRead()) } } @@ -423,6 +435,14 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => } + def htmlTag(): Inline = { + jump(safeTagMarker) + readUntil(safeTagMarker) + if (char != endOfText) jump(safeTagMarker) + var read = getRead + HtmlTag(read) + } + def bold(): Inline = { jump("'''") val i = inline(check("'''")) @@ -530,7 +550,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => checkSkipInitWhitespace(Array(endOfLine)) || checkSkipInitWhitespace(Array('=')) || checkSkipInitWhitespace(Array('{', '{', '{')) || - checkSkipInitWhitespace(Array(' ', '-', ' ')) || + checkList || checkSkipInitWhitespace(Array('\u003D')) } offset = poff @@ -606,10 +626,18 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => /* JUMPERS */ - /** jumps all the characters in chars - * @return true only if the correct characters have been jumped - * consumes any matching characters - */ + /** jumps a character and consumes it + * @return true only if the correct character has been jumped */ + final def jump(ch: Char): Boolean = { + if (char == ch) { + nextChar() + true + } + else false + } + + /** jumps all the characters in chars, consuming them in the process. + * @return true only if the correct characters have been jumped */ final def jump(chars: Array[Char]): Boolean = { var index = 0 while (index < chars.length && char == chars(index) && char != endOfText) { diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 03fd92235d..2c174860e4 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -7,7 +7,7 @@ import scala.collection.mutable.{LinkedHashMap, SynchronizedMap} import scala.concurrent.SyncVar import scala.util.control.ControlThrowable import scala.tools.nsc.io.AbstractFile -import scala.tools.nsc.util.{SourceFile, Position, RangePosition, OffsetPosition, NoPosition, WorkScheduler} +import scala.tools.nsc.util.{SourceFile, Position, RangePosition, NoPosition, WorkScheduler} import scala.tools.nsc.reporters._ import scala.tools.nsc.symtab._ import scala.tools.nsc.ast._ diff --git a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala index 337f306664..6ef85b2f59 100644 --- a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala +++ b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala @@ -3,7 +3,7 @@ package interactive import ast.Trees import symtab.Positions -import scala.tools.nsc.util.{SourceFile, Position, RangePosition, OffsetPosition, NoPosition, WorkScheduler} +import scala.tools.nsc.util.{SourceFile, Position, RangePosition, NoPosition, WorkScheduler} import scala.collection.mutable.ListBuffer /** Handling range positions diff --git a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala index 7c977c6e60..bde90bc347 100644 --- a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala +++ b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package interactive diff --git a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala index c821b9ed80..0c3d24d46f 100644 --- a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala +++ b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala @@ -1,7 +1,6 @@ /* NSC -- new Scala compiler * Copyright 2005-2010 LAMP/EPFL */ -// $Id$ package scala.tools.nsc package interpreter diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala index fddb1ee928..58ce85f1f6 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala @@ -9,6 +9,7 @@ package interpreter import jline._ import java.util.{ List => JList } +import util.returning object Completion { def looksLikeInvocation(code: String) = ( @@ -166,7 +167,19 @@ class Completion(val repl: Interpreter) extends CompletionOutput { override def follow(id: String) = if (completions(0) contains id) { for (clazz <- repl clazzForIdent id) yield { - (typeOf(clazz.getName) map TypeMemberCompletion.apply) getOrElse new InstanceCompletion(clazz) + // XXX The isMemberClass check is a workaround for the crasher described + // in the comments of #3431. The issue as described by iulian is: + // + // Inner classes exist as symbols + // inside their enclosing class, but also inside their package, with a mangled + // name (A$B). The mangled names should never be loaded, and exist only for the + // optimizer, which sometimes cannot get the right symbol, but it doesn't care + // and loads the bytecode anyway. + // + // So this solution is incorrect, but in the short term the simple fix is + // to skip the compiler any time completion is requested on a nested class. + if (clazz.isMemberClass) new InstanceCompletion(clazz) + else (typeOf(clazz.getName) map TypeMemberCompletion.apply) getOrElse new InstanceCompletion(clazz) } } else None diff --git a/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala b/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala index b3957e1062..92df6a8736 100644 --- a/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala +++ b/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Stepan Koltsov */ -// $Id$ package scala.tools.nsc package interpreter diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala index 34367eacea..ab11a53d43 100644 --- a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala +++ b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Stepan Koltsov */ -// $Id$ package scala.tools.nsc package interpreter diff --git a/src/compiler/scala/tools/nsc/interpreter/Parsed.scala b/src/compiler/scala/tools/nsc/interpreter/Parsed.scala index 0b92608d88..84f5477c21 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Parsed.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Parsed.scala @@ -7,6 +7,7 @@ package scala.tools.nsc package interpreter import jline.ArgumentCompletor.{ ArgumentDelimiter, ArgumentList } +import util.returning /** One instance of a command buffer. */ diff --git a/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala b/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala index 9d604ab8b3..c350468c3b 100644 --- a/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala +++ b/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Stepan Koltsov */ -// $Id$ package scala.tools.nsc package interpreter diff --git a/src/compiler/scala/tools/nsc/interpreter/package.scala b/src/compiler/scala/tools/nsc/interpreter/package.scala index 2ded3a7900..eaf736c5b7 100644 --- a/src/compiler/scala/tools/nsc/interpreter/package.scala +++ b/src/compiler/scala/tools/nsc/interpreter/package.scala @@ -6,9 +6,6 @@ package scala.tools.nsc package object interpreter { - /** Apply a function and return the passed value */ - def returning[T](x: T)(f: T => Unit): T = { f(x) ; x } - /** Tracing */ def tracing[T](msg: String)(x: T): T = { println("(" + msg + ") " + x) ; x } @@ -18,6 +15,14 @@ package object interpreter { /** null becomes "", otherwise identity */ def onull(s: String) = if (s == null) "" else s + /** Heuristically strip interpreter wrapper prefixes + * from an interpreter output string. + */ + def stripWrapperGunk(str: String): String = { + val wrapregex = """(line[0-9]+\$object[$.])?(\$iw[$.])*""" + str.replaceAll(wrapregex, "") + } + /** Class objects */ def classForName(name: String): Option[Class[_]] = try Some(Class forName name) diff --git a/src/compiler/scala/tools/nsc/io/AbstractFile.scala b/src/compiler/scala/tools/nsc/io/AbstractFile.scala index 079b33c2a2..5d4f7b8464 100644 --- a/src/compiler/scala/tools/nsc/io/AbstractFile.scala +++ b/src/compiler/scala/tools/nsc/io/AbstractFile.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc @@ -231,7 +230,7 @@ abstract class AbstractFile extends AnyRef with Iterable[AbstractFile] { * creating an empty file if it does not already existing. */ def fileNamed(name: String): AbstractFile = { - assert(isDirectory) + assert(isDirectory, "Tried to find '%s' in '%s' but it is not a directory".format(name, path)) Option(lookupName(name, false)) getOrElse new PlainFile((sfile.get / name).createFile()) } @@ -240,7 +239,7 @@ abstract class AbstractFile extends AnyRef with Iterable[AbstractFile] { * does not already exist. */ def subdirectoryNamed(name: String): AbstractFile = { - assert (isDirectory) + assert (isDirectory, "Tried to find '%s' in '%s' but it is not a directory".format(name, path)) Option(lookupName(name, true)) getOrElse new PlainFile((sfile.get / name).createDirectory()) } diff --git a/src/compiler/scala/tools/nsc/io/File.scala b/src/compiler/scala/tools/nsc/io/File.scala index 66a0da3a0f..fb7170b3b3 100644 --- a/src/compiler/scala/tools/nsc/io/File.scala +++ b/src/compiler/scala/tools/nsc/io/File.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.nsc package io diff --git a/src/compiler/scala/tools/nsc/io/FileOperationException.scala b/src/compiler/scala/tools/nsc/io/FileOperationException.scala index a94b2c2ef2..2863a485df 100644 --- a/src/compiler/scala/tools/nsc/io/FileOperationException.scala +++ b/src/compiler/scala/tools/nsc/io/FileOperationException.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.nsc package io diff --git a/src/compiler/scala/tools/nsc/io/PlainFile.scala b/src/compiler/scala/tools/nsc/io/PlainFile.scala index a40d01d1f5..9346e88bb2 100644 --- a/src/compiler/scala/tools/nsc/io/PlainFile.scala +++ b/src/compiler/scala/tools/nsc/io/PlainFile.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc @@ -11,8 +10,7 @@ package io import java.io.{ File => JFile, FileInputStream, FileOutputStream, IOException } import PartialFunction._ -object PlainFile -{ +object PlainFile { /** * If the specified File exists, returns an abstract file backed * by it. Otherwise, returns null. diff --git a/src/compiler/scala/tools/nsc/io/SourceReader.scala b/src/compiler/scala/tools/nsc/io/SourceReader.scala index ccd946d0b6..cc69c238b3 100644 --- a/src/compiler/scala/tools/nsc/io/SourceReader.scala +++ b/src/compiler/scala/tools/nsc/io/SourceReader.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/io/VirtualFile.scala b/src/compiler/scala/tools/nsc/io/VirtualFile.scala index 6e3ad7ead6..421e39195d 100644 --- a/src/compiler/scala/tools/nsc/io/VirtualFile.scala +++ b/src/compiler/scala/tools/nsc/io/VirtualFile.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc @@ -32,7 +31,7 @@ class VirtualFile(val name: String, _path: String) extends AbstractFile */ def this(name: String) = this(name, name) - override def hashCode = name.hashCode + override def hashCode = name.## override def equals(that: Any) = cond(that) { case x: VirtualFile => x.name == name } //######################################################################## diff --git a/src/compiler/scala/tools/nsc/io/ZipArchive.scala b/src/compiler/scala/tools/nsc/io/ZipArchive.scala index 4ee3a29671..4be11fc9a8 100644 --- a/src/compiler/scala/tools/nsc/io/ZipArchive.scala +++ b/src/compiler/scala/tools/nsc/io/ZipArchive.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index fe46e22654..0388df7005 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ //todo: allow infix type patterns diff --git a/src/compiler/scala/tools/nsc/javac/JavaTokens.scala b/src/compiler/scala/tools/nsc/javac/JavaTokens.scala index c91ecc95c2..eb64ffe062 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaTokens.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaTokens.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package javac diff --git a/src/compiler/scala/tools/nsc/matching/Matrix.scala b/src/compiler/scala/tools/nsc/matching/Matrix.scala index de3204318f..2c9d974d61 100644 --- a/src/compiler/scala/tools/nsc/matching/Matrix.scala +++ b/src/compiler/scala/tools/nsc/matching/Matrix.scala @@ -16,7 +16,7 @@ trait Matrix extends MatrixAdditions { import analyzer.Typer import CODE._ import Debug._ - import Flags.{ TRANS_FLAG } + import Flags.{ TRANS_FLAG, SYNTHETIC } /** Translation of match expressions. * @@ -201,7 +201,7 @@ trait Matrix extends MatrixAdditions { { val n: Name = if (name == null) newName(pos, "temp") else name // careful: pos has special meaning - owner.newVariable(pos, n) setInfo tpe setFlag (0L /: flags)(_|_) + owner.newVariable(pos, n) setInfo tpe setFlag (SYNTHETIC.toLong /: flags)(_|_) } def typedValDef(x: Symbol, rhs: Tree) = diff --git a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala index d3dddbfaaf..fbfe00d2c1 100644 --- a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala +++ b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala @@ -135,7 +135,7 @@ trait MatrixAdditions extends ast.TreeDSL } } - returning[Tree](resetTraverser traverse _)(lxtt transform tree) + returning(lxtt transform tree)(resetTraverser traverse _) } } diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index d4a920008f..f33f637a46 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -3,12 +3,10 @@ * Copyright 2007 Google Inc. All Rights Reserved. * Author: bqe@google.com (Burak Emir) */ -// $Id$ package scala.tools.nsc package matching -import util.Position import transform.ExplicitOuter import symtab.Flags import collection._ @@ -172,11 +170,7 @@ trait ParallelMatching extends ast.TreeDSL def tail = ps.tail def size = ps.length - def headType = head.necessaryType - def isCaseHead = head.isCaseClass - private val dummyCount = if (isCaseHead) headType.typeSymbol.caseFieldAccessors.length else 0 - def dummies = emptyPatterns(dummyCount) - // def dummies = head.dummies + def dummies = head.dummies def apply(i: Int): Pattern = ps(i) def pzip() = ps.zipWithIndex @@ -193,9 +187,10 @@ trait ParallelMatching extends ast.TreeDSL } } - object TypedUnapply { - def unapply(x: Tree): Option[Boolean] = condOpt(x) { - case Typed(UnapplyParamType(tpe), tpt) => !(tpt.tpe <:< tpe) + if (settings.Xmigration28.value) { + for (p <- ps ; if isArraySeqTest(scrut.tpe, p.tpe)) { + val reportPos = if (p.tree.pos.isDefined) p.tree.pos else scrut.pos + cunit.warning(reportPos, "An Array will no longer match as Seq[_].") } } @@ -203,7 +198,7 @@ trait ParallelMatching extends ast.TreeDSL tracing("Rule", head match { case x if isEquals(x.tree.tpe) => new MixEquals(this, rest) case x: SequencePattern => new MixSequence(this, rest, x) - case AnyUnapply(false) => new MixUnapply(this, rest, false) + case AnyUnapply(false) => new MixUnapply(this, rest) case _ => isPatternSwitch(scrut, ps) match { case Some(x) => new MixLiteralInts(x, rest) @@ -359,7 +354,7 @@ trait ParallelMatching extends ast.TreeDSL /** mixture rule for unapply pattern */ - class MixUnapply(val pmatch: PatternMatch, val rest: Rep, typeTest: Boolean) extends RuleApplication { + class MixUnapply(val pmatch: PatternMatch, val rest: Rep) extends RuleApplication { val uapattern = head match { case x: UnapplyPattern => x ; case _ => abort("XXX") } val ua @ UnApply(app, args) = head.tree @@ -444,32 +439,92 @@ trait ParallelMatching extends ast.TreeDSL * Note: pivot == head, just better typed. */ sealed class MixSequence(val pmatch: PatternMatch, val rest: Rep, pivot: SequencePattern) extends RuleApplication { + require(scrut.tpe <:< head.tpe) + def hasStar = pivot.hasStar - private def pivotLen = pivot.nonStarLength + private def pivotLen = pivot.nonStarLength + private def seqDummies = emptyPatterns(pivot.elems.length + 1) // one pattern var per sequence element up to elemCount, and one more for the rest of the sequence lazy val pvs = scrut createSequenceVars pivotLen - // divide the remaining rows into success/failure branches, expanding subsequences of patterns - private lazy val rowsplit = { - require(scrut.tpe <:< head.tpe) + // Should the given pattern join the expanded pivot in the success matrix? If so, + // this partial function will be defined for the pattern, and the result of the apply + // is the expanded sequence of new patterns. + lazy val successMatrixFn = new PartialFunction[Pattern, List[Pattern]] { + private def seqIsDefinedAt(x: SequenceLikePattern) = (hasStar, x.hasStar) match { + case (true, true) => true + case (true, false) => pivotLen <= x.nonStarLength + case (false, true) => pivotLen >= x.nonStarLength + case (false, false) => pivotLen == x.nonStarLength + } - val res = for ((c, rows) <- pmatch pzip rest.rows) yield { - def canSkip = pivot canSkipSubsequences c - def passthrough(skip: Boolean) = if (skip) None else Some(rows insert c) + def isDefinedAt(pat: Pattern) = pat match { + case x: SequenceLikePattern => seqIsDefinedAt(x) + case WildcardPattern() => true + case _ => false + } - pivot.subsequences(c, scrut.seqType) match { - case Some(ps) => (Some(rows insert ps), passthrough(canSkip)) - case None => (None, passthrough(false)) - } + def apply(pat: Pattern): List[Pattern] = pat match { + case x: SequenceLikePattern => + def isSameLength = pivotLen == x.nonStarLength + def rebound = x.nonStarPatterns :+ (x.elemPatterns.last rebindTo WILD(scrut.seqType)) + + (pivot.hasStar, x.hasStar, isSameLength) match { + case (true, true, true) => rebound :+ NoPattern + case (true, true, false) => (seqDummies drop 1) :+ x + case (true, false, true) => x.elemPatterns ++ List(NilPattern, NoPattern) + case (false, true, true) => rebound + case (false, false, true) => x.elemPatterns :+ NoPattern + case _ => seqDummies + } + + case _ => seqDummies } + } + + // Should the given pattern be in the fail matrix? This is true of any sequences + // as long as the result of the length test on the pivot doesn't make it impossible: + // for instance if neither sequence is right ignoring and they are of different + // lengths, the later one cannot match since its length must be wrong. + def failureMatrixFn(c: Pattern) = (pivot ne c) && (c match { + case x: SequenceLikePattern => + (hasStar, x.hasStar) match { + case (_, true) => true + case (true, false) => pivotLen > x.nonStarLength + case (false, false) => pivotLen != x.nonStarLength + } + case WildcardPattern() => true + case _ => false + }) - res.unzip match { case (l1, l2) => (l1.flatten, l2.flatten) } + // divide the remaining rows into success/failure branches, expanding subsequences of patterns + val successRows = pmatch pzip rest.rows collect { + case (c, row) if successMatrixFn isDefinedAt c => row insert successMatrixFn(c) } + val failRows = pmatch pzip rest.rows collect { + case (c, row) if failureMatrixFn(c) => row insert c + } + + // the discrimination test for sequences is a call to lengthCompare. Note that + // this logic must be fully consistent wiith successMatrixFn and failureMatrixFn above: + // any inconsistency will (and frequently has) manifested as pattern matcher crashes. + lazy val cond = { + // the method call symbol + val methodOp: Symbol = head.tpe member nme.lengthCompare + + // the comparison to perform. If the pivot is right ignoring, then a scrutinee sequence + // of >= pivot length could match it; otherwise it must be exactly equal. + val compareOp: (Tree, Tree) => Tree = if (hasStar) _ INT_>= _ else _ INT_== _ - lazy val cond = (pivot precondition pmatch).get // length check - lazy val success = squeezedBlockPVs(pvs, remake(rowsplit._1, pvs, hasStar).toTree) - lazy val failure = remake(rowsplit._2).toTree + // scrutinee.lengthCompare(pivotLength) [== | >=] 0 + val compareFn: Tree => Tree = (t: Tree) => compareOp((t DOT methodOp)(LIT(pivotLen)), ZERO) + + // wrapping in a null check on the scrutinee + nullSafe(compareFn, FALSE)(scrut.id) + } + lazy val success = squeezedBlockPVs(pvs, remake(successRows, pvs, hasStar).toTree) + lazy val failure = remake(failRows).toTree final def tree(): Tree = codegen } @@ -508,53 +563,38 @@ trait ParallelMatching extends ast.TreeDSL * remaining: remaining, rows index and pattern */ class MixTypes(val pmatch: PatternMatch, val rest: Rep) extends RuleApplication { - case class Yes(bx: Int, moreSpecific: Pattern, subsumed: List[Pattern]) - case class No(bx: Int, remaining: Pattern) - - val (yeses, noes) = { - val _ys = new ListBuffer[Yes] - val _ns = new ListBuffer[No] - - for ((pattern, j) <- pmatch.pzip()) { - // scrutinee, head of pattern group - val (s, p) = (pattern.tpe, head.necessaryType) - - def isEquivalent = head.necessaryType =:= pattern.tpe - def isObjectTest = pattern.isObject && (p =:= pattern.necessaryType) - - def sMatchesP = matches(s, p) - def pMatchesS = matches(p, s) - - def ifEquiv(yes: Pattern): Pattern = if (isEquivalent) yes else pattern - - def passl(p: Pattern = NoPattern, ps: List[Pattern] = pmatch.dummies) = Some(Yes(j, p, ps)) - def passr() = Some( No(j, pattern)) - - def typed(pp: Tree) = passl(ifEquiv(Pattern(pp))) - def subs() = passl(ifEquiv(NoPattern), pattern subpatterns pmatch) - - val (oneY, oneN) = pattern match { - case Pattern(LIT(null), _) if !(p =:= s) => (None, passr) // (1) - case x if isObjectTest => (passl(), None) // (2) - case Pattern(Typed(pp, _), _) if sMatchesP => (typed(pp), None) // (4) - // The next line used to be this which "fixed" 1697 but introduced - // numerous regressions including #3136. - // case Pattern(_: UnApply, _) => (passl(), passr) - case Pattern(_: UnApply, _) => (None, passr) - case x if !x.isDefault && sMatchesP => (subs(), None) - case x if x.isDefault || pMatchesS => (passl(), passr) - case _ => (None, passr) - } - oneY map (_ys +=) - oneN map (_ns +=) + val succRows = new ListBuffer[(Int, List[Pattern])] + val failRows = new ListBuffer[(Int, Pattern)] + + for ((pattern, j) <- pmatch.pzip()) { + def isMoreSpecific = matches(pattern.tpe, head.tpe) + def isLessSpecific = matches(head.tpe, pattern.tpe) + def isEquivalent = head.tpe =:= pattern.tpe + def isObjectTest = pattern.isObject && (head.tpe =:= pattern.tpe) + + def whichSubs = if (head.isCaseClass) (pattern expandToArity head.arity) else Nil + + def ifElsePattern(yes: Pattern) = if (isEquivalent) yes else pattern + + def succDummy = succRows += ((j, NoPattern :: pmatch.dummies)) + def succTyped(pp: Pattern) = succRows += ((j, ifElsePattern(pp) :: pmatch.dummies)) + def succSubs = succRows += ((j, ifElsePattern(NoPattern) :: whichSubs)) + def failOnly = failRows += ((j, pattern)) + + pattern match { + case Pattern(LIT(null), _) if !isEquivalent => failOnly + case x if isObjectTest => succDummy + // Note: bugs 1697/2337/etc have their origins right here because they + // have a type test which when passed doesn't guarantee a match: the + // unapply can still fail. + case Pattern(Typed(pp, _), _) if isMoreSpecific => succTyped(Pattern(pp)) + case Pattern(UnApply(_, _), _) => failOnly + case x if !x.isDefault && isMoreSpecific => succSubs + case x if x.isDefault || isLessSpecific => succDummy ; failOnly + case _ => failOnly } - (_ys.toList, _ns.toList) } - val moreSpecific = yeses map (_.moreSpecific) - val subsumed = yeses map (x => (x.bx, x.subsumed)) - val remaining = noes map (x => (x.bx, x.remaining)) - // temporary checks so we're less crashy while we determine what to implement. def checkErroneous(scrut: Scrutinee): Type = { scrut.tpe match { @@ -565,29 +605,20 @@ trait ParallelMatching extends ast.TreeDSL } } - private def mkZipped = - for (Yes(j, moreSpecific, subsumed) <- yeses) yield - j -> (moreSpecific :: subsumed) - - lazy val casted = scrut castedTo pmatch.headType + lazy val casted = scrut castedTo head.tpe lazy val cond = condition(checkErroneous(casted), scrut, head.boundVariables.nonEmpty) - private def isAnyMoreSpecific = yeses exists (x => !x.moreSpecific.isEmpty) - lazy val (subtests, subtestVars) = - if (isAnyMoreSpecific) (mkZipped, List(casted.pv)) - else (subsumed, Nil) - - lazy val newRows = - for ((j, ps) <- subtests) yield - (rest rows j).insert2(ps, pmatch(j).boundVariables, casted.sym) - lazy val success = { - val srep = remake(newRows, subtestVars ::: casted.accessorPatternVars, includeScrut = false) + val newRows = + for ((j, ps) <- succRows.toList) yield + (rest rows j).insert2(ps, pmatch(j).boundVariables, casted.sym) + + val newRoots = casted.pv :: casted.accessorPatternVars + val srep = remake(newRows, newRoots, false) squeezedBlock(casted.allValDefs, srep.toTree) } - lazy val failure = - mkFail(remaining map { case (p1, p2) => rest rows p1 insert p2 }) + lazy val failure = mkFail(failRows.toList map { case (p1, p2) => rest rows p1 insert p2 }) final def tree(): Tree = codegen } diff --git a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala index 83fd3a9608..82bddb2013 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala @@ -104,10 +104,7 @@ trait PatternBindings extends ast.TreeDSL // Like rebindToEqualsCheck, but subtly different. Not trying to be // mysterious -- I haven't sorted it all out yet. - def rebindToObjectCheck(): Pattern = { - val sType = sufficientType - rebindToType(mkEqualsRef(sType), sType) - } + def rebindToObjectCheck(): Pattern = rebindToType(mkEqualsRef(atomicTpe), atomicTpe) /** Helpers **/ private def wrapBindings(vs: List[Symbol], pat: Tree): Tree = vs match { diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala index a21a9c7d9f..7621c1c2f3 100644 --- a/src/compiler/scala/tools/nsc/matching/Patterns.scala +++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala @@ -85,10 +85,11 @@ trait Patterns extends ast.TreeDSL { // 8.1.4 (a) case class ApplyIdentPattern(tree: Apply) extends ApplyPattern with NamePattern { - require (!isVarPattern(fn) && args.isEmpty) + // XXX - see bug 3411 for code which violates this assumption + // require (!isVarPattern(fn) && args.isEmpty) val ident @ Ident(name) = fn - override def sufficientType = Pattern(ident).equalsCheck + override def atomicTpe = Pattern(ident).equalsCheck override def simplify(pv: PatternVar) = this.rebindToObjectCheck() override def description = "Id(%s)".format(name) } @@ -97,7 +98,7 @@ trait Patterns extends ast.TreeDSL { require (args.isEmpty) val Apply(select: Select, _) = tree - override def sufficientType = mkSingletonFromQualifier + override def atomicTpe = mkSingletonFromQualifier override def simplify(pv: PatternVar) = this.rebindToObjectCheck() override def description = backticked match { case Some(s) => "this." + s @@ -116,7 +117,7 @@ trait Patterns extends ast.TreeDSL { case class ObjectPattern(tree: Apply) extends ApplyPattern { // NamePattern? require(!fn.isType && isModule) - override def sufficientType = tpe.narrow + override def atomicTpe = tpe.narrow override def simplify(pv: PatternVar) = this.rebindToObjectCheck() override def description = "Obj(%s)".format(fn) } @@ -138,9 +139,7 @@ trait Patterns extends ast.TreeDSL { private def isColonColon = cleanName == "::" - override def subpatterns(pm: MatchMatrix#PatternMatch) = - if (pm.head.isCaseClass) toPats(args) - else super.subpatterns(pm) + override def expandToArity(newArity: Int): List[Pattern] = toPats(args) override def simplify(pv: PatternVar) = if (args.isEmpty) this rebindToEmpty tree.tpe @@ -167,19 +166,20 @@ trait Patterns extends ast.TreeDSL { private val MethodType(List(arg, _*), _) = fn.tpe private def uaTyped = Typed(tree, TypeTree(arg.tpe)) setType arg.tpe - override def necessaryType = arg.tpe + // to match an extractor, the arg type must be matched. + override def tpe = arg.tpe override def simplify(pv: PatternVar) = if (pv.sym.tpe <:< arg.tpe) this else this rebindTo uaTyped - override def description = "UnApp(%s => %s)".format(necessaryType, resTypesString) + override def description = "UnApp(%s => %s)".format(tpe, resTypesString) } // 8.1.8 (unapplySeq calls) - case class SequenceExtractorPattern(tree: UnApply) extends UnapplyPattern { + case class SequenceExtractorPattern(tree: UnApply) extends UnapplyPattern with SequenceLikePattern { - private val UnApply( + lazy val UnApply( Apply(TypeApply(Select(_, nme.unapplySeq), List(tptArg)), _), List(ArrayValue(_, elems)) ) = tree @@ -211,90 +211,24 @@ trait Patterns extends ast.TreeDSL { override def description = "UnSeq(%s => %s)".format(tptArg, resTypesString) } - abstract class SequencePattern extends Pattern { - val tree: ArrayValue - def nonStarPatterns: List[Pattern] - def subsequences(other: Pattern, seqType: Type): Option[List[Pattern]] - def canSkipSubsequences(second: Pattern): Boolean - - lazy val ArrayValue(elemtpt, elems) = tree - lazy val elemPatterns = toPats(elems) - - override def dummies = emptyPatterns(elems.length + 1) - override def subpatternsForVars: List[Pattern] = elemPatterns + trait SequenceLikePattern extends Pattern { + def elems: List[Tree] + def elemPatterns = toPats(elems) + def nonStarPatterns: List[Pattern] = if (hasStar) elemPatterns.init else elemPatterns def nonStarLength = nonStarPatterns.length def isAllDefaults = nonStarPatterns forall (_.isDefault) - def isShorter(other: SequencePattern) = nonStarLength < other.nonStarLength - def isSameLength(other: SequencePattern) = nonStarLength == other.nonStarLength - - protected def lengthCheckOp: (Tree, Tree) => Tree = - if (hasStar) _ ANY_>= _ - else _ MEMBER_== _ - - // optimization to avoid trying to match if length makes it impossible - override def precondition(pm: PatternMatch) = { - import pm.{ scrut, head } - val len = nonStarLength - val compareOp = head.tpe member nme.lengthCompare - - def cmpFunction(t1: Tree) = lengthCheckOp((t1 DOT compareOp)(LIT(len)), ZERO) - - Some(nullSafe(cmpFunction _, FALSE)(scrut.id)) - } - - /** True if 'next' must be checked even if 'first' failed to match after passing its length test - * (the conditional supplied by getPrecondition.) This is an optimization to avoid checking sequences - * which cannot match due to a length incompatibility. - */ - override def description = "Seq(%s)".format(elemPatterns) + def isShorter(other: SequenceLikePattern) = nonStarLength < other.nonStarLength + def isSameLength(other: SequenceLikePattern) = nonStarLength == other.nonStarLength } // 8.1.8 (b) (literal ArrayValues) - case class SequenceNoStarPattern(tree: ArrayValue) extends SequencePattern { - require(!hasStar) - lazy val nonStarPatterns = elemPatterns - - // no star - def subsequences(other: Pattern, seqType: Type): Option[List[Pattern]] = - condOpt(other) { - case next: SequenceStarPattern if isSameLength(next) => next rebindStar seqType - case next: SequenceNoStarPattern if isSameLength(next) => next.elemPatterns ::: List(NoPattern) - case WildcardPattern() | (_: SequencePattern) => dummies - } - - def canSkipSubsequences(second: Pattern): Boolean = - (tree eq second.tree) || (cond(second) { - case x: SequenceNoStarPattern => (x isShorter this) && this.isAllDefaults - }) - } - - // 8.1.8 (b) - case class SequenceStarPattern(tree: ArrayValue) extends SequencePattern { - require(hasStar) - lazy val nonStarPatterns = elemPatterns.init - - // yes star - private def nilPats = List(NilPattern, NoPattern) - def subsequences(other: Pattern, seqType: Type): Option[List[Pattern]] = - condOpt(other) { - case next: SequenceStarPattern if isSameLength(next) => (next rebindStar seqType) ::: List(NoPattern) - case next: SequenceStarPattern if (next isShorter this) => (dummies drop 1) ::: List(next) - case next: SequenceNoStarPattern if isSameLength(next) => next.elemPatterns ::: nilPats - case WildcardPattern() | (_: SequencePattern) => dummies - } - - def rebindStar(seqType: Type): List[Pattern] = - nonStarPatterns ::: List(elemPatterns.last rebindTo WILD(seqType)) - - def canSkipSubsequences(second: Pattern): Boolean = - (tree eq second.tree) || (cond(second) { - case x: SequenceStarPattern => this isShorter x - case x: SequenceNoStarPattern => !(x isShorter this) - }) + case class SequencePattern(tree: ArrayValue) extends Pattern with SequenceLikePattern { + lazy val ArrayValue(elemtpt, elems) = tree - override def description = "Seq*(%s)".format(elemPatterns) + override def subpatternsForVars: List[Pattern] = elemPatterns + override def description = "Seq(%s)".format(elemPatterns mkString ", ") } // 8.1.8 (c) @@ -353,7 +287,7 @@ trait Patterns extends ast.TreeDSL { case x: Literal => LiteralPattern(x) case x: UnApply => UnapplyPattern(x) case x: Ident => if (isVarPattern(x)) VariablePattern(x) else SimpleIdPattern(x) - case x: ArrayValue => if (isRightIgnoring(x)) SequenceStarPattern(x) else SequenceNoStarPattern(x) + case x: ArrayValue => SequencePattern(x) case x: Select => StableIdPattern(x) case x: Star => StarPattern(x) case x: This => ThisPattern(x) // XXX ? @@ -377,13 +311,20 @@ trait Patterns extends ast.TreeDSL { object UnapplyPattern { private object UnapplySeq { + /** This is as far as I can tell an elaborate attempt to spot case List(...) and + * avoid the extractor penalty. It has led to some bugs (e.g. 2800, 3050) which + * I attempt to address below. + */ private object TypeApp { def unapply(x: Any) = condOpt(x) { case TypeApply(sel @ Select(stor, nme.unapplySeq), List(tpe)) if stor.symbol eq ListModule => tpe } } def unapply(x: UnApply) = condOpt(x) { - case UnApply(Apply(TypeApp(tptArg), _), List(ArrayValue(_, xs))) => (tptArg, xs) + case UnApply(Apply(TypeApp(tptArg), _), List(ArrayValue(_, xs))) + // make sure it's not only _*, as otherwise the rewrite + // also removes the instance check. + if (xs.isEmpty || xs.size > 1 || !isStar(xs.head)) => (tptArg, xs) } } @@ -449,7 +390,7 @@ trait Patterns extends ast.TreeDSL { protected def mkSingletonFromQualifier = { def pType = qualifier match { case _: Apply => PseudoType(tree) - case _ => singleType(Pattern(qualifier).necessaryType, sym) + case _ => singleType(Pattern(qualifier).tpe, sym) } qualifier.tpe match { case t: ThisType => singleType(t, sym) // this.X @@ -460,7 +401,7 @@ trait Patterns extends ast.TreeDSL { sealed trait NamePattern extends Pattern { def name: Name - override def sufficientType = tpe.narrow + override def atomicTpe = tpe.narrow override def simplify(pv: PatternVar) = this.rebindToEqualsCheck() override def description = name.toString() } @@ -487,26 +428,31 @@ trait Patterns extends ast.TreeDSL { protected lazy val Apply(fn, args) = tree override def subpatternsForVars: List[Pattern] = toPats(args) - override def dummies = - if (!this.isCaseClass) Nil - else emptyPatterns(sufficientType.typeSymbol.caseFieldAccessors.size) - def isConstructorPattern = fn.isType } sealed abstract class Pattern extends PatternBindingLogic { val tree: Tree + // The type of a pattern says: in order for something to match this + // pattern, it must conform to this type. It does NOT say that if + // something does conform to this type, it definitely matches the pattern: + // see atomic type for that. + def tpe = tree.tpe + + // The atomic type of a pattern says: if something matches this, it + // definitely matches the pattern (but this is independent of nullness + // and guards, which are checked independently.) + def atomicTpe = tpe + // returns either a simplification of this pattern or identity. def simplify(pv: PatternVar): Pattern = this - def simplify(): Pattern = this simplify null - // the right number of dummies for this pattern - def dummies: List[Pattern] = Nil + // the arity of this pattern + def arity = if (isCaseClass) caseAccessors.length else 0 - // given this scrutinee, what if any condition must be satisfied before - // we even try to match? - def precondition(scrut: PatternMatch): Option[Tree] = None + // the right number of dummies for this pattern + def dummies: List[Pattern] = emptyPatterns(arity) // 8.1.13 // A pattern p is irrefutable for type T if any of the following applies: @@ -517,33 +463,26 @@ trait Patterns extends ast.TreeDSL { // pi is irrefutable for Ti. def irrefutableFor(tpe: Type) = false - // does this pattern completely cover that pattern (i.e. latter cannot be matched) - def completelyCovers(second: Pattern) = false - // Is this a default pattern (untyped "_" or an EmptyTree inserted by the matcher) def isDefault = false - // what type must a scrutinee have to have any chance of matching this pattern? - def necessaryType = tpe - - // what type could a scrutinee have which would automatically indicate a match? - // (nullness and guards will still be checked.) - def sufficientType = tpe - // XXX have to determine if this can be made useful beyond an extractor barrier. // Default sufficient type might be NothingClass.tpe, tpe.narrow, ... // the subpatterns for this pattern (at the moment, that means constructor arguments) - def subpatterns(pm: MatchMatrix#PatternMatch): List[Pattern] = pm.dummies + def expandToArity(newArity: Int): List[Pattern] = + if (isDefault) emptyPatterns(newArity) + else if (newArity == 0) Nil + else Predef.error("expandToArity(" + newArity + ") in " + this) def sym = tree.symbol - def tpe = tree.tpe def prefix = tpe.prefix def isEmpty = tree.isEmpty def isSymValid = (sym != null) && (sym != NoSymbol) def isModule = sym.isModule || tpe.termSymbol.isModule def isCaseClass = tpe.typeSymbol hasFlag Flags.CASE + def caseAccessors = tpe.typeSymbol.caseFieldAccessors def isObject = isSymValid && prefix.isStable // XXX not entire logic def unadorn(t: Tree): Tree = Pattern unadorn t @@ -585,7 +524,7 @@ trait Patterns extends ast.TreeDSL { if (boundVariables.isEmpty) description else "%s%s".format(bindingsDescription, description) } - def toTypeString() = "%s <: x <: %s".format(necessaryType, sufficientType) + def toTypeString() = "%s <: x <: %s".format(tpe, atomicTpe) } /*** Extractors ***/ diff --git a/src/compiler/scala/tools/nsc/plugins/Plugin.scala b/src/compiler/scala/tools/nsc/plugins/Plugin.scala index f527441c68..1b7e208334 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugin.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugin.scala @@ -2,7 +2,6 @@ * Copyright 2007-2010 LAMP/EPFL * @author Lex Spoon */ -// $Id$ package scala.tools.nsc package plugins diff --git a/src/compiler/scala/tools/nsc/plugins/PluginComponent.scala b/src/compiler/scala/tools/nsc/plugins/PluginComponent.scala index 1da08cc4ee..4234d49545 100644 --- a/src/compiler/scala/tools/nsc/plugins/PluginComponent.scala +++ b/src/compiler/scala/tools/nsc/plugins/PluginComponent.scala @@ -3,7 +3,6 @@ * @author Lex Spoon * Updated by Anders Bach Nielsen */ -// $Id$ package scala.tools.nsc package plugins diff --git a/src/compiler/scala/tools/nsc/plugins/PluginDescription.scala b/src/compiler/scala/tools/nsc/plugins/PluginDescription.scala index 2345fcc32c..2498d84338 100644 --- a/src/compiler/scala/tools/nsc/plugins/PluginDescription.scala +++ b/src/compiler/scala/tools/nsc/plugins/PluginDescription.scala @@ -2,7 +2,6 @@ * Copyright 2007-2010 LAMP/EPFL * @author Lex Spoon */ -// $Id$ package scala.tools.nsc package plugins diff --git a/src/compiler/scala/tools/nsc/plugins/PluginLoadException.scala b/src/compiler/scala/tools/nsc/plugins/PluginLoadException.scala index 42780d7a05..f0402809d7 100644 --- a/src/compiler/scala/tools/nsc/plugins/PluginLoadException.scala +++ b/src/compiler/scala/tools/nsc/plugins/PluginLoadException.scala @@ -2,7 +2,6 @@ * Copyright 2007-2010 LAMP/EPFL * @author Lex Spoon */ -// $Id$ package scala.tools.nsc package plugins diff --git a/src/compiler/scala/tools/nsc/plugins/Plugins.scala b/src/compiler/scala/tools/nsc/plugins/Plugins.scala index e800e0f904..5823a09995 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugins.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugins.scala @@ -3,7 +3,6 @@ * @author Lex Spoon * Updated by Anders Bach Nielsen */ -// $Id$ package scala.tools.nsc package plugins diff --git a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala index e35843fc9c..11ef7ffb68 100644 --- a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala @@ -2,7 +2,6 @@ * Copyright 2002-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package reporters diff --git a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala index f7d380c975..1f01087dad 100644 --- a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala @@ -2,7 +2,6 @@ * Copyright 2002-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package reporters diff --git a/src/compiler/scala/tools/nsc/reporters/Reporter.scala b/src/compiler/scala/tools/nsc/reporters/Reporter.scala index bdb6c6ae6f..8dcb5183bb 100644 --- a/src/compiler/scala/tools/nsc/reporters/Reporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/Reporter.scala @@ -2,7 +2,6 @@ * Copyright 2002-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package reporters diff --git a/src/compiler/scala/tools/nsc/reporters/ReporterTimer.scala b/src/compiler/scala/tools/nsc/reporters/ReporterTimer.scala index 4c2f6a4a69..56f904a8bc 100644 --- a/src/compiler/scala/tools/nsc/reporters/ReporterTimer.scala +++ b/src/compiler/scala/tools/nsc/reporters/ReporterTimer.scala @@ -2,7 +2,6 @@ * Copyright 2002-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package reporters diff --git a/src/compiler/scala/tools/nsc/reporters/StoreReporter.scala b/src/compiler/scala/tools/nsc/reporters/StoreReporter.scala index b94639bb5c..e4736297e9 100644 --- a/src/compiler/scala/tools/nsc/reporters/StoreReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/StoreReporter.scala @@ -2,7 +2,6 @@ * Copyright 2002-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package reporters diff --git a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala index 75e2c5ce11..21608f7f05 100644 --- a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala @@ -69,9 +69,12 @@ trait AbsSettings { * In immutable, of course they will return a new object, which means * we can't use "this.type", at least not in a non-casty manner, which * is unfortunate because we lose type information without it. + * + * ...but now they're this.type because of #3462. The immutable + * side doesn't exist yet anyway. */ - def withAbbreviation(name: String): Setting - def withHelpSyntax(help: String): Setting + def withAbbreviation(name: String): this.type + def withHelpSyntax(help: String): this.type def helpSyntax: String = name def abbreviations: List[String] = Nil diff --git a/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala b/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala index 945d9aa2fe..388e68497e 100644 --- a/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala +++ b/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala @@ -2,7 +2,6 @@ * Copyright 2007-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package symtab diff --git a/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala b/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala index f2e62856d5..40177fad10 100644 --- a/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala +++ b/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala @@ -2,7 +2,6 @@ * Copyright 2007-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package symtab diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index 3511565326..597a34c773 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -2,14 +2,14 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package symtab import scala.collection.mutable.{HashMap, HashSet} -import scala.tools.nsc.util.{Position, NoPosition} +import scala.tools.nsc.util.NoPosition import Flags._ +import PartialFunction._ trait Definitions extends reflect.generic.StandardDefinitions { self: SymbolTable => @@ -17,12 +17,6 @@ trait Definitions extends reflect.generic.StandardDefinitions { object definitions extends AbsDefinitions { def isDefinitionsInitialized = isInitialized - // Working around bug #2133 - private object definitionHelpers { - def cond[T](x: T)(f: PartialFunction[T, Boolean]) = (f isDefinedAt x) && f(x) - } - import definitionHelpers._ - // symbols related to packages var emptypackagescope: Scope = null //debug diff --git a/src/compiler/scala/tools/nsc/symtab/Flags.scala b/src/compiler/scala/tools/nsc/symtab/Flags.scala index b0cc3a5340..de8f92fdf4 100644 --- a/src/compiler/scala/tools/nsc/symtab/Flags.scala +++ b/src/compiler/scala/tools/nsc/symtab/Flags.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package symtab diff --git a/src/compiler/scala/tools/nsc/symtab/InfoTransformers.scala b/src/compiler/scala/tools/nsc/symtab/InfoTransformers.scala index 54bd35e5b3..95dcb07c7c 100644 --- a/src/compiler/scala/tools/nsc/symtab/InfoTransformers.scala +++ b/src/compiler/scala/tools/nsc/symtab/InfoTransformers.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package symtab diff --git a/src/compiler/scala/tools/nsc/symtab/Names.scala b/src/compiler/scala/tools/nsc/symtab/Names.scala index b0e6c5250a..e6222a7a94 100644 --- a/src/compiler/scala/tools/nsc/symtab/Names.scala +++ b/src/compiler/scala/tools/nsc/symtab/Names.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package symtab diff --git a/src/compiler/scala/tools/nsc/symtab/Scopes.scala b/src/compiler/scala/tools/nsc/symtab/Scopes.scala index f305f20d2a..bc8b93ac2c 100644 --- a/src/compiler/scala/tools/nsc/symtab/Scopes.scala +++ b/src/compiler/scala/tools/nsc/symtab/Scopes.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package symtab diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index 9133228768..ed72fc16fa 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package symtab @@ -330,7 +329,7 @@ trait StdNames extends reflect.generic.StdNames { self: SymbolTable => val print = newTermName("print") val productArity = newTermName("productArity") val productElement = newTermName("productElement") - val productElementName = newTermName("productElementName") + // val productElementName = newTermName("productElementName") val productPrefix = newTermName("productPrefix") val readResolve = newTermName("readResolve") val sameElements = newTermName("sameElements") diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 947f5a8f88..a95c8ada8f 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package symtab diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala index 75902568fa..0fdbeae98f 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package symtab diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index ebab5d9be7..3157e5cc20 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc @@ -928,7 +927,20 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable => * type parameters later. */ def typeParams: List[Symbol] = - if (isMonomorphicType) List() else { rawInfo.load(this); rawInfo.typeParams } + if (isMonomorphicType) + List() + else { + if (validTo == NoPeriod) { + val current = phase + try { + phase = phaseOf(infos.validFrom) + rawInfo.load(this) + } finally { + phase = current + } + } + rawInfo.typeParams + } /** The value parameter sections of this symbol. */ diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index dc59587c4a..e0987c2d8b 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -2301,7 +2301,7 @@ A type's typeSymbol should never be inspected directly. origin+ (if(typeArgs.isEmpty) "" else (typeArgs map (_.safeToString)).mkString("[ ", ", ", " ]")) // +"#"+tid //DEBUG if (constr.inst eq null) "<null " + origin + ">" - else if (settings.debug.value) varString+"(@"+constr.hashCode+")"+constr.toString + else if (settings.debug.value) varString+"(@"+constr.## +")"+constr.toString else if (constr.inst eq NoType) varString else constr.inst.toString } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/AbstractFileReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/AbstractFileReader.scala index b32646e3cb..106318a47d 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/AbstractFileReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/AbstractFileReader.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala index a139f605b0..a3917cf2d2 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package symtab diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 7cd32ff81e..9c382439bc 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package symtab diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala index 23f45e0d13..624b3635bf 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Iulian Dragos */ -// $Id$ package scala.tools.nsc package symtab diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala index 0ae2d5b015..d1f9280872 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package symtab diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index 68d314bfe9..91141ce4d6 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package symtab diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala index 4022258746..a94838e163 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package symtab diff --git a/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala b/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala index 20dbb4d917..f62a42375a 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala @@ -2,7 +2,6 @@ * Copyright 2004-2010 LAMP/EPFL */ -// $Id$ package scala.tools.nsc package symtab diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala index 4d9c0ffc92..a90fb8b66c 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala @@ -2,7 +2,6 @@ * Copyright 2004-2010 LAMP/EPFL */ -// $Id$ package scala.tools.nsc package symtab diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index 92f117428a..f1ed9f43a0 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package transform @@ -162,7 +161,8 @@ abstract class AddInterfaces extends InfoTransform { case ClassInfoType(parents, decls, _) => assert(phase == implClassPhase) ClassInfoType( - ObjectClass.tpe :: (parents.tail map mixinToImplClass) ::: List(iface.tpe), + ObjectClass.tpe :: (parents.tail map mixinToImplClass filter (_.typeSymbol != ObjectClass)) + ::: List(iface.tpe), implDecls(sym, decls), sym) case PolyType(tparams, restpe) => diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index e6811cf497..c3c60253b9 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -2,7 +2,6 @@ * Copyrights 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package transform diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index ad88b783b4..c9049d9ab1 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author */ -// $Id$ package scala.tools.nsc package transform @@ -28,6 +27,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { import collection.mutable private val guardedCtorStats: mutable.Map[Symbol, List[Tree]] = new mutable.HashMap[Symbol, List[Tree]] + private val ctorParams: mutable.Map[Symbol, List[Symbol]] = new mutable.HashMap[Symbol, List[Symbol]] def transformClassTemplate(impl: Template): Template = { val clazz = impl.symbol.owner // the transformed class @@ -78,18 +78,22 @@ abstract class Constructors extends Transform with ast.TreeDSL { // A transformer for expressions that go into the constructor val intoConstructorTransformer = new Transformer { + def isParamRef(sym: Symbol) = + (sym hasFlag PARAMACCESSOR) && + sym.owner == clazz && + !(sym.isGetter && sym.accessed.isVariable) && + !sym.isSetter override def transform(tree: Tree): Tree = tree match { case Apply(Select(This(_), _), List()) => // references to parameter accessor methods of own class become references to parameters // outer accessors become references to $outer parameter - if ((tree.symbol hasFlag PARAMACCESSOR) && tree.symbol.owner == clazz) + if (isParamRef(tree.symbol)) gen.mkAttributedIdent(parameter(tree.symbol.accessed)) setPos tree.pos else if (tree.symbol.outerSource == clazz && !clazz.isImplClass) gen.mkAttributedIdent(parameterNamed(nme.OUTER)) setPos tree.pos else super.transform(tree) - case Select(This(_), _) - if ((tree.symbol hasFlag PARAMACCESSOR) && !tree.symbol.isSetter && tree.symbol.owner == clazz) => + case Select(This(_), _) if (isParamRef(tree.symbol)) => // references to parameter accessor field of own class become references to parameters gen.mkAttributedIdent(parameter(tree.symbol)) setPos tree.pos case Select(_, _) => @@ -301,7 +305,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { case _ => false } - log("merging: " + originalStats.mkString("\n") + " : " + specializedStats.mkString("\n")) + log("merging: " + originalStats.mkString("\n") + "\nwith\n" + specializedStats.mkString("\n")) val res = for (s <- originalStats; val stat = s.duplicate) yield { log("merge: looking at " + stat) val stat1 = stat match { @@ -315,8 +319,13 @@ abstract class Constructors extends Transform with ast.TreeDSL { } if (stat1 eq stat) { + assert(ctorParams(genericClazz).length == constrParams.length) + // this is just to make private fields public + (new specializeTypes.ImplementationAdapter(ctorParams(genericClazz), constrParams, null, true))(stat1) + // statements coming from the original class need retyping in the current context if (settings.debug.value) log("retyping " + stat1) + val d = new specializeTypes.Duplicator d.retyped(localTyper.context1.asInstanceOf[d.Context], stat1, @@ -351,6 +360,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { if (usesSpecializedField && shouldGuard && postfix.nonEmpty) { // save them for duplication in the specialized subclass guardedCtorStats(clazz) = postfix + ctorParams(clazz) = constrParams val tree = If( diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 88a7e13d80..4c000ce3f7 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package transform @@ -336,9 +335,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. def erasedTypeRef(sym: Symbol): Type = typeRef(erasure(sym.owner.tpe), sym, List()) - /** Remove duplicate references to class Object in a list of parent classes - * todo: needed? - */ + /** Remove duplicate references to class Object in a list of parent classes */ private def removeDoubleObject(tps: List[Type]): List[Type] = tps match { case List() => List() case tp :: tps1 => diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index ee5bc040f5..f78022bdaa 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package transform @@ -62,6 +61,12 @@ abstract class ExplicitOuter extends InfoTransform result } + /** Issue a migration warning for instance checks which might be on an Array and + * for which the type parameter conforms to Seq, because these answers changed in 2.8. + */ + def isArraySeqTest(lhs: Type, rhs: Type) = + ArrayClass.tpe <:< lhs.widen && rhs.widen.matchesPattern(SeqClass.tpe) + def outerAccessor(clazz: Symbol): Symbol = { val firstTry = clazz.info.decl(nme.expandedName(nme.OUTER, clazz)) if (firstTry != NoSymbol && firstTry.outerSource == clazz) firstTry @@ -295,7 +300,6 @@ abstract class ExplicitOuter extends InfoTransform * </p> */ class ExplicitOuterTransformer(unit: CompilationUnit) extends OuterPathTransformer(unit) { - /** The definition tree of the outer accessor of current class */ def outerFieldDef: Tree = VAL(outerField(currentClass)) === EmptyTree @@ -484,8 +488,14 @@ abstract class ExplicitOuter extends InfoTransform matchTranslation(mch) case _ => - val x = super.transform(tree) + if (settings.Xmigration28.value) tree match { + case TypeApply(fn @ Select(qual, _), args) if fn.symbol == Object_isInstanceOf || fn.symbol == Any_isInstanceOf => + if (isArraySeqTest(qual.tpe, args.head.tpe)) + unit.warning(tree.pos, "An Array will no longer match as Seq[_].") + case _ => () + } + val x = super.transform(tree) if (x.tpe eq null) x else x setType transformInfo(currentOwner, x.tpe) } diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala index 7fc826cdbb..1bee37bfe6 100644 --- a/src/compiler/scala/tools/nsc/transform/Flatten.scala +++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package transform diff --git a/src/compiler/scala/tools/nsc/transform/InfoTransform.scala b/src/compiler/scala/tools/nsc/transform/InfoTransform.scala index 9872705dfc..fa93a9b534 100644 --- a/src/compiler/scala/tools/nsc/transform/InfoTransform.scala +++ b/src/compiler/scala/tools/nsc/transform/InfoTransform.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author */ -// $Id$ package scala.tools.nsc package transform diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index 6ed0bfcccb..33fa14033e 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author */ -// $Id$ package scala.tools.nsc package transform diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/transform/LiftCode.scala index 951fa53041..a6a4a8d22c 100644 --- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala +++ b/src/compiler/scala/tools/nsc/transform/LiftCode.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Gilles Dubochet */ -// $Id$ package scala.tools.nsc package transform diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 18c4a74950..a9810b2217 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package transform @@ -568,7 +567,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { val newSyms = newDefs map (_.symbol) def isNotDuplicate(tree: Tree) = tree match { case DefDef(_, _, _, _, _, _) => - val sym = tree.symbol; + val sym = tree.symbol !(sym.isDeferred && (newSyms exists (nsym => nsym.name == sym.name && (nsym.tpe matches sym.tpe)))) case _ => @@ -742,14 +741,14 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { && !sym.accessed.hasFlag(PRESUPER) && !sym.isOuterAccessor) - if (settings.debug.value) { - log("needsInitFlag(" + sym.fullName + "): " + res) - log("\tsym.isGetter: " + sym.isGetter) - log("\t!isInitializedToDefault: " + !sym.isInitializedToDefault + sym.hasFlag(DEFAULTINIT) + sym.hasFlag(ACCESSOR) + sym.isTerm) - log("\t!sym.hasFlag(PARAMACCESSOR): " + !sym.hasFlag(PARAMACCESSOR)) - //println("\t!sym.accessed.hasFlag(PRESUPER): " + !sym.accessed.hasFlag(PRESUPER)) - log("\t!sym.isOuterAccessor: " + !sym.isOuterAccessor) - } +// if (settings.debug.value) { +// log("needsInitFlag(" + sym.fullName + "): " + res) +// log("\tsym.isGetter: " + sym.isGetter) +// log("\t!isInitializedToDefault: " + !sym.isInitializedToDefault + sym.hasFlag(DEFAULTINIT) + sym.hasFlag(ACCESSOR) + sym.isTerm) +// log("\t!sym.hasFlag(PARAMACCESSOR): " + !sym.hasFlag(PARAMACCESSOR)) +// //println("\t!sym.accessed.hasFlag(PRESUPER): " + !sym.accessed.hasFlag(PRESUPER)) +// log("\t!sym.isOuterAccessor: " + !sym.isOuterAccessor) +// } res } diff --git a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala index 305f9218ec..1500759b30 100644 --- a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala +++ b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package transform diff --git a/src/compiler/scala/tools/nsc/transform/SampleTransform.scala b/src/compiler/scala/tools/nsc/transform/SampleTransform.scala index 02e73035be..6661543d89 100644 --- a/src/compiler/scala/tools/nsc/transform/SampleTransform.scala +++ b/src/compiler/scala/tools/nsc/transform/SampleTransform.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package transform diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index c2e5e474a9..c4ce7fe6e2 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Iulian Dragos */ -// $Id$ package scala.tools.nsc package transform @@ -11,6 +10,7 @@ import scala.tools.nsc.symtab.Flags import scala.tools.nsc.util.FreshNameCreator import scala.collection.{mutable, immutable} +import immutable.Set /** Specialize code on types. */ @@ -55,7 +55,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } /** Reduce the given environment to contain mappings only for type variables in tps. */ - def reduce(env: TypeEnv, tps: immutable.Set[Symbol]): TypeEnv = { + def restrict(env: TypeEnv, tps: immutable.Set[Symbol]): TypeEnv = { env filter { kv => tps.contains(kv._1)} } @@ -314,11 +314,13 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } def specializedTypeVars(sym: Symbol): immutable.Set[Symbol] = - specializedTypeVars(atPhase(currentRun.typerPhase)(sym.info)) + atPhase(currentRun.typerPhase)(specializedTypeVars(sym.info)) /** Return the set of @specialized type variables mentioned by the given type. - * It only counts type variables that appear naked or as arguments to Java - * arrays (the only places where it makes sense to specialize). + * It only counts type variables that appear: + * - naked + * - as arguments to type constructors in @specialized positions + * (arrays ar considered as Array[@specialized T] */ def specializedTypeVars(tpe: Type): immutable.Set[Symbol] = tpe match { case TypeRef(pre, sym, args) => @@ -327,7 +329,11 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { immutable.ListSet.empty + sym else if (sym == definitions.ArrayClass) specializedTypeVars(args) - else immutable.ListSet.empty[Symbol] + else { + val extra = for ((tp, arg) <- sym.typeParams.zip(args) if tp.hasAnnotation(SpecializedClass)) + yield specializedTypeVars(arg).toList + immutable.ListSet.empty[Symbol] ++ extra.flatten + } case PolyType(tparams, resTpe) => specializedTypeVars(tparams map (_.info)) ++ specializedTypeVars(resTpe) @@ -565,6 +571,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { normalizeMember(m.owner, m, outerEnv) flatMap { normalizedMember => val ms = specializeMember(m.owner, normalizedMember, outerEnv, clazz.info.typeParams) // atPhase(currentRun.typerPhase)(println("normalizedMember.info: " + normalizedMember.info)) // bring the info to the typer phase + // interface traits have concrete members now + if (ms.nonEmpty && clazz.isTrait && clazz.isInterface) + clazz.resetFlag(INTERFACE) + if (normalizedMember.isMethod) { val newTpe = subst(outerEnv, normalizedMember.info) if (newTpe != normalizedMember.info) // only do it when necessary, otherwise the method type might be at a later phase already @@ -599,7 +609,15 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { private def normalizeMember(owner: Symbol, sym: Symbol, outerEnv: TypeEnv): List[Symbol] = { if (settings.debug.value) log("normalizeMember: " + sym.fullName) if (sym.isMethod && !atPhase(currentRun.typerPhase)(sym.typeParams.isEmpty)) { - val (stps, tps) = splitParams(sym.info.typeParams) + var (stps, tps) = splitParams(sym.info.typeParams) + val unusedStvars = stps -- specializedTypeVars(sym.info).toList + if (unusedStvars.nonEmpty && currentRun.compiles(sym) && !sym.isSynthetic) { + reporter.warning(sym.pos, "%s %s unused or used in non-specializable positions." + .format(unusedStvars.mkString("", ", ", ""), if (unusedStvars.length == 1) "is" else "are")) + unusedStvars foreach (_.removeAnnotation(SpecializedClass)) + stps = stps -- unusedStvars + tps = tps ::: unusedStvars + } val res = sym :: (for (env <- specializations(stps) if needsSpecialization(env, sym)) yield { val keys = env.keysIterator.toList; val vals = env.valuesIterator.toList @@ -636,7 +654,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { for (spec <- specializations(tparams)) yield { if (sym.hasFlag(PRIVATE)) sym.resetFlag(PRIVATE).setFlag(PROTECTED) val specMember = subst(outerEnv)(specializedOverload(owner, sym, spec)) - typeEnv(specMember) = outerEnv ++ spec + typeEnv(specMember) = typeEnv(sym) ++ outerEnv ++ spec overloads(sym) = Overload(specMember, spec) :: overloads(sym) specMember } @@ -674,54 +692,83 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ private def specialOverrides(clazz: Symbol): List[Symbol] = { log("specialOverrides(" + clazz + ")") + + /** Return the overridden symbol in syms that needs a specialized overriding symbol, + * together with its specialization environment. The overridden symbol may not be + * the closest to 'overriding', in a given hierarchy. + * + * An method m needs a special override if + * * m overrides a method whose type contains specialized type variables + * * there is a valid specialization environment that maps the overridden method type to m's type. + */ + def needsSpecialOverride(overriding: Symbol, syms: List[Symbol]): (Symbol, TypeEnv) = { + def missingSpecializations(baseTvar: Symbol, derivedTvar: Symbol): Set[Type] = { + val baseSet = concreteTypes(baseTvar).toSet + val derivedSet = concreteTypes(derivedTvar).toSet + baseSet diff derivedSet + } + + def checkOverriddenTParams(overridden: Symbol) { + if (currentRun.compiles(overriding)) + for (val (baseTvar, derivedTvar) <- overridden.info.typeParams.zip(overriding.info.typeParams); + val missing = missingSpecializations(baseTvar, derivedTvar) + if missing.nonEmpty) + reporter.error(derivedTvar.pos, + "Type parameter has to be specialized at least for the same types as in the overridden method. Missing " + + "types: " + missing.mkString("", ", ", "")) + } + + for (overridden <- syms) { + if (settings.debug.value) + log("Overridden: " + overridden.fullName + ": " + overridden.info + + "\n by " + overriding.fullName + ": " + overriding.info) + val stvars = specializedTypeVars(overridden.info) + if (!stvars.isEmpty) { + if (settings.debug.value) log("\t\tspecializedTVars: " + stvars) + checkOverriddenTParams(overridden) + + val env = unify(overridden.info, overriding.info, emptyEnv) + if (settings.debug.value) + log("\t\tenv: " + env + "isValid: " + TypeEnv.isValid(env, overridden) + + "found: " + atPhase(phase.next)(overridden.owner.info.decl(specializedName(overridden, env)))) + if (!TypeEnv.restrict(env, stvars).isEmpty + && TypeEnv.isValid(env, overridden) + && atPhase(phase.next)(overridden.owner.info.decl(specializedName(overridden, env))) != NoSymbol) + return (overridden, env) + } + } + (NoSymbol, emptyEnv) + } + val oms = new mutable.ListBuffer[Symbol] for (overriding <- clazz.info.decls; - val allOverridden = overriding.allOverriddenSymbols - if !allOverridden.isEmpty; - val overridden = allOverridden.head) { - if (settings.debug.value) - log("\toverriding pairs: " + overridden.fullName + ": " + overridden.info - + " overriden by " + overriding.fullName + ": " + overriding.info) - if (overriding.owner == clazz && !specializedTypeVars(overridden.info).isEmpty) { - if (settings.debug.value) log("\t\tspecializedTVars: " + specializedTypeVars(overridden.info)) - val env = unify(overridden.info, overriding.info, emptyEnv) - if (settings.debug.value) - log("\t\tenv: " + env + "isValid: " - + TypeEnv.isValid(env, overridden) - + " looking for: " + specializedName(overridden, env) + " in:\n" - + atPhase(phase.next)(overridden.owner.info.decls) - + "found: " + atPhase(phase.next)(overridden.owner.info.decl(specializedName(overridden, env)))) - if (!env.isEmpty - && TypeEnv.isValid(env, overridden) - && atPhase(phase.next)(overridden.owner.info.decl(specializedName(overridden, env))) != NoSymbol) { - log("Added specialized overload for " + overriding.fullName + " in env: " + env) - val om = specializedOverload(clazz, overridden, env) - typeEnv(om) = env - concreteSpecMethods += overriding - if (!overriding.isDeferred) { - // if the override is a normalized member, 'om' gets the implementation from - // its original target, and adds the environment of the normalized member (that is, - // any specialized /method/ type parameter bindings) - info(om) = info.get(overriding) match { - case Some(NormalizedMember(target)) => - typeEnv(om) = env ++ typeEnv(overriding) - SpecialOverride(target) - case _ => SpecialOverride(overriding) - } - info(overriding) = Forward(om) - om setPos overriding.pos // set the position of the concrete, overriding member - } else { - // abstract override - if (settings.debug.value) log("abstract override " + overriding.fullName + " with specialized " + om.fullName) - info(om) = Forward(overriding) - } - overloads(overriding) = Overload(om, env) :: overloads(overriding) - oms += om - atPhase(phase.next)( - assert(overridden.owner.info.decl(om.name) != NoSymbol, - "Could not find " + om.name + " in " + overridden.owner.info.decls)) + val (overridden, env) = needsSpecialOverride(overriding, overriding.allOverriddenSymbols) + if overridden != NoSymbol) { + log("Added specialized overload for " + overriding.fullName + " in env: " + env) + val om = specializedOverload(clazz, overridden, env) + typeEnv(om) = env + concreteSpecMethods += overriding + if (!overriding.isDeferred) { // concrete method + // if the override is a normalized member, 'om' gets the implementation from + // its original target, and adds the environment of the normalized member (that is, + // any specialized /method/ type parameter bindings) + info(om) = info.get(overriding) match { + case Some(NormalizedMember(target)) => + typeEnv(om) = env ++ typeEnv(overriding) + SpecialOverride(target) + case _ => SpecialOverride(overriding) } + info(overriding) = Forward(om) + om setPos overriding.pos + } else { // abstract override + if (settings.debug.value) log("abstract override " + overriding.fullName + " with specialized " + om.fullName) + info(om) = Forward(overriding) } + overloads(overriding) = Overload(om, env) :: overloads(overriding) + oms += om + atPhase(phase.next)( + assert(overridden.owner.info.decl(om.name) != NoSymbol, + "Could not find " + om.name + " in " + overridden.owner.info.decls)) } oms.toList } @@ -824,7 +871,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ override def transformInfo(sym: Symbol, tpe: Type): Type = { val res = tpe match { - case PolyType(targs, ClassInfoType(base, decls, clazz)) => + case PolyType(targs, ClassInfoType(base, decls, clazz)) if clazz != definitions.RepeatedParamClass && clazz != definitions.JavaRepeatedParamClass => val parents = base map specializedType if (settings.debug.value) log("transformInfo (poly) " + clazz + " with parents1: " + parents + " ph: " + phase) // if (clazz.name.toString == "$colon$colon") @@ -905,6 +952,52 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val global: SpecializeTypes.this.global.type = SpecializeTypes.this.global } with typechecker.Duplicators + /** A tree symbol substituter that substitutes on type skolems. + * If a type parameter is a skolem, it looks for the original + * symbol in the 'from' and maps it to the corresponding new + * symbol. The new symbol should probably be a type skolem as + * well (not enforced). + * + * All private members are made protected in order to be accessible from + * specialized classes. + */ + class ImplementationAdapter(from: List[Symbol], + to: List[Symbol], + targetClass: Symbol, + addressFields: Boolean) extends TreeSymSubstituter(from, to) { + override val symSubst = new SubstSymMap(from, to) { + override def matches(sym1: Symbol, sym2: Symbol) = + if (sym2.isTypeSkolem) sym2.deSkolemize eq sym1 + else sym1 eq sym2 + } + + private def isAccessible(sym: Symbol): Boolean = + (currentClass == sym.owner.enclClass) && (currentClass != targetClass) + + private def shouldMakePublic(sym: Symbol): Boolean = + sym.hasFlag(PRIVATE | PROTECTED) && (addressFields || !nme.isLocalName(sym.name)) + + /** All private members that are referenced are made protected, + * in order to be accessible from specialized subclasses. + */ + override def transform(tree: Tree): Tree = tree match { + case Select(qual, name) => + val sym = tree.symbol + if (sym.hasFlag(PRIVATE)) + if (settings.debug.value) + log("seeing private member %s, currentClass: %s, owner: %s, isAccessible: %b, isLocalName: %b" + .format(sym, currentClass, sym.owner.enclClass, isAccessible(sym), nme.isLocalName(sym.name))) + if (shouldMakePublic(sym) && !isAccessible(sym)) { + if (settings.debug.value) log("changing private flag of " + sym) + sym.makeNotPrivate(sym.owner) + } + super.transform(tree) + + case _ => + super.transform(tree) + } + } + def specializeCalls(unit: CompilationUnit) = new TypingTransformer(unit) { /** Map a specializable method to it's rhs, when not deferred. */ val body: mutable.Map[Symbol, Tree] = new mutable.HashMap @@ -938,20 +1031,22 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { /** The specialized symbol of 'tree.symbol' for tree.tpe, if there is one */ def specSym(qual: Tree): Option[Symbol] = { val env = unify(symbol.tpe, tree.tpe, emptyEnv) - log("checking for rerouting: " + tree + " with sym.tpe: " + symbol.tpe + " tree.tpe: " + tree.tpe + " env: " + env) + log("[specSym] checking for rerouting: %s with \n\tsym.tpe: %s, \n\ttree.tpe: %s \n\tenv: %s \n\tname: %s" + .format(tree, symbol.tpe, tree.tpe, env, specializedName(symbol, env))) if (!env.isEmpty) { // a method? - val specMember = overload(symbol, env) - if (specMember.isDefined) Some(specMember.get.sym) - else { // a field? - val specMember = qual.tpe.member(specializedName(symbol, env)) - if (specMember ne NoSymbol) Some(specMember) - else None - } + val specMember = qual.tpe.member(specializedName(symbol, env)) + if (specMember ne NoSymbol) + if (typeEnv(specMember) == env) Some(specMember) + else { + log("wrong environments for specialized member: \n\ttypeEnv(%s) = %s\n\tenv = %s".format(specMember, typeEnv(specMember), env)) + None + } + else None } else None } def maybeTypeApply(fun: Tree, targs: List[Tree]) = - if (targs.isEmpty)fun else TypeApply(fun, targs) + if (targs.isEmpty) fun else TypeApply(fun, targs) curTree = tree tree match { @@ -971,13 +1066,14 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val qual1 = transform(qual) specSym(qual1) match { case Some(specMember) => - if (settings.debug.value) log("found " + specMember) + if (settings.debug.value) log("found " + specMember.fullName) assert(symbol.info.typeParams.length == targs.length) val env = typeEnv(specMember) val residualTargs = - for ((tvar, targ) <-symbol.info.typeParams.zip(targs) if !env.isDefinedAt(tvar)) + for ((tvar, targ) <- symbol.info.typeParams.zip(targs) if !env.isDefinedAt(tvar)) yield targ - assert(residualTargs.length == specMember.info.typeParams.length) + assert(residualTargs.length == specMember.info.typeParams.length, + "residual: %s, tparams: %s, env: %s".format(residualTargs, symbol.info.typeParams, env)) val tree1 = maybeTypeApply(Select(qual1, specMember), residualTargs) log("rewrote " + tree + " to " + tree1) localTyper.typedOperator(atPos(tree.pos)(tree1)) // being polymorphic, it must be a method @@ -988,10 +1084,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { case Select(qual, name) => if (settings.debug.value) log("looking at Select: " + tree + " sym: " + symbol + ": " + symbol.info + "[tree.tpe: " + tree.tpe + "]") - //if (settings.debug.value) log("\toverloads: " + overloads.mkString("", "\n", "")) + if (!specializedTypeVars(symbol.info).isEmpty && name != nme.CONSTRUCTOR) { - if (settings.debug.value) - log("checking for unification at " + tree + " with sym.tpe: " + symbol.tpe + " and tree.tpe: " + tree.tpe + " at " + tree.pos.line) val env = unify(symbol.tpe, tree.tpe, emptyEnv) if (settings.debug.value) log("checking for rerouting: " + tree + " with sym.tpe: " + symbol.tpe + " tree.tpe: " + tree.tpe + " env: " + env) if (!env.isEmpty) { @@ -1048,8 +1142,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val superRef: Tree = Select(Super(nme.EMPTY.toTypeName, nme.EMPTY.toTypeName), nme.CONSTRUCTOR) forwardCall(tree.pos, superRef, vparamss) } - val tree1 = atPos(symbol.pos)(treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, Block(List(t), Literal(())))) - localTyper.typed(tree1) + if (symbol.isPrimaryConstructor) localTyper typed { + atPos(symbol.pos)(treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, Block(List(t), Literal(())))) + } else { + // duplicate the original constructor + duplicateBody(ddef, info(symbol).target) + } } else info(symbol) match { case Implementation(target) => @@ -1177,7 +1275,9 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val symbol = tree.symbol if (settings.debug.value) log("specializing body of" + symbol.fullName + ": " + symbol.info) val DefDef(mods, name, tparams, vparamss, tpt, _) = tree - val (_, origtparams) = splitParams(source.typeParams) +// val (_, origtparams) = splitParams(source.typeParams) + val boundTvars = typeEnv(symbol).keySet + val origtparams = source.typeParams.filter(!boundTvars(_)) if (settings.debug.value) log("substituting " + origtparams + " for " + symbol.typeParams) // skolemize type parameters @@ -1192,54 +1292,14 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val symSubstituter = new ImplementationAdapter( parameters(source).flatten ::: origtparams, vparamss1.flatten.map(_.symbol) ::: newtparams, - source.enclClass) + source.enclClass, + false) // don't make private fields public val tmp = symSubstituter(body(source).duplicate) tpt.tpe = tpt.tpe.substSym(oldtparams, newtparams) treeCopy.DefDef(tree, mods, name, tparams, vparamss1, tpt, tmp) } - /** A tree symbol substituter that substitutes on type skolems. - * If a type parameter is a skolem, it looks for the original - * symbol in the 'from' and maps it to the corresponding new - * symbol. The new symbol should probably be a type skolem as - * well (not enforced). - * - * All private members are made protected in order to be accessible from - * specialized classes. - */ - class ImplementationAdapter(from: List[Symbol], to: List[Symbol], targetClass: Symbol) extends TreeSymSubstituter(from, to) { - override val symSubst = new SubstSymMap(from, to) { - override def matches(sym1: Symbol, sym2: Symbol) = - if (sym2.isTypeSkolem) sym2.deSkolemize eq sym1 - else sym1 eq sym2 - } - - private def isAccessible(sym: Symbol): Boolean = - (currentClass == sym.owner.enclClass) && (currentClass != targetClass) - - /** All private members that are referenced are made protected, - * in order to be accessible from specialized subclasses. - */ - override def transform(tree: Tree): Tree = tree match { - case Select(qual, name) => - val sym = tree.symbol - if (sym.hasFlag(PRIVATE)) - if (settings.debug.value) log("seeing private member " + sym + " targetClass: " + currentClass + " owner: " + sym.owner.enclClass) - if (sym.hasFlag(PRIVATE | PROTECTED) && !nme.isLocalName(sym.name) && !isAccessible(sym)) { - if (settings.debug.value) log("changing private flag of " + sym) -// tree.symbol.resetFlag(PRIVATE).setFlag(PROTECTED) - sym.makeNotPrivate(sym.owner) -// tree.symbol.resetFlag(PRIVATE | PROTECTED) -// tree.symbol.privateWithin = NoSymbol - } - super.transform(tree) - - case _ => - super.transform(tree) - } - } - def warn(clazz: Symbol)(pos: Position, err: String) = if (!clazz.hasFlag(SPECIALIZED)) unit.warning(pos, err) @@ -1263,19 +1323,21 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { if (info(m).target.isGetterOrSetter) hasSpecializedFields = true if (m.isClassConstructor) { val origParamss = parameters(info(m).target) - assert(origParamss.length == 1) // we are after uncurry val vparams = for ((tp, sym) <- m.info.paramTypes zip origParamss(0)) yield m.newValue(sym.pos, specializedName(sym, typeEnv(cls))) .setInfo(tp) .setFlag(sym.flags) + // param accessors for private members (the others are inherited from the generic class) - for (param <- vparams if cls.info.nonPrivateMember(param.name) == NoSymbol; - val acc = param.cloneSymbol(cls).setFlag(PARAMACCESSOR | PRIVATE)) { - cls.info.decls.enter(acc) - mbrs += ValDef(acc, EmptyTree).setType(NoType).setPos(m.pos) - } + if (m.isPrimaryConstructor) + for (param <- vparams if cls.info.nonPrivateMember(param.name) == NoSymbol; + val acc = param.cloneSymbol(cls).setFlag(PARAMACCESSOR | PRIVATE)) { + cls.info.decls.enter(acc) + mbrs += ValDef(acc, EmptyTree).setType(NoType).setPos(m.pos) + } + // ctor mbrs += atPos(m.pos)(DefDef(m, Modifiers(m.flags), List(vparams) map (_ map ValDef), EmptyTree)) } else { @@ -1291,11 +1353,14 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } } if (hasSpecializedFields) { + import definitions.BooleanClass + + val isSpecializedInstance = cls.hasFlag(SPECIALIZED) || cls.info.parents.exists(_.typeSymbol.hasFlag(SPECIALIZED)) val sym = cls.newMethod(nme.SPECIALIZED_INSTANCE, cls.pos) - .setInfo(MethodType(Nil, definitions.BooleanClass.tpe)) + .setInfo(MethodType(Nil, BooleanClass.tpe)) cls.info.decls.enter(sym) mbrs += atPos(sym.pos) { - DefDef(sym, Literal(cls.hasFlag(SPECIALIZED)).setType(sym.tpe.finalResultType)).setType(NoType) + DefDef(sym, Literal(isSpecializedInstance).setType(BooleanClass.tpe)).setType(NoType) } } mbrs.toList diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index 9fff8534d3..9b54dd9428 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Iulian Dragos */ -// $Id$ package scala.tools.nsc package transform diff --git a/src/compiler/scala/tools/nsc/transform/Transform.scala b/src/compiler/scala/tools/nsc/transform/Transform.scala index 9fb6d5cdc1..2fc3eee59c 100644 --- a/src/compiler/scala/tools/nsc/transform/Transform.scala +++ b/src/compiler/scala/tools/nsc/transform/Transform.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package transform diff --git a/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala b/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala index 65f3caf642..8efbb356e8 100644 --- a/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala +++ b/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package transform diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index bad98193b0..0270323133 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author */ -// $Id$ package scala.tools.nsc package transform @@ -404,8 +403,15 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { Select(predef, "wrap"+elemtp.typeSymbol.name+"Array") else TypeApply(Select(predef, "genericWrapArray"), List(TypeTree(elemtp))) - val adaptedTree = // need to cast to Array[elemtp], as arrays are not covariant - gen.mkCast(tree, arrayType(elemtp)) + val pt = arrayType(elemtp) + val adaptedTree = // might need to cast to Array[elemtp], as arrays are not covariant + if (tree.tpe <:< pt) tree + else gen.mkCast( + if (elemtp.typeSymbol == AnyClass && isValueClass(tree.tpe.typeArgs.head.typeSymbol)) + gen.mkRuntimeCall("toObjectArray", List(tree)) + else + tree, + arrayType(elemtp)) Apply(meth, List(adaptedTree)) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala index 70bf55e661..63e5a9fb25 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package typechecker diff --git a/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala b/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala index f1e88fe6e8..ac1853cbe0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package typechecker diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 82c4c01b79..7469388a08 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package typechecker @@ -317,7 +316,7 @@ trait Contexts { self: Analyzer => override def toString(): String = { if (this == NoContext) "NoContext" else owner.toString() + " @ " + tree.getClass() + - " " + tree.toString() + ", scope = " + scope.hashCode() + + " " + tree.toString() + ", scope = " + scope.## + " " + scope.toList + "\n:: " + outer.toString() } diff --git a/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala b/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala index a2e9f10a5a..43ac9182c3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala +++ b/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package typechecker diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index 78f43296b4..dbc3ffbe17 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -189,6 +189,7 @@ abstract class Duplicators extends Analyzer { if (tree.hasSymbol && tree.symbol != NoSymbol && !tree.symbol.isLabel // labels cannot be retyped by the type checker as LabelDef has no ValDef/return type trees && invalidSyms.isDefinedAt(tree.symbol)) { + if (settings.debug.value) log("removed symbol " + tree.symbol) tree.symbol = NoSymbol } @@ -240,7 +241,9 @@ abstract class Duplicators extends Analyzer { case Select(th @ This(_), sel) if (oldClassOwner ne null) && (th.symbol == oldClassOwner) => log("selection on this, no type ascription required") - super.typed(atPos(tree.pos)(Select(This(newClassOwner), sel)), mode, pt) + // we use the symbol name instead of the tree name because the symbol may have been + // name mangled, rendering the tree name obsolete + super.typed(atPos(tree.pos)(Select(This(newClassOwner), tree.symbol.name)), mode, pt) case This(_) if (oldClassOwner ne null) && (tree.symbol == oldClassOwner) => // val tree1 = Typed(This(newClassOwner), TypeTree(fixType(tree.tpe.widen))) diff --git a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala index 5b79662014..7cfc4733d3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala +++ b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package typechecker diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index e503d721f9..3abaf4f337 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ //todo: rewrite or disllow new T where T is a mixin (currently: <init> not a member of T) //todo: use inherited type info also for vars and values @@ -127,8 +126,7 @@ self: Analyzer => case _ => false } - override def hashCode = - name.hashCode + pre.hashCode + sym.hashCode + override def hashCode = name.## + pre.## + sym.## override def toString = "ImplicitInfo(" + name + "," + pre + "," + sym + ")" } @@ -573,6 +571,19 @@ self: Analyzer => /** A set containing names that are shadowed by implicit infos */ lazy val shadowed = new HashSet[Name]("shadowed", 512) + // #3453 + // in addition to the implicit symbols that may shadow the implicit with name `name`, + // this method tests whether there's a non-implicit symbol with name `name` in scope + // inspired by logic in typedIdent + def nonImplicitSynonymInScope(name: Name) = { + val defEntry = context.scope.lookupEntry(name) + (defEntry ne null) && + reallyExists(defEntry.sym) && + !defEntry.sym.isImplicit // the implicit ones are handled by the `shadowed` set above + // also, subsumes the test that defEntry.sym ne info.sym + // (the `info` that's in scope at the call to nonImplicitSynonymInScope in tryImplicit) + } + /** Is `sym' the standard conforms method in Predef? * Note: DON't replace this by sym == Predef_conforms, as Predef_conforms is a `def' * which does a member lookup (it can't be a lazy val because we might reload Predef @@ -594,7 +605,7 @@ self: Analyzer => def tryImplicit(info: ImplicitInfo): SearchResult = { incCounter(triedImplicits) if (info.isCyclicOrErroneous || - (isLocal && shadowed.contains(info.name)) || + (isLocal && (shadowed.contains(info.name) || nonImplicitSynonymInScope(info.name))) || (isView && isConformsMethod(info.sym)) || //@M this condition prevents no-op conversions, which are a problem (besides efficiency), // one example is removeNames in NamesDefaults, which relies on the type checker failing in case of ambiguity between an assignment/named arg @@ -617,6 +628,11 @@ self: Analyzer => applicable } + // #3453 -- alternative fix, seems not to be faster than encoding the set as the boolean predicate nonImplicitSynonymInScope + // in addition to the *implicit* symbols that may shadow the implicit with name `name` (added to shadowed by addAppInfos) + // add names of non-implicit symbols that are in scope (accessible without prefix) + // for(sym <- context.scope; if !sym.isImplicit) shadowed addEntry sym.name + var applicable = Map[ImplicitInfo, SearchResult]() for (is <- iss) applicable = addAppInfos(is, applicable) diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 1ee1604319..31bb86994e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package typechecker diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 37f8a21bf8..d56b8ed944 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package typechecker @@ -298,7 +297,7 @@ trait Namers { self: Analyzer => private def enterSymFinishWith(tree: Tree, tparams: List[TypeDef]) { val sym = tree.symbol - if (settings.debug.value) log("entered " + sym + " in " + context.owner + ", scope-id = " + context.scope.hashCode()); + if (settings.debug.value) log("entered " + sym + " in " + context.owner + ", scope-id = " + context.scope.## ) var ltype = namerOf(sym).typeCompleter(tree) if (!tparams.isEmpty) { //@M! TypeDef's type params are handled differently @@ -876,6 +875,7 @@ trait Namers { self: Analyzer => if (vparam.tpt.isEmpty) vparam.symbol setInfo WildcardType val overridden = overriddenSymbol if (overridden != NoSymbol && !(overridden hasFlag OVERLOADED)) { + overridden.cookJavaRawInfo() // #3404 xform java rawtypes into existentials resultPt = site.memberType(overridden) match { case PolyType(tparams, rt) => rt.substSym(tparams, tparamSyms) case mt => mt diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index ef2c3c3071..f1d0537f46 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package typechecker diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 72f6f1ae39..4b5de16a31 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package typechecker diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 8a7f4b0958..fabf2ed063 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package typechecker diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 1e8b89cb6f..f33e3506fd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package typechecker @@ -88,7 +87,7 @@ trait SyntheticMethods extends ast.TreeDSL { typer typed { DEF(method) === LIT(nargs) } } - /** Common code for productElement and productElementName + /** Common code for productElement and (currently disabled) productElementName */ def perElementMethod(accs: List[Symbol], methodName: Name, resType: Type, caseFn: Symbol => Tree): Tree = { val symToTpe = makeTypeConstructor(List(IntClass.tpe), resType) @@ -108,8 +107,8 @@ trait SyntheticMethods extends ast.TreeDSL { def productElementMethod(accs: List[Symbol]): Tree = perElementMethod(accs, nme.productElement, AnyClass.tpe, x => Ident(x)) - def productElementNameMethod(accs: List[Symbol]): Tree = - perElementMethod(accs, nme.productElementName, StringClass.tpe, x => Literal(x.name.toString)) + // def productElementNameMethod(accs: List[Symbol]): Tree = + // perElementMethod(accs, nme.productElementName, StringClass.tpe, x => Literal(x.name.toString)) def moduleToStringMethod: Tree = { val method = syntheticMethod(nme.toString_, FINAL, makeNoArgConstructor(StringClass.tpe)) diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index c2b6e7adf2..de9da9d814 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package typechecker diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index f503a797bb..aad80c1d8c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ //todo: rewrite or disllow new T where T is a mixin (currently: <init> not a member of T) //todo: use inherited type info also for vars and values @@ -2619,6 +2618,7 @@ trait Typers { self: Analyzer => (nme.ERROR, None) } else { names -= sym + if(isJava) sym.cookJavaRawInfo() // #3429 val annArg = tree2ConstArg(rhs, sym.tpe.resultType) (sym.name, annArg) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 6f432cc3c4..5bbda13acd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package typechecker @@ -100,13 +99,13 @@ trait Unapplies extends ast.TreeDSL } def copyUntyped[T <: Tree](tree: T): T = - returning[T](UnTyper traverse _)(tree.duplicate) + returning[T](tree.duplicate)(UnTyper traverse _) - def copyUntypedInvariant(td: TypeDef): TypeDef = - returning[TypeDef](UnTyper traverse _)( - treeCopy.TypeDef(td, td.mods &~ (COVARIANT | CONTRAVARIANT), td.name, - td.tparams, td.rhs).duplicate - ) + def copyUntypedInvariant(td: TypeDef): TypeDef = { + val copy = treeCopy.TypeDef(td, td.mods &~ (COVARIANT | CONTRAVARIANT), td.name, td.tparams, td.rhs) + + returning[TypeDef](copy.duplicate)(UnTyper traverse _) + } private def classType(cdef: ClassDef, tparams: List[TypeDef]): Tree = { val tycon = REF(cdef.symbol) diff --git a/src/compiler/scala/tools/nsc/typechecker/Variances.scala b/src/compiler/scala/tools/nsc/typechecker/Variances.scala index feaf57a541..7d0500d598 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Variances.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Variances.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package typechecker diff --git a/src/compiler/scala/tools/nsc/util/CharArrayReader.scala b/src/compiler/scala/tools/nsc/util/CharArrayReader.scala index 39a104fb14..907622e31f 100644 --- a/src/compiler/scala/tools/nsc/util/CharArrayReader.scala +++ b/src/compiler/scala/tools/nsc/util/CharArrayReader.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package util diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index c35b7139c6..4994542fdb 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package util @@ -247,7 +246,7 @@ abstract class ClassPath[T] { /** Filters for assessing validity of various entities. */ def validClassFile(name: String) = (name endsWith ".class") && context.isValidName(name) - def validPackage(name: String) = (name != "META-INF") && (name != "") && (name.head != '.') + def validPackage(name: String) = (name != "META-INF") && (name != "") && (name(0) != '.') def validSourceFile(name: String) = validSourceExtensions exists (name endsWith _) def validSourceExtensions = List(".scala", ".java") @@ -321,8 +320,7 @@ class DirectoryClassPath(val dir: AbstractFile, val context: ClassPathContext[Ab case f if f.isDirectory && validPackage(f.name) => new DirectoryClassPath(f, context) } toList - - override def toString() = "directory classpath: "+ dir.toString() + override def toString() = "directory classpath: "+ dir } /** diff --git a/src/compiler/scala/tools/nsc/util/DocStrings.scala b/src/compiler/scala/tools/nsc/util/DocStrings.scala index 7ca2722a54..06045daf3b 100755 --- a/src/compiler/scala/tools/nsc/util/DocStrings.scala +++ b/src/compiler/scala/tools/nsc/util/DocStrings.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id: ClassPath.scala 20028 2009-12-07 11:49:19Z cunei $ package scala.tools.nsc package util diff --git a/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala b/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala index 0c9fa6db72..714e731891 100644 --- a/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala +++ b/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package util diff --git a/src/compiler/scala/tools/nsc/util/HashSet.scala b/src/compiler/scala/tools/nsc/util/HashSet.scala index dc9ec73040..aa6e19538c 100644 --- a/src/compiler/scala/tools/nsc/util/HashSet.scala +++ b/src/compiler/scala/tools/nsc/util/HashSet.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package util @@ -27,7 +26,7 @@ class HashSet[T >: Null <: AnyRef](val label: String, initialCapacity: Int) exte private def index(x: Int): Int = math.abs(x % capacity) def findEntryOrUpdate(x: T): T = { - var h = index(x.hashCode()) + var h = index(x.##) var entry = table(h) while (entry ne null) { if (x == entry) @@ -43,7 +42,7 @@ class HashSet[T >: Null <: AnyRef](val label: String, initialCapacity: Int) exte } def findEntry(x: T): T = { - var h = index(x.hashCode()) + var h = index(x.##) var entry = table(h) while ((entry ne null) && entry != x) { h = index(h + 1) @@ -53,7 +52,7 @@ class HashSet[T >: Null <: AnyRef](val label: String, initialCapacity: Int) exte } def addEntry(x: T) { - var h = index(x.hashCode()) + var h = index(x.##) var entry = table(h) while (entry ne null) { if (entry == x) return @@ -77,7 +76,7 @@ class HashSet[T >: Null <: AnyRef](val label: String, initialCapacity: Int) exte } private def addOldEntry(x: T) { - var h = index(x.hashCode()) + var h = index(x.##) var entry = table(h) while (entry ne null) { h = index(h + 1) diff --git a/src/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala b/src/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala index ddefcc04ee..fa377a294d 100644 --- a/src/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala +++ b/src/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package util diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala index 806c885291..8d0ff37c44 100644 --- a/src/compiler/scala/tools/nsc/util/Position.scala +++ b/src/compiler/scala/tools/nsc/util/Position.scala @@ -3,7 +3,6 @@ * @author Martin Odersky * */ -// $Id$ package scala.tools.nsc package util diff --git a/src/compiler/scala/tools/nsc/util/RegexCache.scala b/src/compiler/scala/tools/nsc/util/RegexCache.scala index 5227b8ea4d..5c3197afa5 100644 --- a/src/compiler/scala/tools/nsc/util/RegexCache.scala +++ b/src/compiler/scala/tools/nsc/util/RegexCache.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Lex Spoon */ -// $Id$ package scala.tools.nsc package util diff --git a/src/compiler/scala/tools/nsc/util/Set.scala b/src/compiler/scala/tools/nsc/util/Set.scala index 8896ee02a5..c8ba3d27c9 100644 --- a/src/compiler/scala/tools/nsc/util/Set.scala +++ b/src/compiler/scala/tools/nsc/util/Set.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package util diff --git a/src/compiler/scala/tools/nsc/util/ShowPickled.scala b/src/compiler/scala/tools/nsc/util/ShowPickled.scala index b87d603570..82911892d9 100644 --- a/src/compiler/scala/tools/nsc/util/ShowPickled.scala +++ b/src/compiler/scala/tools/nsc/util/ShowPickled.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools package nsc diff --git a/src/compiler/scala/tools/nsc/util/SourceFile.scala b/src/compiler/scala/tools/nsc/util/SourceFile.scala index f9f3c5e5fe..8c1d308209 100644 --- a/src/compiler/scala/tools/nsc/util/SourceFile.scala +++ b/src/compiler/scala/tools/nsc/util/SourceFile.scala @@ -3,14 +3,15 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package util -import scala.tools.nsc.io.{AbstractFile, VirtualFile} +import io.{ AbstractFile, VirtualFile } import scala.collection.mutable.ArrayBuffer -import annotation.{ tailrec, switch } +import annotation.tailrec +import java.util.regex.Pattern +import java.io.IOException import Chars._ /** abstract base class of a source file used in the compiler */ @@ -18,6 +19,7 @@ abstract class SourceFile { def content : Array[Char] // normalized, must end in SU def file : AbstractFile def isLineBreak(idx : Int) : Boolean + def isSelfContained: Boolean def length : Int def position(offset: Int) : Position = { assert(offset < length) @@ -47,6 +49,42 @@ abstract class SourceFile { def identifier(pos: Position, compiler: Global): Option[String] = None } +object ScriptSourceFile { + /** Length of the script header from the given content, if there is one. + * The header begins with "#!" or "::#!" and ends with a line starting + * with "!#" or "::!#". + */ + def headerLength(cs: Array[Char]): Int = { + val headerPattern = Pattern.compile("""^(::)?!#.*(\r|\n|\r\n)""", Pattern.MULTILINE) + val headerStarts = List("#!", "::#!") + + if (headerStarts exists (cs startsWith _)) { + val matcher = headerPattern matcher cs.mkString + if (matcher.find) matcher.end + else throw new IOException("script file does not close its header with !# or ::!#") + } + else 0 + } + def stripHeader(cs: Array[Char]): Array[Char] = cs drop headerLength(cs) + + def apply(file: AbstractFile, content: Array[Char]) = { + val underlying = new BatchSourceFile(file, content) + val headerLen = headerLength(content) + val stripped = new ScriptSourceFile(underlying, content drop headerLen, headerLen) + + stripped + } +} +import ScriptSourceFile._ + +class ScriptSourceFile(underlying: BatchSourceFile, content: Array[Char], override val start: Int) extends BatchSourceFile(underlying.file, content) { + override def isSelfContained = false + + override def positionInUltimateSource(pos: Position) = + if (!pos.isDefined) super.positionInUltimateSource(pos) + else new OffsetPosition(underlying, pos.point + start) +} + /** a file whose contents do not change over time */ class BatchSourceFile(val file : AbstractFile, val content: Array[Char]) extends SourceFile { @@ -55,16 +93,13 @@ class BatchSourceFile(val file : AbstractFile, val content: Array[Char]) extends def this(file: AbstractFile, cs: Seq[Char]) = this(file, cs.toArray) override def equals(that : Any) = that match { - case that : BatchSourceFile => file.path == that.file.path + case that : BatchSourceFile => file.path == that.file.path && start == that.start case _ => false } - override def hashCode = file.path.hashCode + override def hashCode = file.path.## + start.## val length = content.length - - // in SourceFileFragments, these are overridden to compensate during offset calculation - // Invariant: length + start = underlyingLength - def underlyingLength = length def start = 0 + def isSelfContained = true override def identifier(pos: Position, compiler: Global) = if (pos.isDefined && pos.source == this && pos.point != -1) { @@ -82,13 +117,14 @@ class BatchSourceFile(val file : AbstractFile, val content: Array[Char]) extends else isLineBreakChar(ch) } - private lazy val lineIndices: Array[Int] = { + def calculateLineIndices(cs: Array[Char]) = { val buf = new ArrayBuffer[Int] buf += 0 - for (i <- 0 until content.length) if (isLineBreak(i)) buf += i + 1 - buf += content.length // sentinel, so that findLine below works smoother + for (i <- 0 until cs.length) if (isLineBreak(i)) buf += i + 1 + buf += cs.length // sentinel, so that findLine below works smoother buf.toArray } + private lazy val lineIndices: Array[Int] = calculateLineIndices(content) def lineToOffset(index : Int): Int = lineIndices(index) @@ -106,125 +142,4 @@ class BatchSourceFile(val file : AbstractFile, val content: Array[Char]) extends lastLine = findLine(0, lines.length, lastLine) lastLine } - -/** - - // An array which maps line numbers (counting from 0) to char offset into content - private lazy val lineIndices: Array[Int] = { - - val xs = content.indices filter isLineBreak map (_ + 1) toArray - val arr = new Array[Int](xs.length + 1) - arr(0) = 0 - System.arraycopy(xs, 0, arr, 1, xs.length) - - arr - } - // A reverse map which also hunts down the right answer on non-exact lookups - private class SparseReverser() { - val revMap = Map(lineIndices.zipWithIndex: _*) - - def apply(x: Int): Int = revMap.get(x) match { - case Some(res) => res - case _ => - var candidate = x - 1 - while (!revMap.contains(candidate)) - candidate -= 1 - - revMap(candidate) - } - } - private lazy val lineIndicesRev = new SparseReverser() - - def lineToOffset(index : Int): Int = lineIndices(index) - def offsetToLine(offset: Int): Int = lineIndicesRev(offset) - - */ -} - -/** A source file composed of multiple other source files. - * - * @version 1.0 - */ -class CompoundSourceFile( - name: String, - components: List[BatchSourceFile], - contents: Array[Char]) -extends BatchSourceFile(name, contents) -{ - /** The usual constructor. Specify a name for the compound file and - * a list of component sources. - */ - def this(name: String, components: BatchSourceFile*) = - this(name, components.toList, components flatMap (CompoundSourceFile stripSU _.content) toArray) - - /** Create an instance with the specified components and a generic name. */ - def this(components: BatchSourceFile*) = this("(virtual file)", components: _*) - - override def positionInUltimateSource(position: Position) = { - if (!position.isDefined) super.positionInUltimateSource(position) - else { - var off = position.point - var compsLeft = components - // the search here has to be against the length of the files underlying the - // components, not their advertised length (which in the case of a fragment is - // less than the underlying length.) Otherwise we can and will overshoot the - // correct component and return a garbage position. - while (compsLeft.head.underlyingLength-1 <= off && !compsLeft.tail.isEmpty) { - off = off - compsLeft.head.underlyingLength + 1 - compsLeft = compsLeft.tail - } - // now that we've identified the correct component, we have to adjust the - // position we report since it is expected relative to the fragment, not the - // underlying file. Thus, off - comp.start. - val comp = compsLeft.head - comp.positionInUltimateSource(new OffsetPosition(this, off - comp.start)) - } - } -} - -object CompoundSourceFile { - private[util] def stripSU(chars: Array[Char]) = - if (chars.length > 0 && chars.last == SU) - chars dropRight 1 - else - chars -} - - -/** One portion of an underlying file. The fragment includes - * the indices from the specified start (inclusively) to stop - * (not inclusively). - */ -class SourceFileFragment private ( - name: String, - underlyingFile: BatchSourceFile, - override val start: Int, - stop: Int, - contents: Array[Char]) -extends BatchSourceFile(name, contents) { - override def underlyingLength = underlyingFile.length - def this(name: String, underlyingFile: BatchSourceFile, start: Int, stop: Int) = - this( - name, - underlyingFile, - start, - stop, - { assert(start >= 0) - assert(start <= stop) - assert(start <= underlyingFile.length) - assert(stop <= underlyingFile.length) - underlyingFile.content.slice(start, stop).toArray }) - - def this(underlyingFile: BatchSourceFile, start: Int, stop: Int) = - this( - "(fragment of " + underlyingFile.file.name + ")", - underlyingFile, - start, - stop) - - override def positionInUltimateSource(position: Position) = - super.positionInUltimateSource( - if (position.isDefined) new OffsetPosition(this, position.point) - else position - ) } diff --git a/src/compiler/scala/tools/nsc/util/Statistics.scala b/src/compiler/scala/tools/nsc/util/Statistics.scala index 5aee76d946..de51c2778c 100644 --- a/src/compiler/scala/tools/nsc/util/Statistics.scala +++ b/src/compiler/scala/tools/nsc/util/Statistics.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package util diff --git a/src/compiler/scala/tools/nsc/util/TreeSet.scala b/src/compiler/scala/tools/nsc/util/TreeSet.scala index 86e44df684..522c99c4e0 100644 --- a/src/compiler/scala/tools/nsc/util/TreeSet.scala +++ b/src/compiler/scala/tools/nsc/util/TreeSet.scala @@ -2,7 +2,6 @@ * Copyright 2005-2010 LAMP/EPFL * @author Martin Odersky */ -// $Id$ package scala.tools.nsc package util diff --git a/src/compiler/scala/tools/nsc/util/package.scala b/src/compiler/scala/tools/nsc/util/package.scala new file mode 100644 index 0000000000..92d4eab54f --- /dev/null +++ b/src/compiler/scala/tools/nsc/util/package.scala @@ -0,0 +1,29 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2010 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools.nsc + +import java.io.{ OutputStream, PrintStream, ByteArrayOutputStream, PrintWriter, StringWriter } + +package object util { + /** Apply a function and return the passed value */ + def returning[T](x: T)(f: T => Unit): T = { f(x) ; x } + + /** Generate a string using a routine that wants to write on a stream. */ + def stringFromWriter(writer: PrintWriter => Unit): String = { + val stringWriter = new StringWriter() + val stream = new NewLinePrintWriter(stringWriter) + writer(stream) + stream.close() + stringWriter.toString + } + def stringFromStream(stream: OutputStream => Unit): String = { + val bs = new ByteArrayOutputStream() + val ps = new PrintStream(bs) + stream(ps) + ps.close() + bs.toString() + } +} diff --git a/src/compiler/scala/tools/util/AbstractTimer.scala b/src/compiler/scala/tools/util/AbstractTimer.scala index f91c964d26..b0ea663c47 100644 --- a/src/compiler/scala/tools/util/AbstractTimer.scala +++ b/src/compiler/scala/tools/util/AbstractTimer.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.util diff --git a/src/compiler/scala/tools/util/SocketConnection.scala b/src/compiler/scala/tools/util/SocketConnection.scala index 085d754300..040f2b2392 100644 --- a/src/compiler/scala/tools/util/SocketConnection.scala +++ b/src/compiler/scala/tools/util/SocketConnection.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.util diff --git a/src/compiler/scala/tools/util/SocketServer.scala b/src/compiler/scala/tools/util/SocketServer.scala index 7dcfd7efce..88d7013f36 100644 --- a/src/compiler/scala/tools/util/SocketServer.scala +++ b/src/compiler/scala/tools/util/SocketServer.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools.util diff --git a/src/compiler/scala/tools/util/StringOps.scala b/src/compiler/scala/tools/util/StringOps.scala index 6e5b3e54d3..1a42c32fc8 100644 --- a/src/compiler/scala/tools/util/StringOps.scala +++ b/src/compiler/scala/tools/util/StringOps.scala @@ -6,7 +6,6 @@ ** |/ ** \* */ -// $Id$ package scala.tools package util |