diff options
127 files changed, 3294 insertions, 1207 deletions
diff --git a/.classpath b/.classpath index 6494ce68fc..73b2108718 100644 --- a/.classpath +++ b/.classpath @@ -4,9 +4,12 @@ <classpathentry exported="true" kind="lib" path="build/quick/lib/compiler/"/> <classpathentry exported="true" kind="lib" path="lib/fjbg.jar"/> <classpathentry exported="true" kind="lib" path="lib/msil.jar"/> + <classpathentry exported="true" kind="lib" path="lib/jline.jar"/> <classpathentry exported="true" kind="lib" path="lib/ant-contrib.jar"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> <classpathentry exported="true" kind="lib" path="build/quick/lib/library" sourcepath="src/library"/> + <classpathentry exported="true" kind="lib" path="build/quick/lib/actors" sourcepath="src/actors"/> + <classpathentry exported="true" kind="lib" path="build/quick/lib/dbc" sourcepath="src/dbc"/> <classpathentry kind="output" path="build/quick/lib/compiler"/> </classpath> diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF index 65d696ebde..e0625c8cb1 100644 --- a/META-INF/MANIFEST.MF +++ b/META-INF/MANIFEST.MF @@ -1,22 +1,68 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: Scala Compiler -Bundle-SymbolicName: nsc;singleton:=true -Bundle-Version: 1.0.0 +Bundle-Name: Scala Distribution +Bundle-SymbolicName: scala;singleton:=true +Bundle-Version: 2.6.1.B1 Eclipse-LazyStart: true Bundle-ClassPath: lib/fjbg.jar, build/quick/lib/library/, + build/quick/lib/actors/, + build/quick/lib/dbc/, build/quick/lib/compiler/ Export-Package: ch.epfl.lamp.fjbg, scala, + scala.actors, + scala.actors.remote, scala.collection, - scala.runtime, + scala.collection.jcl, scala.collection.immutable, scala.collection.mutable, - scala.collection.jcl, + scala.dbc, + scala.dbc.datatype, + scala.dbc.exception, + scala.dbc.result, + scala.dbc.statement, + scala.dbc.statement.expression, + scala.dbc.syntax, + scala.dbc.value, + scala.dbc.vendor, + scala.compat, + scala.concurrent, + scala.io, + scala.mobile, + scala.ref, + scala.reflect, + scala.runtime, + scala.testing, + scala.text, scala.util, + scala.util.automata, + scala.util.grammar, + scala.util.logging, + scala.util.parsing, + scala.util.parsing.ast, + scala.util.parsing.combinator, + scala.util.parsing.combinator.lexical, + scala.util.parsing.combinator.syntactical, + scala.util.parsing.combinator.testing, + scala.util.parsing.combinator1, + scala.util.parsing.combinator1.lexical, + scala.util.parsing.combinator1.syntactical, + scala.util.parsing.combinator1.testing, + scala.util.parsing.input, + scala.util.parsing.json, + scala.util.parsing.syntax, + scala.util.regexp, + scala.xml, + scala.xml.dtd, + scala.xml.factory, + scala.xml.parsing, + scala.xml.path, + scala.xml.pull, + scala.xml.transform, scala.tools.nsc, scala.tools.nsc.util, + scala.tools.nsc.io, scala.tools.nsc.typechecker, scala.tools.nsc.symtab, scala.tools.nsc.ast, diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index 8822f52642..d0d66afb57 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -16,9 +16,8 @@ trait CompilationUnits { self: Global => * It typically corresponds to a single file of source code. It includes * error-reporting hooks. */ class CompilationUnit(val source: SourceFile) extends CompilationUnitTrait { - /** the fresh name creator */ - var fresh = new FreshNameCreator + var fresh : FreshNameCreator = new FreshNameCreator.Default /** the content of the compilation unit in tree form */ var body: Tree = EmptyTree @@ -28,6 +27,9 @@ trait CompilationUnits { self: Global => */ val depends = new HashSet[Symbol] + /** used to track changes in a signature */ + var pickleHash : Long = 0 + def position(pos: Int) = source.position(pos) /** The icode representation of classes in this compilation unit. @@ -38,14 +40,14 @@ trait CompilationUnits { self: Global => val errorPositions = new HashSet[Position] def error(pos: Position, msg: String) = - if (!(errorPositions contains pos)) { - errorPositions += pos + if (inIDE || !(errorPositions contains pos)) { + if (!inIDE) errorPositions += pos reporter.error((pos), msg) } def warning(pos: Position, msg: String) = - if (!(errorPositions contains pos)) { - errorPositions += pos + if (inIDE || !(errorPositions contains pos)) { + if (!inIDE) errorPositions += pos reporter.warning((pos), msg) } @@ -58,8 +60,8 @@ trait CompilationUnits { self: Global => else currentRun.uncheckedWarnings = true def incompleteInputError(pos: Position, msg:String) = - if (!(errorPositions contains pos)) { - errorPositions += pos + if (inIDE || !(errorPositions contains pos)) { + if (!inIDE) errorPositions += pos reporter.incompleteInputError((pos), msg) } diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 26d162cdeb..fa9354dc81 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -12,7 +12,7 @@ import java.nio.charset._ import compat.Platform.currentTime import scala.tools.nsc.io.{SourceReader, AbstractFile} import scala.tools.nsc.reporters._ -import scala.tools.nsc.util.{ClassPath, SourceFile} +import scala.tools.nsc.util.{ClassPath, SourceFile, BatchSourceFile} import scala.collection.mutable.{HashSet, HashMap, ListBuffer} @@ -112,9 +112,9 @@ class Global(var settings: Settings, var reporter: Reporter) extends Trees else null // reporting ------------------------------------------------------- - - def error(msg: String) = reporter.error(null, msg) - def warning(msg: String) = reporter.warning(null, msg) + import nsc.util.NoPosition + def error(msg: String) = reporter.error(NoPosition, msg) + def warning(msg: String) = reporter.warning(NoPosition, msg) def inform(msg: String) = Console.err.println(msg) def inform[T](msg: String, value: T): T = { inform(msg+value); value } @@ -200,7 +200,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends Trees } def getSourceFile(f: AbstractFile): SourceFile = - new SourceFile(f, reader.read(f)) + new BatchSourceFile(f, reader.read(f)) def getSourceFile(name: String): SourceFile = { val f = AbstractFile.getFile(name) @@ -216,7 +216,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends Trees getSourceFile(ret.sourceFile) } - object loaders extends SymbolLoaders { + val loaders = new SymbolLoaders { val global: Global.this.type = Global.this } @@ -246,6 +246,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends Trees if (settings.debug.value) inform("[running phase " + name + " on " + unit + "]") val unit0 = currentRun.currentUnit currentRun.currentUnit = unit + reporter.setSource(unit.source) if (!reporter.cancelled) apply(unit) currentRun.advanceUnit assert(currentRun.currentUnit == unit) @@ -266,6 +267,10 @@ class Global(var settings: Settings, var reporter: Reporter) extends Trees val global: Global.this.type = Global.this } + object generateIdeMaps extends GenerateIdeMaps { + val global: Global.this.type = Global.this + } + object superAccessors extends SuperAccessors { val global: Global.this.type = Global.this } @@ -382,6 +387,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends Trees protected def builtInPhaseDescriptors: List[SubComponent] = List( analyzer.namerFactory: SubComponent, // note: types are there because otherwise analyzer.typerFactory: SubComponent, // consistency check after refchecks would fail. + generateIdeMaps, // optionally generate .ide files from symbol info that can be used in the IDE superAccessors, // add super accessors pickler, // serializes symbol tables refchecks, // perform reference and override checking, translate nested objects @@ -503,7 +509,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends Trees private def addUnit(unit: CompilationUnit) { unitbuf += unit - fileset += unit.source.getFile() + fileset += unit.source.file } def units: Iterator[CompilationUnit] = unitbuf.elements @@ -587,8 +593,11 @@ class Global(var settings: Settings, var reporter: Reporter) extends Trees addUnit(unit) var localPhase = firstPhase.asInstanceOf[GlobalPhase] while ((localPhase.id < globalPhase.id || localPhase.id <= namerPhase.id) && !reporter.hasErrors) { + val oldSource = reporter.getSource + reporter.setSource(unit.source) atPhase(localPhase)(localPhase.applyPhase(unit)) localPhase = localPhase.next.asInstanceOf[GlobalPhase] + reporter.setSource(oldSource) } refreshProgress } @@ -690,6 +699,11 @@ class Global(var settings: Settings, var reporter: Reporter) extends Trees def forCLDC: Boolean = settings.target.value == "cldc" def forMSIL: Boolean = settings.target.value == "msil" def onlyPresentation = settings.doc.value - // used to disable caching in lampion IDE. - def inIDE = false + + override def inIDE = false + private val unpickleIDEHook0 : (( => Type) => Type) = f => f + def unpickleIDEHook : (( => Type) => Type) = unpickleIDEHook0 + def doPickleHash = false + /* hook for IDE to detect source from class dependencies */ + def attachSourceToClass(clazz : ClassSymbol, tpe : LazyType, sourceFile : AbstractFile) = clazz.sourceFile = sourceFile } diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala index 9f0b6ce7ab..06a16075ef 100644 --- a/src/compiler/scala/tools/nsc/Interpreter.scala +++ b/src/compiler/scala/tools/nsc/Interpreter.scala @@ -17,7 +17,7 @@ import scala.collection.mutable.{ListBuffer, HashSet, ArrayBuffer} import io.PlainFile import reporters.{ConsoleReporter, Reporter} import symtab.Flags -import util.{ClassPath, SourceFile} +import util.{SourceFile,BatchSourceFile,ClassPath} import nsc.{InterpreterResults=>IR} /** <p> @@ -59,6 +59,10 @@ import nsc.{InterpreterResults=>IR} */ class Interpreter(val settings: Settings, out: PrintWriter) { import symtab.Names + + /** the compiler to compile expressions with */ + val compiler: scala.tools.nsc.Global = newCompiler(settings, reporter) + import compiler.Traverser import compiler.{Tree, TermTree, ValOrDefDef, ValDef, DefDef, Assign, @@ -70,7 +74,8 @@ class Interpreter(val settings: Settings, out: PrintWriter) { /** construct an interpreter that reports to Console */ def this(settings: Settings) = - this(settings, new PrintWriter(new ConsoleWriter, true)) + this(settings, + new PrintWriter(new ConsoleWriter, true)) /** whether to print out result lines */ private var printResults: Boolean = true @@ -95,8 +100,8 @@ class Interpreter(val settings: Settings, out: PrintWriter) { /** directory to save .class files to */ val classfilePath = File.createTempFile("scalaint", "") - classfilePath.delete() // the file is created as a file; make it a directory - classfilePath.mkdirs() + classfilePath.delete // the file is created as a file; make it a directory + classfilePath.mkdirs /* set up the compiler's output directory */ settings.outdir.value = classfilePath.getPath @@ -108,10 +113,8 @@ class Interpreter(val settings: Settings, out: PrintWriter) { /** Instantiate a compiler. Subclasses can override this to * change the compiler class used by this interpreter. */ protected def newCompiler(settings: Settings, reporter: Reporter) - = new Global(settings, reporter) + = new scala.tools.nsc.Global(settings, reporter) - /** the compiler to compile expressions with */ - val compiler: Global = newCompiler(settings, reporter) /** the compiler's classpath, as URL's */ val compilerClasspath: List[URL] = @@ -350,7 +353,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { def simpleParse(code: String): List[Tree] = { val unit = new CompilationUnit( - new SourceFile("<console>", code.toCharArray())) + new BatchSourceFile("<console>", code.toCharArray())) val scanner = new compiler.syntaxAnalyzer.UnitParser(unit); val xxx = scanner.templateStatSeq; xxx._2 @@ -384,7 +387,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { * compilation errors, or false otherwise. */ def compileString(code: String): Boolean = - compileSources(List(new SourceFile("<script>", code.toCharArray))) + compileSources(List(new BatchSourceFile("<script>", code.toCharArray))) /** Build a request from the user. <code>trees</code> is <code>line</code> * after being parsed. @@ -701,7 +704,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { val objRun = new compiler.Run() //println("source: "+objectSourceCode) //DEBUG objRun.compileSources( - List(new SourceFile("<console>", objectSourceCode.toCharArray)) + List(new BatchSourceFile("<console>", objectSourceCode.toCharArray)) ) if (reporter.hasErrors) return false @@ -711,7 +714,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { // compile the result-extraction object new compiler.Run().compileSources( - List(new SourceFile("<console>", resultObjectSourceCode.toCharArray)) + List(new BatchSourceFile("<console>", resultObjectSourceCode.toCharArray)) ) // success diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala index 3266ec3799..e8f3cebb99 100644 --- a/src/compiler/scala/tools/nsc/ScriptRunner.scala +++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala @@ -14,7 +14,7 @@ import java.util.jar.{JarEntry, JarOutputStream} import scala.tools.nsc.io.PlainFile import scala.tools.nsc.reporters.{Reporter,ConsoleReporter} -import scala.tools.nsc.util.{ClassPath, CompoundSourceFile, SourceFile, SourceFileFragment} +import scala.tools.nsc.util.{ClassPath, CompoundSourceFile, BatchSourceFile, SourceFile, SourceFileFragment} /** An object that runs Scala code in script files. * @@ -185,18 +185,17 @@ class ScriptRunner { getSourceFile: PlainFile => SourceFile): SourceFile = { val preamble = - new SourceFile("<script preamble>", + new BatchSourceFile("<script preamble>", preambleCode(objectName).toCharArray) val middle = { val f = new File(filename) new SourceFileFragment( - getSourceFile(new PlainFile(f)), + getSourceFile(new PlainFile(f)).asInstanceOf[BatchSourceFile], headerLength(filename), f.length.asInstanceOf[Int]) } - - val end = new SourceFile("<script trailer>", endCode.toCharArray) + val end = new BatchSourceFile("<script trailer>", "\n} }\n".toCharArray) new CompoundSourceFile(preamble, middle, end) } diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala index 9f656e7906..52258b3ae6 100644 --- a/src/compiler/scala/tools/nsc/Settings.scala +++ b/src/compiler/scala/tools/nsc/Settings.scala @@ -84,21 +84,22 @@ class Settings(error: String => Unit) { new java.io.ByteArrayOutputStream()).getEncoding val debuginfo = new DebugSetting ("-g", "Specify level of generated debugging info", List("none", "source", "line", "vars", "notc"), "vars", "vars") - val nowarnings = BooleanSetting ("-nowarn", "Generate no warnings") - val verbose = BooleanSetting ("-verbose", "Output messages about what the compiler is doing") - val deprecation = BooleanSetting ("-deprecation", "Output source locations where deprecated APIs are used") - val unchecked = BooleanSetting ("-unchecked", "Enable detailed unchecked warnings") + val nowarnings = BooleanSetting ("-nowarn", "Generate no warnings").hideToIDE + val verbose = BooleanSetting ("-verbose", "Output messages about what the compiler is doing").hideToIDE + val deprecation = BooleanSetting ("-deprecation", "Output source locations where deprecated APIs are used").hideToIDE + val unchecked = BooleanSetting ("-unchecked", "Enable detailed unchecked warnings").hideToIDE + val noide = BooleanSetting ("-noide", "Do not generate class-source mappings that are used by the Scala IDE").hideToIDE val classpath = new StringSetting ("-classpath", "path", "Specify where to find user class files", classpathDefault) { override val abbreviation = "-cp" } val sourcepath = StringSetting ("-sourcepath", "path", "Specify where to find input source files", "") val bootclasspath = StringSetting ("-bootclasspath", "path", "Override location of bootstrap class files", bootclasspathDefault) val extdirs = StringSetting ("-extdirs", "dirs", "Override location of installed extensions", extdirsDefault) val outdir = StringSetting ("-d", "directory", "Specify where to place generated class files", ".") - val encoding = StringSetting ("-encoding", "encoding", "Specify character encoding used by source files", encodingDefault).showToIDE + val encoding = StringSetting ("-encoding", "encoding", "Specify character encoding used by source files", encodingDefault) val target = ChoiceSetting ("-target", "Specify for which target object files should be built", List("jvm-1.5", "jvm-1.4", "msil", "cldc"), "jvm-1.4") - val printLate = BooleanSetting ("-print", "Print program with all Scala-specific features removed") + val printLate = BooleanSetting ("-print", "Print program with all Scala-specific features removed").hideToIDE val XO = BooleanSetting ("-optimise", "Generates faster bytecode by applying optimisations to the program") - val explaintypes = BooleanSetting ("-explaintypes", "Explain type errors in more detail") - val uniqid = BooleanSetting ("-uniqid", "Print identifiers with unique names for debugging") + val explaintypes = BooleanSetting ("-explaintypes", "Explain type errors in more detail").hideToIDE + val uniqid = BooleanSetting ("-uniqid", "Print identifiers with unique names for debugging").hideToIDE val version = BooleanSetting ("-version", "Print product version and exit").hideToIDE val help = BooleanSetting ("-help", "Print a synopsis of standard options").hideToIDE val Xhelp = BooleanSetting ("-X", "Print a synopsis of advanced options").hideToIDE @@ -113,18 +114,18 @@ class Settings(error: String => Unit) { val Xplugtypes = BooleanSetting ("-Xplug-types", "Process annotations on types") val plugin = MultiStringSetting("-Xplugin", "file", "Load a plugin from a file") val disable = MultiStringSetting("-Xplugin-disable", "plugin", "Disable a plugin") - val showPlugins = BooleanSetting ("-Xplugin-list", "Print a synopsis of loaded plugins") + val showPlugins = BooleanSetting ("-Xplugin-list", "Print a synopsis of loaded plugins").hideToIDE val pluginOptions = new MultiStringSetting("-P", "plugin:opt", "Pass an option to a plugin") { override def helpSyntax = "-P:<plugin>:<opt>" } val require = MultiStringSetting("-Xplugin-require", "plugin", "Abort unless a plugin is available") val pluginsDir = StringSetting ("-Xpluginsdir", "path", "Location to find compiler plugins", pluginsDirDefault) val print = PhasesSetting ("-Xprint", "Print out program after") - val Xprintpos = BooleanSetting ("-Xprint-pos", "Print tree positions (as offsets)") + val Xprintpos = BooleanSetting ("-Xprint-pos", "Print tree positions (as offsets)").hideToIDE val printtypes = BooleanSetting ("-Xprint-types", "Print tree types (debugging option)").hideToIDE val prompt = BooleanSetting ("-Xprompt", "Display a prompt after each error (debugging option)").hideToIDE val resident = BooleanSetting ("-Xresident", "Compiler stays resident, files to compile are read from standard input").hideToIDE val Xshowcls = StringSetting ("-Xshow-class", "class", "Show class info", "") val Xshowobj = StringSetting ("-Xshow-object", "object", "Show object info", "") - val showPhases = BooleanSetting ("-Xshow-phases", "Print a synopsis of compiler phases") + val showPhases = BooleanSetting ("-Xshow-phases", "Print a synopsis of compiler phases").hideToIDE val sourceReader = StringSetting ("-Xsource-reader", "classname", "Specify a custom method for reading source files", "scala.tools.nsc.io.SourceReader") val Yhelp = BooleanSetting ("-Y", "Print a synopsis of private options").hideToIDE @@ -141,12 +142,12 @@ class Settings(error: String => Unit) { val inline = BooleanSetting ("-Yinline", "Perform inlining when possible") val Xlinearizer = ChoiceSetting ("-Ylinearizer", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo") val log = PhasesSetting ("-Ylog", "Log operations in") - val logAll = BooleanSetting ("-Ylog-all", "Log all operations") + val logAll = BooleanSetting ("-Ylog-all", "Log all operations").hideToIDE val Xmatchalgo = ChoiceSetting ("-Ymatch-algo", "which match algorithm to use", List("both","par","incr"), "both") val noimports = BooleanSetting ("-Yno-imports", "Compile without any implicit imports") val nopredefs = BooleanSetting ("-Yno-predefs", "Compile without any implicit predefined values") val script = StringSetting ("-Xscript", "object", "compile as a script, wrapping the code into object.main()", "").hideToIDE - val Xshowtrees = BooleanSetting ("-Yshow-trees", "Show detailed trees when used in connection with -print:phase") + val Xshowtrees = BooleanSetting ("-Yshow-trees", "Show detailed trees when used in connection with -print:phase").hideToIDE val skip = PhasesSetting ("-Yskip", "Skip") val Xsqueeze = ChoiceSetting ("-Ysqueeze", "if on, creates compact code in matching", List("on","on","off"), "on") val statistics = BooleanSetting ("-Ystatistics", "Print compiler statistics").hideToIDE diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala index 1533013e21..05c65f4671 100644 --- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala @@ -223,7 +223,8 @@ abstract class NodePrinters { printcln("Super(\"" + qual + "\", \"" + mix + "\")" + nodeinfo2(tree)) case Template(parents, self, body) => println("Template(" + nodeinfo(tree)) - println(" " + parents.map(p => p.tpe.typeSymbol) + ", // parents") + println(" " + parents.map(p => if (p.tpe ne null) p.tpe.typeSymbol else "null-" + p) + ", // parents") + traverse(self, level + 2, true) if (body.isEmpty) println(" List() // no body") else { diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala index ef29cf04f9..2fa44c2dc8 100644 --- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala @@ -293,7 +293,7 @@ abstract class TreePrinters { print(fun); printRow(targs, "[", ", ", "]") case Apply(fun, vargs) => - print(fun); printRow(vargs, "(", ", ", ")") + print(fun); print(vargs.mkString("(", ",", ")")) // printRow(vargs, "(", ", ", ")") case ApplyDynamic(qual, vargs) => print("<apply-dynamic>("); print(qual); print("#"); print(tree.symbol.nameString) @@ -362,6 +362,7 @@ abstract class TreePrinters { print(tpt); printColumn(whereClauses, " forSome { ", ";", "}") + case tree : StubTree => print(tree.toString) case tree => print("<unknown tree of class "+tree.getClass+">") } diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index acd3805ee7..1949c4cc7c 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -157,6 +157,26 @@ abstract class Trees extends SymbolTable { case t: Tree => this eq t case _ => false } + def hashCodeStructure : Int = { + var hc = getClass.hashCode + def f(what : Any) : Unit = what match { + case what : Tree => hc += what.hashCodeStructure + case what : Iterable[_] => what.foreach(f) + case what : Product => g(what) + case null => + case what => hc += what.hashCode + } + def g(what : Product) : Unit = { + hc += what.productArity + var i = 0 + while (i < what.productArity) { + f(what.productElement(i)) + i += 1 + } + } + g(this.asInstanceOf[Product]) + hc + } def equalsStructure(that: Tree): Boolean = { if (this == that) return true @@ -181,8 +201,7 @@ abstract class Trees extends SymbolTable { val results = for (i <- 0.until(this0.productArity).toList) yield equals0(this0.productElement(i), that0.productElement(i)) val b = results.foldLeft(true)((x,y) => x && y) - b && (if (tpe == null || tpe == NoType) that.tpe == null || that.tpe == NoType - else tpe == that.tpe) + b // ignore type! } def duplicate: this.type = @@ -465,6 +484,10 @@ abstract class Trees extends SymbolTable { extends Tree { override def symbol: Symbol = definition.symbol override def symbol_=(sym: Symbol) { definition.symbol = sym } + // sean: seems to be important to the IDE + override def isDef = definition.isDef + override def isTerm = definition.isTerm + override def isType = definition.isType } /** Instantiation template @@ -759,6 +782,9 @@ abstract class Trees extends SymbolTable { case class ExistentialTypeTree(tpt: Tree, whereClauses: List[Tree]) extends TypTree + trait StubTree extends Tree { + override def equalsStructure(that: Tree): Boolean = this eq that + } /* A standard pattern match case EmptyTree => case PackageDef(name, stats) => @@ -1325,6 +1351,7 @@ abstract class Trees extends SymbolTable { copy.TypeBoundsTree(tree, transform(lo), transform(hi)) case ExistentialTypeTree(tpt, whereClauses) => copy.ExistentialTypeTree(tree, transform(tpt), transformTrees(whereClauses)) + case tree : StubTree => tree.duplicate } def transformTrees(trees: List[Tree]): List[Tree] = @@ -1467,6 +1494,7 @@ abstract class Trees extends SymbolTable { traverse(lo); traverse(hi) case ExistentialTypeTree(tpt, whereClauses) => traverse(tpt); traverseTrees(whereClauses) + case tree : StubTree => } def traverseTrees(trees: List[Tree]) { diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala index 038d993c45..a6c3d85d71 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala @@ -7,7 +7,7 @@ package scala.tools.nsc.ast.parser import scala.collection.mutable -import scala.tools.nsc.util.{Position,SourceFile} +import scala.tools.nsc.util.{Position,NoPosition,SourceFile} import scala.xml.{Text, TextBuffer} import SourceFile.{SU,LF} @@ -16,9 +16,7 @@ import SourceFile.{SU,LF} * @author Burak Emir * @version 1.0 */ -trait MarkupParsers { - self: SyntaxAnalyzer => - +trait MarkupParsers {self: Parsers => case object MissingEndTagException extends RuntimeException { override def getMessage = "start tag was here: " } @@ -34,32 +32,21 @@ trait MarkupParsers { import global._ //import posAssigner.atPos - class MarkupParser(p: UnitParser, presWS: Boolean) /*with scala.xml.parsing.MarkupParser[Tree,Tree] */{ + class MarkupParser(parser: UnitParser, presWS: Boolean) /*with scala.xml.parsing.MarkupParser[Tree,Tree] */{ import Tokens.{EMPTY, LBRACE, RBRACE} + import parser.i2p final val preserveWS = presWS + var input : ScannerInput = _ - import p.{symbXMLBuilder => handle} - def s = p.in - import p.in.g2p - import p.in.p2g - import p.in.token - - /** holds the position in the source file */ - /*[Duplicate]*/ var pos: Position = _ - - /** holds temporary values of pos */ - /*[Duplicate]*/ var tmppos: Position = _ - - /** holds the next character */ - /*[Duplicate]*/ var ch: Char = _ + import parser.{symbXMLBuilder => handle} - /** character buffer, for names */ - /*[Duplicate]*/ protected val cbuf = new StringBuilder() - - /** append Unicode character to name buffer*/ - /*[Duplicate]*/ protected def putChar(c: Char) = cbuf.append(c) + def pos : Int = input.offset + var tmppos : Position = NoPosition + def ch = input.head + /** this method assign the next character to ch and advances in input */ + def nextch = input.next // { s.in.next; /*s.xNext;*/ ch = s.in.ch ; pos = s.in.cpos } /*[Duplicate]*/ var xEmbeddedBlock = false @@ -74,7 +61,7 @@ trait MarkupParsers { else reportSyntaxError("'" + that + "' expected instead of '" + ch + "'") } - var debugLastStartElement = new mutable.Stack[(Position, String)] + var debugLastStartElement = new mutable.Stack[(Int, String)] /** checks whether next character starts a Scala block, if yes, skip it. * @return true if next character starts a scala block @@ -109,7 +96,7 @@ trait MarkupParsers { } catch { case e => reportSyntaxError("error parsing attribute value") - p.errorTermTree + parser.errorTermTree } case '{' => @@ -138,14 +125,14 @@ trait MarkupParsers { * @param endch either ' or " */ /*[Duplicate]*/ def xAttributeValue(endCh: Char): String = { + val buf = new StringBuilder while (ch != endCh) { if (ch == SU) throw TruncatedXML - putChar(ch) - nextch + buf append nextch } - val str = cbuf.toString() - cbuf.length = 0 + val str = buf.toString() + // @todo: normalize attribute value // well-formedness constraint if (str.indexOf('<') != -1) { @@ -430,20 +417,19 @@ trait MarkupParsers { /*[Duplicate]*/ def xName: String = { if (ch == SU) { throw TruncatedXML - } else if ( !xml.Parsing.isNameStart(ch)) { reportSyntaxError("name expected, but char '"+ch+"' cannot start a name") return "" } + val buf = new StringBuilder do { - putChar(ch) - nextch + buf append nextch } while (xml.Parsing.isNameChar(ch)) - if (':' == cbuf.charAt(cbuf.length-1)) { + if (':' == buf.last) { reportSyntaxError( "name cannot end in ':'" ) - cbuf.length = cbuf.length - 1 + buf.setLength(buf.length - 1) } - val n = cbuf.toString().intern() - cbuf.length = 0 + val n = buf.toString().intern() + //cbuf.length = 0 n } @@ -494,8 +480,9 @@ trait MarkupParsers { // return "" //} else { var exit = false + val buf = new StringBuilder while (!exit && (ch!=SU)) { - putChar(ch) + buf append ch val expectRBRACE = ch == '}' // TODO check for "}}" nextch @@ -509,8 +496,8 @@ trait MarkupParsers { } exit = xCheckEmbeddedBlock ||(ch == '<') || (ch == '&') } - val str = cbuf.toString() - cbuf.length = 0 + val str = buf.toString() + //cbuf.length = 0 str //} } @@ -525,64 +512,55 @@ trait MarkupParsers { * precondition: s.xStartsXML == true */ def xLiteral: Tree = try { - init; pushScannerState + input = parser.in.flush handle.isPattern = false - val pos = s.currentPos - var lastend = 0 - var lastch = ch + + //val pos = s.currentPos var tree:Tree = null val ts = new mutable.ArrayBuffer[Tree]() - tmppos = pos // Iuli: added this line, as it seems content_LT uses tmppos when creating trees + tmppos = (pos) // Iuli: added this line, as it seems content_LT uses tmppos when creating trees + assert(nextch == '<') content_LT(ts) //Console.println("xLiteral:ts = "+ts.toList) - lastend = s.in.bp - lastch = s.in.ch + //lastend = s.in.bp + //lastch = s.in.ch //if (settings.debug.value) { // Console.println("DEBUG 1: I am getting char '"+ch+"' at lastend "+lastend+" pos = "+pos); // DEBUG //} + val save = input.offset xSpaceOpt // parse more XML ? if (ch == '<') { - //val ts = new mutable.ArrayBuffer[Tree](); - //ts.append( tree ); while (ch == '<') { nextch ts.append(element) - lastend = s.in.bp - lastch = s.in.ch xSpaceOpt } tree = handle.makeXMLseq((pos), ts) + parser.in.resume(Tokens.XMLSTART) } else { + parser.in.seek(save, Tokens.XMLSTART) assert(ts.length == 1) tree = ts(0) } - s.in.bp = lastend // ugly hack - s.in.ch = lastch - //if (settings.debug.value) { - // Console.println("DEBUG 2: restoring char '"+lastch+"' at lastend "+lastend+" pos = "+pos); // DEBUG - //} - //Console.println("out of xLiteral, parsed:"+tree.toString()); - s.next.token = Tokens.EMPTY; - s.nextToken - popScannerState tree - } - catch { + } catch { case c @ TruncatedXML => - s.incompleteInputError(s.in.cpos-1, c.getMessage) - s.nextToken + parser.incompleteInputError(c.getMessage) + parser.in.resume(Tokens.XMLSTART) EmptyTree case c @ (MissingEndTagException | ConfusedAboutBracesException) => - p.syntaxError((debugLastStartElement.top._1), - c.getMessage + debugLastStartElement.top._2+">") + parser.syntaxError((debugLastStartElement.top._1):Int, + c.getMessage + debugLastStartElement.top._2+">") + parser.in.resume(Tokens.XMLSTART) EmptyTree case _:ArrayIndexOutOfBoundsException => - p.syntaxError((debugLastStartElement.top._1), + parser.syntaxError((debugLastStartElement.top._1), "missing end tag in XML literal for <" +debugLastStartElement.top._2+">"); + parser.in.resume(Tokens.XMLSTART) EmptyTree } @@ -591,92 +569,96 @@ trait MarkupParsers { * precondition: s.xStartsXML == true */ def xLiteralPattern: Tree = try { - init; pushScannerState + input = parser.in.flush val oldMode = handle.isPattern; handle.isPattern = true + assert(nextch == '<') var tree = xPattern; xSpaceOpt; handle.isPattern = oldMode; - s.next.token = Tokens.EMPTY; - s.nextToken - popScannerState + parser.in.resume(Tokens.XMLSTART) tree } catch { case c @ TruncatedXML => - s.incompleteInputError(s.in.cpos-1, c.getMessage) - s.nextToken + parser.syntaxError(pos - 1, c.getMessage) + //s.nextToken + parser.in.resume(Tokens.XMLSTART) EmptyTree case c @ (MissingEndTagException | ConfusedAboutBracesException) => - p.syntaxError((debugLastStartElement.top._1), + parser.syntaxError((debugLastStartElement.top._1), c.getMessage + debugLastStartElement.top._2+">") EmptyTree case _:ArrayIndexOutOfBoundsException => - p.syntaxError((debugLastStartElement.top._1), + parser.syntaxError((debugLastStartElement.top._1), "missing end tag in XML literal for <" +debugLastStartElement.top._2+">") EmptyTree } def xEmbeddedExpr: Tree = { - sync - val b = p.block() //p.expr(true,false); - if (s.in.ch == SU) - throw TruncatedXML - if (/*s.*/token != RBRACE) { + xEmbeddedBlock = false + parser.in.resume(LBRACE) + val b = parser.block() //p.expr(true,false); + if (parser.in.token != RBRACE) { + input = parser.in.flush reportSyntaxError(" expected end of Scala block") + } else { + input = parser.in.flush + assert(nextch == '}') } - init b } /** xScalaPatterns ::= patterns */ def xScalaPatterns: List[Tree] = { - sync - val b = p.patterns(true) - if (s.in.ch == SU) - throw TruncatedXML - if (/*s.*/token != RBRACE) { - reportSyntaxError(" expected end of Scala patterns") + xEmbeddedBlock = false + parser.in.resume(LBRACE) + val b = parser.patterns(true) + if (parser.in.token != RBRACE) { + input = parser.in.flush + reportSyntaxError(" expected end of Scala pattern") + } else { + input = parser.in.flush + assert(nextch == '}') } - init b } //var ch: Char = _; - /** this method assign the next character to ch and advances in input */ - def nextch { s.in.next; /*s.xNext;*/ ch = s.in.ch ; pos = s.in.cpos } //def lookahead = { s.xLookahead } var scannerState: List[List[Int]] = Nil +/* private def pushScannerState { scannerState = s.sepRegions :: scannerState s.sepRegions = Nil } - private def popScannerState { s.sepRegions = scannerState.head scannerState = scannerState.tail } - + */ +/* private def init { ch = s.in.ch pos = s.in.cpos } + */ def reportSyntaxError(str: String) = { - p.syntaxError(pos-1, "in XML literal: " + str) + parser.syntaxError(pos - 1, "in XML literal: " + str) nextch } - +/* private def sync { xEmbeddedBlock = false s.xSync } - +*/ /** '<' xPattern ::= Name [S] { xmlPattern | '{' pattern3 '}' } ETag * | Name [S] '/' '>' */ @@ -710,7 +692,7 @@ trait MarkupParsers { } case '{' => // embedded Scala patterns while (ch == '{') { - s.in.next + nextch ts ++= xScalaPatterns } // postcond: xEmbeddedBlock = false; diff --git a/src/compiler/scala/tools/nsc/ast/parser/NewScanners.scala b/src/compiler/scala/tools/nsc/ast/parser/NewScanners.scala new file mode 100644 index 0000000000..8b312cab1d --- /dev/null +++ b/src/compiler/scala/tools/nsc/ast/parser/NewScanners.scala @@ -0,0 +1,870 @@ +package scala.tools.nsc.ast.parser +import scala.tools.nsc.util.SourceFile._ +import scala.tools.nsc.util._ + +trait NewScanners { + val global : Global + import global._ + import Tokens._ + trait CoreScannerInput extends BufferedIterator[Char] { + private[NewScanners] val scratch = new StringBuilder + def readIfStartsWith(c : Char) : Boolean = + if (head == c) { next; true } else false + def readIfStartsWith(c0 : Char, c1 : Char) : Boolean = + if (head == c0 && peek(1) == c1) { + next; next; true + } else false + def startsWith(c0: Char, c1 : Char) : Boolean = head == c0 && peek(1) == c1 + def isUnicode : Boolean + + def peek(idx : Int) : Char + + def offset : Int + def error(offset : Int, msg : String) : Unit + def textFor(from : Int, until : Int) : RandomAccessSeq[Char] + } + trait ScannerInput extends CoreScannerInput { + def seek(offset : Int) : Unit + } + class DefaultInput(in : NewCharArrayReader) extends ScannerInput { + import scala.collection.mutable._ + def seek(offset : Int) = in.seek(offset) + def offset = in.offset + def head = peek(0) + def next = in.next + def isUnicode : Boolean = in.isUnicode + def hasNext = in.hasNext + def peek(idx : Int) = { + val offset = in.offset + var jdx = idx + var result = in.next + while (jdx > 0) { + jdx = jdx - 1 + result =in.next + } + in.seek(offset) // jump back to old position + result + } + def error(offset : Int, msg : String) : Unit = {} + def textFor(from : Int, until : Int) = in.buf.slice(from, until).mkString + } + + abstract class ParserScanner extends BaseScanner { + def init = nextToken + + private var doc : String = "" + var sepRegions : List[Int] = Nil + private val current = new TokenHolder + private val next = new TokenHolder + implicit def in : ScannerInput + + var lastCode = EMPTY + next.code = EMPTY + current.code = EMPTY + def hasNext = in.hasNext || (next.code != EMPTY && next.code != EOF) + def flush : ScannerInput = { + assert(current.code != EMPTY) + in.seek(unadjust(current.offset)) + current.code = EMPTY + next.code = EMPTY + in + } + def seek(offset : Int, lastCode : Int) = { + assert(current.code == EMPTY) + in.seek(unadjust(offset)) + this.lastCode = lastCode + nextToken + } + def resume(lastCode : Int) = { + assert(current.code == EMPTY) + this.lastCode = lastCode + nextToken + } + /** read next token and return last position + */ + def skipToken: Int = { + val p = current.offset; nextToken + // XXX: account for off by one error //??? + p + } + def currentPos = { + assert(current.code != EMPTY) + current.offset + } + def fillNext : Boolean = { + assert(next.code == EMPTY) + var hasNewline = false + do { + fill(next) + } while (next.code match { + case NEWLINE|NEWLINES|WHITESPACE|COMMENT => + assert((next.code != COMMENT) == (xmlOk)) + hasNewline = hasNewline || next.code == NEWLINE || next.code == NEWLINES + if (next.code == COMMENT) + doc = next.value.asInstanceOf[Option[String]].getOrElse("") + true + case _ => false + }) + hasNewline + } + def flushDoc = { + val ret = doc + doc = "" + ret + } + + def nextToken : Unit = { + if (current.code == EOF) return // nothing more. + var lastIsComment = false + lastCode = current.code match { + case WHITESPACE|EMPTY => lastCode + case COMMENT => lastIsComment = true; lastCode + case code => code + } + // push on braces + val pushOn = current.code match { + case LBRACE => RBRACE + case LPAREN => RPAREN + case LBRACKET => RBRACKET + case CASE => ARROW + case RBRACE => + while (!sepRegions.isEmpty && sepRegions.head != RBRACE) + sepRegions = sepRegions.tail + if (!sepRegions.isEmpty) + sepRegions = sepRegions.tail + EMPTY + case code @ (ARROW) if (!sepRegions.isEmpty && sepRegions.head == code) => + sepRegions = sepRegions.tail + EMPTY + case code @ (RPAREN|RBRACKET) => + if (!sepRegions.isEmpty && sepRegions.head == code) + sepRegions = sepRegions.tail + EMPTY + case _ => EMPTY + } + if (pushOn != EMPTY) sepRegions = pushOn :: sepRegions + + if (next.code != EMPTY) { + current.copy(next) + next.code = EMPTY + } else fill(current) + + def currentIsNext : Unit = { + assert(next.code != EMPTY) + return nextToken + } + current.code match { + case CASE|SEMI => + fillNext + (current.code,next.code) match { + case (CASE,OBJECT) => + assert(true) + current.code = CASEOBJECT; next.code = EMPTY + case (CASE, CLASS) => current.code = CASECLASS ; next.code = EMPTY + case (SEMI, ELSE ) => currentIsNext + case _ => + } + case WHITESPACE|COMMENT => + if (current.code == COMMENT) + doc = current.value.asInstanceOf[Option[String]].getOrElse("") + nextToken + case NEWLINE | NEWLINES => + assert(xmlOk) + val headIsRBRACE = if (sepRegions.isEmpty) true else sepRegions.head == RBRACE + val hasNewline = fillNext + if (headIsRBRACE && ((inLastOfStat(lastCode) && inFirstOfStat(next.code)) || next.code == EOF)) { + //if (hasNewline) current.code = NEWLINES + } else { + currentIsNext + } + case _ => + } + } + def token = { + assert(current.code != EMPTY) + current.code + } + def nextTokenCode = { + if (next.code == EMPTY) fillNext + next.code + } + def name = current.value.get.asInstanceOf[Name] + def charVal = current.value.get.asInstanceOf[Char] + def intVal(negated : Boolean) : Long = { + val base = current.value.asInstanceOf[Option[Int]].getOrElse(10) + intVal(current.offset, current.code, current.nLit(this), negated, base) + } + def intVal : Long = intVal(false) + def floatVal(negated: Boolean): Double = { + floatVal(current.offset, current.code, current.nLit(this), negated) + } + def floatVal : Double = floatVal(false) + def stringVal = current.value.get.asInstanceOf[String] + } + + class TokenHolder { + var offset : Int = 0 + var code : Int = 0 + var length : Int = 0 + var value : Option[Any] = None + def copy(from : TokenHolder) = { + this.offset = from.offset + this.code = from.code + this.length = from.length + this.value = from.value + } + def set(offset : Int, length : Int, code : Int) = { + this.offset = offset; this.length = length; this.code = code; this.value = None + } + def set(offset : Int, length : Int, code : Int, value : Any) = { + this.offset = offset; this.length = length; this.code = code; this.value = Some(value) + } + def nLit(implicit in : BaseScanner) = (in.in.textFor(in.unadjust(offset), in.unadjust(offset + length))) + } + + trait BaseScanner { + implicit def in : CoreScannerInput + ScannerConfiguration.hashCode // forces initialization + import ScannerConfiguration._ + var xmlOk = false + + def iterator = new Iterator[(Int,Int,Int)] { // offset,length,code + val current = new TokenHolder + def hasNext = in.hasNext + def next = { + fill(current) + (current.offset, current.length, current.code) + } + } + // IDE hooks + def adjust(offset : Int) = offset + def unadjust(offset : Int) = offset + def identifier(name : Name) = name + + protected def fill(current : TokenHolder) : Unit = { + if (!in.hasNext) { + current.offset = adjust(in.offset) + current.code = EOF + return + } + val oldXmlOk = xmlOk + xmlOk = false + val offset = in.offset // call "after" next + def escapeCode(offset : Int) : Char = in.next match { + case c if simpleEscape.isDefinedAt(c) => simpleEscape(c) + case c if isDigit(c) => + val length = in.scratch.length + try { + assert(isDigit(c)) + in.scratch append c + while (isDigit(in.head)) in.scratch append in.next + val n = Integer.parseInt(in.scratch.drop(length).mkString, 8) + if (n > 0377) { + in.error(offset, "malformed octal character code"); 0.toChar + } else n.toChar + } catch { + case ex : Exception => in.error(offset, "malformed octal character code"); 0.toChar + } finally { + in.scratch.setLength(length) + } + case c => in.error(offset, "unrecognized escape code \'" + c + "\'"); c + } + def getIdentRest : Unit = in.readIf{ + case '_' => + in.scratch append '_' + val c = in.head + if (isOperatorPart(c)) getOperatorRest else getIdentRest + case c if isIdentifierPart(c) => + in.scratch append c; getIdentRest + } + + val next = in.next + // called after everything is read. + def length = in.offset - offset + + def value(code : Int, value : Any) : Int = { + current.value = Some(value) + code + } + def doOperator(c : Char) = { + in.scratch.setLength(0) + in.scratch append(c) + getOperatorRest + val name : Name = global.newTermName(in.scratch.toString) + value(name2token(name), (name)) + } + current.offset = adjust(offset) + current.value = None + current.code = next match { + case ';' => (SEMI) + case ',' => (COMMA) + case '(' => xmlOk = true; (LPAREN) + case ')' => (RPAREN) + case '{' => xmlOk = true; (LBRACE) + case '}' => (RBRACE) + case '[' => (LBRACKET) + case ']' => (RBRACKET) + case SU => EOF + case '\u21D2' => (ARROW) + case '<' => + if (oldXmlOk && (in.head match { + case ('!' | '?') => true + case c if xml.Parsing.isNameStart(c) => true + case _ => false + })) { in.next; XMLSTART } + else doOperator('<') + case ' ' | '\t' => in.readWhile(isSpace); xmlOk = true; (WHITESPACE) + case '/' => + if (in.readIfStartsWith('/')) { + while (in.hasNext && !isNewLine(in.head)) in.next + (COMMENT) + } else if (in.readIfStartsWith('*')) { + val emptyOrDoc = in.readIfStartsWith('*') + val empty = emptyOrDoc && in.readIfStartsWith('/') + val isDoc = emptyOrDoc && !empty + + if (isDoc) + in.scratch setLength 0 + + var count = 0 + if (!empty) while (count != -1) in.next match { + case SU => in.error(offset, "unterminated comment"); count = -1 + case '*' if in.readIfStartsWith('/') => count -= 1 + case '/' if in.readIfStartsWith('*') => count += 1 + case c => + if (isDoc) in.scratch append c + } + if (!isDoc) (COMMENT) else value(COMMENT, in.scratch.toString) + } else doOperator('/') + case c @ ('~' | '!' | '@' | '#' | '%' | + '^' | '*' | '+' | '-' | /* '<' | | '/' */ + '>' | '?' | ':' | '=' | '&' | + '|' | '\\') => doOperator(c) + case c @ + ('A' | 'B' | 'C' | 'D' | 'E' | + 'F' | 'G' | 'H' | 'I' | 'J' | + 'K' | 'L' | 'M' | 'N' | 'O' | + 'P' | 'Q' | 'R' | 'S' | 'T' | + 'U' | 'V' | 'W' | 'X' | 'Y' | + 'Z' | '$' | '_' | + 'a' | 'b' | 'c' | 'd' | 'e' | + 'f' | 'g' | 'h' | 'i' | 'j' | + 'k' | 'l' | 'm' | 'n' | 'o' | + 'p' | 'q' | 'r' | 's' | 't' | + 'u' | 'v' | 'w' | 'x' | 'y' | + 'z') => + in.scratch.setLength(0) + in.scratch.append(c : Char) + getIdentRest + val name = global.newTermName(in.scratch.toString) + in.scratch.setLength(0) + val code = name2token(name) + if (code == IDENTIFIER) value(code, identifier(name)) + else value(code, (name)) + case '0' => + if (in.head match { + case 'x' | 'X' => true + case _ => false + }) { in.next; value(getNumber(offset, 16, "0x"), 16) } + else value(getNumber(offset, 8, "0"), 8) + case '1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' => getNumber(offset, 10, "") + case '.' => + val frac = getFraction(false) + val code = (frac getOrElse DOT) + code + case '\'' => + def endQ(cvalue : Char) : Int = { + if (!in.readIfStartsWith('\'')) { + in.error(offset, "missing terminating quote") + } + value(CHARLIT, cvalue) + } + in.next match { + case CR|LF|FF|SU|EOF if !in.isUnicode => + in.error(offset, "unterminated character literal") + value(CHARLIT, 0.toChar) + case '\'' => + in.error(offset, "empty character literal") + value(CHARLIT, 0.toChar) + case c if (Character.isUnicodeIdentifierStart(c)||isIdentifierPart(c)||isOperatorPart(c)) && in.head != '\'' => // symbol + in.scratch.setLength(0) + in.scratch append c + in.readWhile(c => isIdentifierPart(c) || isOperatorPart(c)) + if (in.readIfStartsWith('\'')) in.error(offset, "unexpected quote after symbol") + value(SYMBOLLIT, in.scratch.toString) + case '\\' => endQ(escapeCode(offset)) + case c => endQ(c) + } + case '\"' => + if (in.readIfStartsWith('\"')) { + if (in.readIfStartsWith('\"')) { + // multiline + in.scratch setLength 0 + while (in.next match { + case SU if !in.isUnicode => in.error(offset, "unterminated multi-line string"); false + case '\"' if in.readIfStartsWith('\"') => + if (in.readIfStartsWith('\"')) false + else { + in.scratch append "\"\""; true + } + case '\\' if false => // XXX: not for multi-line strings? + in.scratch append escapeCode(in.offset - 1) + true + case c => in.scratch append c; true + }) {} + val ret = value(STRINGLIT, in.scratch.toString) + in.scratch setLength 0 + ret + } else value(STRINGLIT, "") + } else { + in.scratch setLength 0 + while (in.next match { + case '\"' => false + case CR|LF|FF|SU if !in.isUnicode => + in.error(offset, "unterminated string"); false + case '\\' => + in.scratch append escapeCode(in.offset - 1); true + case c => in.scratch.append(c); true + }) {} + val ret = value(STRINGLIT, in.scratch.toString) + in.scratch setLength 0 + ret + } + case '`' => + in.scratch setLength 0 + while (in.head match { + case '`' => in.next; false + case CR | LF | FF | SU | EOF => + in.error(offset, "unterminated quoted identifier") + false + case _ => true + }) in.scratch append in.next + val name = global.newTermName(in.scratch.toString) + value(BACKQUOTED_IDENT, (name)) + case c if (c == CR | c == LF | c == FF) => + var multiple = false + in.readWhile{ + case d if isNewLine(d) => + multiple = multiple || d == c; true + case ' ' | '\t' => true // eat the whitespace after newlines. + case _ => false + } + xmlOk = true + (if (multiple) NEWLINES else NEWLINE) + case c => + if (Character.isUnicodeIdentifierStart(c)) { + in.scratch.setLength(0) + in.scratch append c + getIdentRest + val name = global.newTermName(in.scratch.toString) + in.scratch.setLength(0) + val code = name2token(name) + value(code, (name)) + } else if (isSpecial(c)) { + in.scratch.setLength(0) + in.scratch append c + getOperatorRest + val name = global.newTermName(in.scratch.toString) + in.scratch.setLength(0) + val code = name2token(name) + value(code, (name)) + } else { + in.error(offset, "illegal character: \'" + c + "\'") + (ERROR) + } + } + current.length = length + } + def intVal(offset : Int, token : Int, name0 : RandomAccessSeq[Char], negated: Boolean, base : Int): Long = { + if (name0.length == 1 && name0(0) == '0') return 0 + + var name = name0 + if (name.length > 2 && name(0) == '0' && (name(1) match { + case 'x'|'X' => true + case _ => false + })) name = name.drop(2) + + while (name.last match { + case 'l'|'L' => true + case _ => false + }) name = name.take(name.length - 1) + + if (token == CHARLIT && !negated) { + if (name.length > 0) name(0) else 0 + } else { + var value: Long = 0 + val divider = if (base == 10) 1 else 2 + val limit: Long = + if (token == LONGLIT) Math.MAX_LONG else Math.MAX_INT + var i = 0 + val len = name.length + while (i < len) { + val d = digit2int(name(i), base) + if (d < 0) { + in.error(offset, "malformed integer number") + return 0 + } + if (value < 0 || + limit / (base / divider) < value || + limit - (d / divider) < value * (base / divider) && + !(negated && limit == value * base - 1 + d)) { + in.error(offset, "integer number too large") + return 0 + } + value = value * base + d + i += 1 + } + if (negated) -value else value + } + } + + + /** convert name, base to double value + */ + def floatVal(offset : Int, token : Int, name0 : RandomAccessSeq[Char], negated: Boolean): Double = { + var name = name0 + while (name.last match { + case 'f'|'F'|'d'|'D' => true + case _ => false + }) name = name.take(name.length - 1) + + val limit: Double = + if (token == DOUBLELIT) Math.MAX_DOUBLE else Math.MAX_FLOAT + try { + val value: Double = java.lang.Double.valueOf(name.mkString).doubleValue() + if (value > limit) + in.error(offset, "floating point number too large") + if (negated) -value else value + } catch { + case _: NumberFormatException => + in.error(offset, "malformed floating point number") + 0.0 + } + } + } + + + // utility functions + def isSpecial(c : Char) : Boolean = { + val chtp = Character.getType(c) + chtp == Character.MATH_SYMBOL || chtp == Character.OTHER_SYMBOL + } + def isDigit(c : Char) : Boolean = digit2int(c, 10) >= 0 + + def isIdentifierStart(c: Char): Boolean = c match { + case 'A' | 'B' | 'C' | 'D' | 'E' | + 'F' | 'G' | 'H' | 'I' | 'J' | + 'K' | 'L' | 'M' | 'N' | 'O' | + 'P' | 'Q' | 'R' | 'S' | 'T' | + 'U' | 'V' | 'W' | 'X' | 'Y' | + 'Z' | '$' | '_' | + 'a' | 'b' | 'c' | 'd' | 'e' | + 'f' | 'g' | 'h' | 'i' | 'j' | + 'k' | 'l' | 'm' | 'n' | 'o' | + 'p' | 'q' | 'r' | 's' | 't' | + 'u' | 'v' | 'w' | 'x' | 'y' | // scala-mode: need to understand multi-line case patterns + 'z' => true + case _ => false + } + def isIdentifierPart(c: Char) : Boolean = c match { + case ('A' | 'B' | 'C' | 'D' | 'E' | + 'F' | 'G' | 'H' | 'I' | 'J' | + 'K' | 'L' | 'M' | 'N' | 'O' | + 'P' | 'Q' | 'R' | 'S' | 'T' | + 'U' | 'V' | 'W' | 'X' | 'Y' | + 'Z' | '$' | '_' | + 'a' | 'b' | 'c' | 'd' | 'e' | + 'f' | 'g' | 'h' | 'i' | 'j' | + 'k' | 'l' | 'm' | 'n' | 'o' | + 'p' | 'q' | 'r' | 's' | 't' | + 'u' | 'v' | 'w' | 'x' | 'y' | + 'z') => true + case '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' => true + case c if Character.isUnicodeIdentifierPart(c) => true + case _ => false + } + //isIdentifierStart(c) || isDigit(c) || isUnicodeIdentifierPart(c) + def isOperatorPart(c : Char) : Boolean = c match { + case '~' | '!' | '@' | '#' | '%' | + '^' | '*' | '+' | '-' | '<' | + '>' | '?' | ':' | '=' | '&' | + '|' | '/' | '\\' => true + case c if isSpecial(c) => true + case _ => false + } + + private def getOperatorRest(implicit in : CoreScannerInput) : Unit = { + in.readWhile{ + case ('/') if in.startsWith('/','*') || in.startsWith('/','/') => false + case ('*') if in.startsWith('*','/') => false + case (c) if isOperatorPart(c) => in.scratch append c; true + case _ => false + } + } + private def isFraction(c0 : Char, c1 : Char) = + isDigit(c0) || (c0 match { + case 'd'|'D'|'f'|'F' if !isIdentifierPart(c1) => true + case 'e'|'E' if isDigit(c1) => true + case _ => false + }) + private def getFraction(hasWhole : Boolean)(implicit in : CoreScannerInput) : Option[Int] = { + val hasDigits = in.readWhile(isDigit) + if (!hasDigits && !hasWhole) return None + + def end(code : Int) : Option[Int] = { + if (!hasDigits && isIdentifierPart(in.peek(1))) None + else in.next; Some(code) + } + in.head match { + case 'f'|'F' => return end(FLOATLIT) + case 'd'|'D' => return end(DOUBLELIT) + case 'e'|'E' if { + val peek = in.peek(1) + peek == '-' || peek == '+' || isDigit(peek) + } => + in.next // eat the e. + var hasDigit = isDigit(in.next) // eat +/-/digit + hasDigit = in.readWhile(isDigit) || hasDigit + in.readIf{ // eat an optional f or d + case 'f'|'F' => FLOATLIT + case 'd'|'D' => DOUBLELIT + } orElse Some(DOUBLELIT) + case _ if hasDigits => Some(DOUBLELIT) + case _ => None // we didn't read anything + } + } + private def getNumber(offset : Int, base : Int, prefix : String)(implicit in : CoreScannerInput) : Int = { + val hasBody = in.readWhile{ + case at if at >= '0' && at <= '9' => true + case at if base == 16 && ((at >= 'a' && at <= 'f') || (at >= 'A' && at <= 'F')) => true + case _ => false + } + if (!hasBody) base match { + // because Java does this + case 16 => + in.error(offset, "Invalid hex literal number") + return INTLIT + case _ => + } + val code = if (in.head == '.') { + in.peek(1) match { + case c if isDigit(c) => in.next; getFraction(true).get + case 'f'|'F'|'d'|'D' if !isIdentifierPart(in.peek(2)) => in.next; getFraction(true).get + case 'e'|'E' if { + val peek = in.peek(2) + isDigit(peek) || peek == '-' || peek == '+' + } => + in.next // consume the dot + in.next // consume the e + in.next // consume the +/-/digit + in.readWhile(isDigit) // consume remaining digits + in.readIf{ + case 'f'|'F' => FLOATLIT + case 'd'|'D' => DOUBLELIT + } getOrElse DOUBLELIT + case c if isIdentifierStart(c) => INTLIT + case _ => in.next; DOUBLELIT + } + } else (in.readIf{ + case 'l'|'L' => LONGLIT + case 'f'|'F' => FLOATLIT + case 'd'|'D' => DOUBLELIT + } getOrElse { + if (in.head == 'e' || in.head == 'E') { + in.next + if (in.head == '-' || in.head == '+') in.next + in.readWhile(isDigit) + in.readIf{ + case 'f'|'F' => FLOATLIT + case 'd'|'D' => DOUBLELIT + } getOrElse DOUBLELIT + } else INTLIT + }) + if (in.readWhile(isIdentifierPart)) + in.error(offset, "Invalid literal number") + code + } + def inFirstOfStat(token: Int) = token match { + case EOF | /*CASE |*/ CATCH | ELSE | EXTENDS | FINALLY | MATCH | REQUIRES | WITH | YIELD | + COMMA | SEMI | NEWLINE | NEWLINES | DOT | USCORE | COLON | EQUALS | ARROW | + LARROW | SUBTYPE | VIEWBOUND | SUPERTYPE | HASH | // todo: add LBRACKET + RPAREN | RBRACKET | RBRACE => false + case _ => true + } + def inLastOfStat(token: Int) = token match { + case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | + IDENTIFIER | BACKQUOTED_IDENT | THIS | NULL | TRUE | FALSE | RETURN | USCORE | + TYPE | XMLSTART | RPAREN | RBRACKET | RBRACE => true + case _ => false + } + + def digit(c : Char, radix : Int) = c match { + case c if c >= '0' && c <= '7' => c - '0' + case c if c >= '8' && c <= '9' && radix >= 10 => c - '0' + case c if c >= '8' && c <= '9' && radix == 8 => throw new NumberFormatException("Malformed octal number") + case c if c >= 'a' && c <= 'f' && radix == 16 => c - 'a' + 9 + case c if c >= 'A' && c <= 'F' && radix == 16 => c - 'A' + 9 + } + private val simpleEscape : PartialFunction[Char,Char] = { + case 'b' => '\b' + case 't' => '\t' + case 'n' => '\n' + case 'f' => '\f' + case 'r' => '\r' + case '\"' => '\"' + case '\'' => '\'' + case '\\' => '\\' + } + + def digit2int(ch: Char, base: Int): Int = { + if ('0' <= ch && ch <= '9' && ch < '0' + base) + ch - '0' + else if ('A' <= ch && ch < 'A' + base - 10) + ch - 'A' + 10 + else if ('a' <= ch && ch < 'a' + base - 10) + ch - 'a' + 10 + else + -1 + } + + object ScannerConfiguration { + private var key: Array[byte] = _ + private var maxKey = 0 + private var tokenName = new Array[global.Name](128); + { + var tokenCount = 0 + // Enter keywords + def enterKeyword(n: global.Name, tokenId: Int) { + while (tokenId >= tokenName.length) { + val newTokName = new Array[global.Name](tokenName.length * 2) + Array.copy(tokenName, 0, newTokName, 0, newTokName.length) + tokenName = newTokName + } + tokenName(tokenId) = n + if (n.start > maxKey) maxKey = n.start + if (tokenId >= tokenCount) tokenCount = tokenId + 1 + } + import global.nme + + enterKeyword(nme.ABSTRACTkw, ABSTRACT) + enterKeyword(nme.CASEkw, CASE) + enterKeyword(nme.CATCHkw, CATCH) + enterKeyword(nme.CLASSkw, CLASS) + enterKeyword(nme.DEFkw, DEF) + enterKeyword(nme.DOkw, DO) + enterKeyword(nme.ELSEkw, ELSE) + enterKeyword(nme.EXTENDSkw, EXTENDS) + enterKeyword(nme.FALSEkw, FALSE) + enterKeyword(nme.FINALkw, FINAL) + enterKeyword(nme.FINALLYkw, FINALLY) + enterKeyword(nme.FORkw, FOR) + enterKeyword(nme.FORSOMEkw, FORSOME) + enterKeyword(nme.IFkw, IF) + enterKeyword(nme.IMPLICITkw, IMPLICIT) + enterKeyword(nme.IMPORTkw, IMPORT) + enterKeyword(nme.LAZYkw, LAZY) + enterKeyword(nme.MATCHkw, MATCH) + enterKeyword(nme.NEWkw, NEW) + enterKeyword(nme.NULLkw, NULL) + enterKeyword(nme.OBJECTkw, OBJECT) + enterKeyword(nme.OVERRIDEkw, OVERRIDE) + enterKeyword(nme.PACKAGEkw, PACKAGE) + enterKeyword(nme.PRIVATEkw, PRIVATE) + enterKeyword(nme.PROTECTEDkw, PROTECTED) + enterKeyword(nme.REQUIRESkw, REQUIRES) + enterKeyword(nme.RETURNkw, RETURN) + enterKeyword(nme.SEALEDkw, SEALED) + enterKeyword(nme.SUPERkw, SUPER) + enterKeyword(nme.THISkw, THIS) + enterKeyword(nme.THROWkw, THROW) + enterKeyword(nme.TRAITkw, TRAIT) + enterKeyword(nme.TRUEkw, TRUE) + enterKeyword(nme.TRYkw, TRY) + enterKeyword(nme.TYPEkw, TYPE) + enterKeyword(nme.VALkw, VAL) + enterKeyword(nme.VARkw, VAR) + enterKeyword(nme.WHILEkw, WHILE) + enterKeyword(nme.WITHkw, WITH) + enterKeyword(nme.YIELDkw, YIELD) + enterKeyword(nme.DOTkw, DOT) + enterKeyword(nme.USCOREkw, USCORE) + enterKeyword(nme.COLONkw, COLON) + enterKeyword(nme.EQUALSkw, EQUALS) + enterKeyword(nme.ARROWkw, ARROW) + enterKeyword(nme.LARROWkw, LARROW) + enterKeyword(nme.SUBTYPEkw, SUBTYPE) + enterKeyword(nme.VIEWBOUNDkw, VIEWBOUND) + enterKeyword(nme.SUPERTYPEkw, SUPERTYPE) + enterKeyword(nme.HASHkw, HASH) + enterKeyword(nme.ATkw, AT) + + // Build keyword array + key = new Array[byte](maxKey + 1) + for (i <- 0 to maxKey) + key(i) = IDENTIFIER + for (j <- 0 until tokenCount) + if (tokenName(j) ne null) + key(tokenName(j).start) = j.asInstanceOf[byte] + + } +//Token representation ----------------------------------------------------- + + /** Convert name to token */ + def name2token(name: global.Name): int = + if (name.start <= maxKey) key(name.start) else IDENTIFIER + + def isKeyword(code : Int) = code match { + case code if code >= IF && code <= REQUIRES => true + case _ => false + } + /** Returns the string representation of given token. */ + def token2string(token: int): String = token match { + case IDENTIFIER | BACKQUOTED_IDENT => "identifier" + case CHARLIT => "character literal" + case INTLIT => "integer literal" + case LONGLIT => "long literal" + case FLOATLIT => "float literal" + case DOUBLELIT => "double literal" + case STRINGLIT => "string literal" + case SYMBOLLIT => "symbol literal" + case LPAREN => "'('" + case RPAREN => "')'" + case LBRACE => "'{'" + case RBRACE => "'}'" + case LBRACKET => "'['" + case RBRACKET => "']'" + case EOF => "eof" + case ERROR => "something" + case SEMI => "';'" + case NEWLINE => "';'" + case NEWLINES => "';'" + case COMMA => "','" + case CASECLASS => + "case class" + case CASEOBJECT => + "case object" + case XMLSTART => + "$XMLSTART$<" + case COMMENT => "cmnt" + case WHITESPACE => "ws" + case IGNORE => "ig" + case _ => + try { + "'" + tokenName(token) + "'" + } catch { + case _: ArrayIndexOutOfBoundsException => + "'<" + token + ">'" + case _: NullPointerException => + "'<(" + token + ")>'" + } + } + } + class UnitScanner(unit: CompilationUnit) extends ParserScanner { + implicit val in = + new DefaultInput(new NewCharArrayReader(unit.source.asInstanceOf[BatchSourceFile].content, !settings.nouescape.value, error)) { + override def error(offset : Int, msg : String) : Unit = UnitScanner.this.error(offset, msg) + } + init + private def error(offset : Int, msg : String) : Unit = unit.error(new OffsetPosition(unit.source,offset), msg) + } +} diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index a820c985e6..582d4646e6 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -8,7 +8,7 @@ package scala.tools.nsc.ast.parser -import scala.tools.nsc.util.{ListBuffer, Position, OffsetPosition} +import scala.tools.nsc.util.{ListBuffer, Position, OffsetPosition, NoPosition, BatchSourceFile} import symtab.Flags import Tokens._ @@ -49,76 +49,94 @@ import Tokens._ * </li> * </ol> */ -trait Parsers { - self: SyntaxAnalyzer => - +trait Parsers extends NewScanners with MarkupParsers { + val global : Global import global._ - //import RequiresIntsAsPositions._ + private val glob: global.type = global import global.posAssigner.atPos + case class OpInfo(operand: Tree, operator: Name, pos: Int) /** ... * * @author Sean McDirmid */ - class UnitParser(unit: global.CompilationUnit) extends Parser { + class UnitParser(val unit: global.CompilationUnit) extends Parser { val in = new UnitScanner(unit) - in.init - import in.ScanPosition - def freshName(prefix : String) = unit.fresh.newName(prefix) - import in.{p2g, g2p} - def posToReport = - if (!in.currentPos.line.isEmpty && !in.lastPos.line.isEmpty && - in.currentPos.line.get > in.lastPos.line.get) in.lastPos; - else in.currentPos + def freshName(pos : Position, prefix : String) = unit.fresh.newName(pos, prefix) + implicit def i2p(offset : Int) : Position = new OffsetPosition(unit.source,offset) + def warning(pos : Int, msg : String) : Unit = unit.warning(pos, msg) + def incompleteInputError(msg: String) : Unit = + unit.incompleteInputError(unit.source.asInstanceOf[BatchSourceFile].content.length - 1, msg) + def deprecationWarning(pos : Int, msg : String) : Unit = unit.deprecationWarning(pos, msg) + def syntaxError(pos: Int, msg: String) : Unit = unit.error(pos, msg) + + /** the markup parser */ + def xmlp = { + if (xmlp0 == null) + xmlp0 = new MarkupParser(this, true) + xmlp0 + } + private var xmlp0: MarkupParser = null + def xmlLiteral : Tree = xmlp.xLiteral + def xmlLiteralPattern : Tree = xmlp.xLiteralPattern + object symbXMLBuilder extends SymbolicXMLBuilder(treeBuilder, UnitParser.this, true) { // DEBUG choices + val global: Parsers.this.global.type = Parsers.this.global + def freshName(prefix: String): Name = UnitParser.this.freshName(NoPosition, prefix) + } + } + // parser constants, here so they don't pollute parser debug listing + private object ParserConfiguration { + final val Local = 0 + final val InBlock = 1 + final val InTemplate = 2 + final val MINUS: Name = "-" + final val PLUS : Name = "+" + final val BANG : Name = "!" + final val TILDE: Name = "~" + final val AMP : Name = "&" + final val SLASH: Name = "/" + final val STAR : Name = "*" + final val BAR : Name = "|" + final val OPT : Name = "?" + final val LT : Name = "<" } abstract class Parser { - protected val in: AbstractScanner - import in.ScanPosition - protected def freshName(prefix: String): Name - protected def posToReport: ScanPosition - import in.{p2g, g2p} + ParserConfiguration.hashCode + import ParserConfiguration._ + val in: ParserScanner + //val unit : CompilationUnit + //import in.ScanPosition + protected def freshName(pos : Position, prefix: String): Name + protected def posToReport: Int = in.currentPos + + protected implicit def i2p(offset : Int) : Position + private implicit def p2i(pos : Position) = pos.offset.get + private def inToken = in.token private def inSkipToken = in.skipToken private def inNextToken = in.nextToken private def inCurrentPos = in.currentPos + private def inNextTokenCode : Int = in.nextTokenCode private def inName = in.name - private def charVal = in.intVal.asInstanceOf[Char] + private def charVal = in.charVal private def intVal(isNegated : Boolean) = in.intVal(isNegated).asInstanceOf[Int] private def longVal(isNegated : Boolean) = in.intVal(isNegated) private def floatVal(isNegated : Boolean) = in.floatVal(isNegated).asInstanceOf[Float] private def doubleVal(isNegated : Boolean) = in.floatVal(isNegated) - private def stringVal = inName.toString - private def inNextTokenCode = in.next.token + private def stringVal = in.stringVal /** whether a non-continuable syntax error has been seen */ - private var syntaxErrorSeen = false - - /** the markup parser */ - def xmlp = { - if (xmlp0 == null) - xmlp0 = this match { - case in: UnitParser => - new MarkupParser(in, true) - case _ => - Console.println("Cannot create XML PARSER " + in) - null - } - xmlp0 - } - private var xmlp0: MarkupParser = null + //private var syntaxErrorSeen = false + private var lastErrorPos : Int = -1 object treeBuilder extends TreeBuilder { val global: Parsers.this.global.type = Parsers.this.global - def freshName(prefix: String, pos : Position): Name = Parser.this.freshName(prefix) + def freshName(pos : Position, prefix: String): Name = Parser.this.freshName(pos, prefix) } import treeBuilder._ - object symbXMLBuilder extends SymbolicXMLBuilder(treeBuilder, Parser.this, true) { // DEBUG choices - val global: Parsers.this.global.type = Parsers.this.global - def freshName(prefix: String): Name = Parser.this.freshName(prefix) - } /** The implicit view parameters of the surrounding class */ var implicitClassViews: List[Tree] = Nil @@ -180,7 +198,7 @@ trait Parsers { /////// ERROR HANDLING ////////////////////////////////////////////////////// - private def skip() { + protected def skip() { var nparens = 0 var nbraces = 0 while (true) { @@ -207,60 +225,42 @@ trait Parsers { inNextToken } } - + def warning(pos : Int, msg : String) : Unit + def incompleteInputError(msg: String) : Unit + def deprecationWarning(pos : Int, msg : String) : Unit + def syntaxError(pos: Int, msg: String) : Unit def syntaxError(msg: String, skipIt: Boolean) { syntaxError(inCurrentPos, msg, skipIt) } - def syntaxError(pos: ScanPosition, msg: String) { - in.error(pos, msg) - } - def syntaxError(pos: ScanPosition, msg: String, skipIt: Boolean) { - if (pos != in.errpos) { + + def syntaxError(pos: Int, msg: String, skipIt: Boolean) { + if (pos > lastErrorPos) { syntaxError(pos, msg) - in.errpos = pos + // no more errors on this token. + lastErrorPos = inCurrentPos } - if (skipIt) { + if (skipIt) skip() - } - syntaxErrorSeen = true - } - - def warning(msg: String) = - if (inCurrentPos != in.errpos) { - in.warning(inCurrentPos, msg) - in.errpos = inCurrentPos - } - - def incompleteInputError(pos: ScanPosition, msg: String) { - if (pos == in.errpos) return - - if (syntaxErrorSeen) - syntaxError(pos, msg, false) - else { - in.incompleteInputError(pos, msg) - in.errpos = pos - } } + def warning(msg: String) : Unit = warning(inCurrentPos, msg) - def incompleteInputError(msg: String) { - incompleteInputError(inCurrentPos, msg) // inCurrentPos should be at the EOF - } def syntaxErrorOrIncomplete(msg: String, skipIt: Boolean) { + val inToken = this.inToken if (inToken == EOF) incompleteInputError(msg) else syntaxError(inCurrentPos, msg, skipIt) } - + // unused. def mismatch(expected: Int, found: Int) { val posToReport = this.posToReport val msg = - in.configuration.token2string(expected) + " expected but " + - in.configuration.token2string(found) + " found." + ScannerConfiguration.token2string(expected) + " expected but " + + ScannerConfiguration.token2string(found) + " found." if (found == EOF) - incompleteInputError(posToReport, msg) + incompleteInputError(msg) else syntaxError(posToReport, msg, true) } @@ -268,33 +268,47 @@ trait Parsers { /** Consume one token of the specified type, or * signal an error if it is not there. */ - def accept(token: Int): ScanPosition = { + def accept(token: Int): Int = { val pos = inCurrentPos if (inToken != token) { val posToReport = - if (inCurrentPos.line.get(0) > in.lastPos.line.get(0)) - in.lastPos - else + //if (inCurrentPos.line(unit.source).get(0) > in.lastPos.line(unit.source).get(0)) + // in.lastPos + //else inCurrentPos val msg = - in.configuration.token2string(token) + " expected but " + - in.configuration.token2string(inToken) + " found." + ScannerConfiguration.token2string(token) + " expected but " + + ScannerConfiguration.token2string(inToken) + " found." if (inToken == EOF) - incompleteInputError(posToReport, msg) + incompleteInputError(msg) else syntaxError(posToReport, msg, true) } if (inToken == token) inNextToken pos } + def surround[T](open : Int, close : Int)(f : => T, orElse : T) : T = { + val wasOpened = inToken == open + accept(open) + if (wasOpened) { + val ret = f + accept(close) + ret + } else orElse + } + /** semi = nl {nl} | `;' * nl = `\n' // where allowed */ - def acceptStatSep() { - if (inToken == NEWLINE || inToken == NEWLINES) inNextToken - else accept(SEMI) + def acceptStatSep() : Boolean = { + if (inToken == NEWLINE || inToken == NEWLINES) { inNextToken; true } + else { + val ret = inToken == SEMI + accept(SEMI) + ret + } } def errorTypeTree = TypeTree().setType(ErrorType).setPos((inCurrentPos)) @@ -355,7 +369,7 @@ trait Parsers { */ def joinComment(trees: => List[Tree]): List[Tree] = { val buf = in.flushDoc - if (buf ne null) trees map (t => DocDef(buf, t) setPos t.pos) + if ((buf ne null) && buf.length > 0) trees map (t => DocDef(buf, t) setPos t.pos) else trees } @@ -377,8 +391,8 @@ trait Parsers { tree match { case Ident(name) => ValDef(Modifiers(Flags.PARAM), name, TypeTree(), EmptyTree) - case Typed(Ident(name), tpe) if (tpe.isType) => - ValDef(Modifiers(Flags.PARAM), name, tpe, EmptyTree) + case Typed(tree @ Ident(name), tpe) if (tpe.isType) => // get the ident! + ValDef(Modifiers(Flags.PARAM), name, tpe, EmptyTree).setPos(tree.pos) case _ => syntaxError(tree.pos, "not a legal formal parameter", false) ValDef(Modifiers(Flags.PARAM), nme.ERROR, errorTypeTree, EmptyTree) @@ -399,7 +413,7 @@ trait Parsers { /** make closure from tree staring with a `.' */ def makeDotClosure(tree: Tree): Tree = { - val pname = freshName("x$") + val pname = freshName(tree.pos, "x$") def insertParam(tree: Tree): Tree = atPos(tree.pos) { tree match { case Ident(name) => @@ -420,7 +434,6 @@ trait Parsers { /////// OPERAND/OPERATOR STACK ///////////////////////////////////////////////// - case class OpInfo(operand: Tree, operator: Name, pos: ScanPosition) var opstack: List[OpInfo] = Nil def precedence(operator: Name): Int = @@ -448,7 +461,7 @@ trait Parsers { if (size > max) syntaxError("too many "+kind+", maximum = "+max, false) } - def checkAssoc(pos: ScanPosition, op: Name, leftAssoc: Boolean) = + def checkAssoc(pos: Int, op: Name, leftAssoc: Boolean) = if (treeInfo.isLeftAssoc(op) != leftAssoc) syntaxError( pos, "left- and right-associative operators with same precedence may not be mixed", false) @@ -470,16 +483,6 @@ trait Parsers { /////// IDENTIFIERS AND LITERALS //////////////////////////////////////////////////////////// - final val MINUS: Name = "-" - final val PLUS : Name = "+" - final val BANG : Name = "!" - final val TILDE: Name = "~" - final val AMP : Name = "&" - final val SLASH: Name = "/" - final val STAR : Name = "*" - final val BAR : Name = "|" - final val OPT : Name = "?" - final val LT : Name = "<" def ident(): Name = if (inToken == IDENTIFIER || inToken == BACKQUOTED_IDENT) { @@ -491,9 +494,9 @@ trait Parsers { nme.ERROR } - def selector(t: Tree) = { - Select(t, ident()) - } + def selector(t: Tree) = + atPos(inCurrentPos)(Select(t, ident())) + /** Path ::= StableId * | [Ident `.'] this @@ -503,11 +506,15 @@ trait Parsers { var t: Tree = null if (inToken == THIS) { t = atPos(inSkipToken) { This(nme.EMPTY.toTypeName) } - if (!thisOK || inToken == DOT) + if (!thisOK || inToken == DOT) { t = selectors(t, typeOK, accept(DOT)) + } } else if (inToken == SUPER) { - t = atPos(inSkipToken) { - Super(nme.EMPTY.toTypeName, mixinQualifierOpt()) + // val pos = inCurrentPos + val pos = inSkipToken + val (mix,usePos) = mixinQualifierOpt(pos) + t = atPos(usePos) { + Super(nme.EMPTY.toTypeName, mix) } t = atPos(accept(DOT)) { selector(t) } if (inToken == DOT) @@ -527,7 +534,8 @@ trait Parsers { t = selectors(t, typeOK, accept(DOT)) } else if (inToken == SUPER) { inNextToken - t = atPos(i.pos) { Super(i.name.toTypeName, mixinQualifierOpt()) } + val (mix,pos) = mixinQualifierOpt(i.pos) + t = atPos(pos) { Super(i.name.toTypeName, mix) } t = atPos(accept(DOT)) {selector(t)} if (inToken == DOT) t = selectors(t, typeOK, inSkipToken) @@ -539,7 +547,7 @@ trait Parsers { t } - def selectors(t: Tree, typeOK: Boolean, pos : ScanPosition): Tree = + def selectors(t: Tree, typeOK: Boolean, pos : Int): Tree = if (typeOK && inToken == TYPE) { inNextToken atPos(pos) { SingletonTypeTree(t) } @@ -551,14 +559,15 @@ trait Parsers { /** MixinQualifier ::= `[' Id `]' */ - def mixinQualifierOpt(): Name = + def mixinQualifierOpt(pos : Position): (Name,Position) = if (inToken == LBRACKET) { inNextToken + val pos = inCurrentPos val name = ident().toTypeName accept(RBRACKET) - name + (name,pos) } else { - nme.EMPTY.toTypeName + (nme.EMPTY.toTypeName,pos) } /** StableId ::= Id @@ -645,7 +654,7 @@ trait Parsers { */ def requiresTypeOpt(): Tree = if (inToken == REQUIRES) { - in.deprecationWarning(in.pos, "`requires T' has been deprecated; use `{ self: T => ...' instead") + deprecationWarning(in.currentPos, "`requires T' has been deprecated; use `{ self: T => ...' instead") inNextToken; placeholderTypeBoundary(annotType(false)) } else TypeTree() @@ -655,9 +664,10 @@ trait Parsers { def types(isPattern: Boolean, isTypeApply: Boolean, isFuncArg: Boolean): List[Tree] = { val ts = new ListBuffer[Tree] + argType(isPattern, isTypeApply, isFuncArg) while (inToken == COMMA) { + val pos = inCurrentPos inNextToken if (inToken == RPAREN) { - in.deprecationWarning(in.pos, "Trailing commas have been deprecated") + deprecationWarning(pos, "Trailing commas have been deprecated") return ts.toList } else { ts += argType(isPattern, isTypeApply, isFuncArg) @@ -676,7 +686,6 @@ trait Parsers { * | InfixType [ExistentialClause] * ExistentialClause ::= forSome `{' ExistentialDcl {semi ExistentialDcl}} `}' * ExistentialDcl ::= type TypeDcl | val ValDcl - * XXX: Hook for IDE. */ def typ(): Tree = { val t = @@ -729,7 +738,7 @@ trait Parsers { def infixTypeFirst(isPattern: Boolean) = if (inToken == LBRACE) scalaAnyRefConstr else annotType(isPattern) - def infixTypeRest(pos: ScanPosition, t0: Tree, isPattern: Boolean, mode: InfixMode.Value): Tree = { + def infixTypeRest(pos: Int, t0: Tree, isPattern: Boolean, mode: InfixMode.Value): Tree = { val t = compoundTypeRest(pos, t0, isPattern) if (isIdent && inName != nme.STAR) { val opPos = inCurrentPos @@ -752,7 +761,7 @@ trait Parsers { def compoundType(isPattern: Boolean): Tree = compoundTypeRest(inCurrentPos, infixTypeFirst(isPattern), isPattern) - def compoundTypeRest(pos: ScanPosition, t: Tree, isPattern: Boolean): Tree = { + def compoundTypeRest(pos: Int, t: Tree, isPattern: Boolean): Tree = { var ts = new ListBuffer[Tree] + t while (inToken == WITH) { inNextToken; ts += annotType(isPattern) @@ -777,7 +786,7 @@ trait Parsers { def annotType(isPattern: Boolean): Tree = { val annots1 = annotations() if (!annots1.isEmpty) - in.deprecationWarning( + deprecationWarning( annots1.head.pos, "Type annotations should now follow the type") // deprecated on August 13, 2007 @@ -805,18 +814,23 @@ trait Parsers { (t /: annots) (makeAnnotated) } - def annotTypeRest(pos: ScanPosition, isPattern: Boolean, t: Tree): Tree = - if (inToken == HASH) - annotTypeRest(pos, isPattern, atPos(inSkipToken) { SelectFromTypeTree(t, ident().toTypeName) }) - else if (inToken == LBRACKET) - annotTypeRest(pos, isPattern, atPos(pos) { AppliedTypeTree(t, typeArgs(isPattern, false)) }) + def annotTypeRest(pos: Int, isPattern: Boolean, t: Tree): Tree = + if (inToken == HASH) { + inSkipToken + val posId = inCurrentPos + val id = ident + annotTypeRest(pos, isPattern, atPos(posId) { SelectFromTypeTree(t, id.toTypeName) }) + } else if (inToken == LBRACKET) { + val usePos = if (t.pos != NoPosition) t.pos else i2p(pos) + annotTypeRest(pos, isPattern, atPos(usePos) { AppliedTypeTree(t, typeArgs(isPattern, false)) }) + } else t /** WildcardType ::= `_' TypeBounds */ - def wildcardType(pos: ScanPosition) = { - val pname = freshName("_$").toTypeName + def wildcardType(pos: Int) = { + val pname = freshName(pos, "_$").toTypeName val param = atPos(pos) { makeSyntheticTypeParam(pname, typeBounds()) } placeholderTypes = param :: placeholderTypes Ident(pname) setPos pos @@ -919,9 +933,10 @@ trait Parsers { def exprs(): List[Tree] = { val ts = new ListBuffer[Tree] + expr() while (inToken == COMMA) { - inNextToken; + val pos = in.currentPos + inNextToken if (inToken == RPAREN) { - in.deprecationWarning(in.pos, "Trailing commas have been deprecated") + deprecationWarning(pos, "Trailing commas have been deprecated") return ts.toList } else { ts += expr() @@ -930,9 +945,6 @@ trait Parsers { ts.toList } - private final val Local = 0 - private final val InBlock = 1 - private final val InTemplate = 2 /** Expr ::= (Bindings | Id) `=>' Expr * | Expr1 @@ -956,8 +968,10 @@ trait Parsers { * | `:' `_' `*' */ def expr(): Tree = expr(Local) - - /** XXX: Hook for IDE */ + /* hook for IDE, unlike expression can be stubbed + * don't use for any tree that can be inspected in the parser! + */ + def statement(location: Int): Tree = expr(location) def expr(location: Int): Tree = { def isWildcard(t: Tree): Boolean = t match { case Ident(name1) if !placeholderParams.isEmpty && name1 == placeholderParams.head.name => true @@ -970,9 +984,8 @@ trait Parsers { var res = inToken match { case IF => val pos = inSkipToken - accept(LPAREN) - val cond = expr() - accept(RPAREN) + + val cond = surround(LPAREN,RPAREN)(expr(),Literal(true)) newLinesOpt() val thenp = expr() val elsep = @@ -981,15 +994,11 @@ trait Parsers { atPos(pos) { If(cond, thenp, elsep) } case TRY => atPos(inSkipToken) { - accept(LBRACE) - val body = block() - accept(RBRACE) + val body = surround(LBRACE,RBRACE)(block(), Literal(())) val catches = if (inToken == CATCH) { inNextToken - accept(LBRACE) - val cases = caseClauses() - accept(RBRACE) + val cases = surround(LBRACE,RBRACE)(caseClauses(), Nil) cases } else List() val finalizer = @@ -998,30 +1007,25 @@ trait Parsers { Try(body, catches, finalizer) } case WHILE => - val lname: Name = freshName("while$") val pos = inSkipToken - accept(LPAREN) - val cond = expr() - accept(RPAREN) + val lname: Name = freshName(pos, "while$") + val cond = surround(LPAREN,RPAREN)(expr(),Literal(true)) newLinesOpt() val body = expr() atPos(pos) { makeWhile(lname, cond, body) } case DO => - val lname: Name = freshName("doWhile$") val pos = inSkipToken + val lname: Name = freshName(pos, "doWhile$") val body = expr() if (isStatSep) inNextToken accept(WHILE) - accept(LPAREN) - val cond = expr() - accept(RPAREN) + val cond = surround(LPAREN,RPAREN)(expr(), Literal(true)) atPos(pos) { makeDoWhile(lname, body, cond) } case FOR => atPos(inSkipToken) { val startToken = inToken - accept(if (startToken == LBRACE) LBRACE else LPAREN) - val enums = enumerators() - accept(if (startToken == LBRACE) RBRACE else RPAREN) + val (open,close) = if (startToken == LBRACE) (LBRACE,RBRACE) else (LPAREN,RPAREN) + val enums = surround(open,close)(enumerators(), Nil) newLinesOpt() if (inToken == YIELD) { inNextToken; makeForYield(enums, expr()) @@ -1036,7 +1040,7 @@ trait Parsers { Throw(expr()) } case DOT => - in.deprecationWarning(in.pos, "`.f' has been deprecated; use `_.f' instead") + deprecationWarning(in.currentPos, "`.f' has been deprecated; use `_.f' instead") atPos(inSkipToken) { if (isIdent) { makeDotClosure(stripParens(simpleExpr())) @@ -1085,9 +1089,7 @@ trait Parsers { } } else if (inToken == MATCH) { t = atPos(inSkipToken) { - accept(LBRACE) - val cases = caseClauses() - accept(RBRACE) + val cases = surround(LBRACE,RBRACE)(caseClauses(), Nil) Match(stripParens(t), cases) } } @@ -1100,7 +1102,7 @@ trait Parsers { } if (!placeholderParams.isEmpty) if (isWildcard(res)) savedPlaceholderParams = placeholderParams ::: savedPlaceholderParams - else res = Function(placeholderParams.reverse, res) + else res = atPos(res.pos){Function(placeholderParams.reverse, res)} placeholderParams = savedPlaceholderParams res } @@ -1147,7 +1149,7 @@ trait Parsers { val name = unaryOp() atPos(pos) { Select(stripParens(simpleExpr()), name) } } else if (isIdent && inName == AMP) { - in.deprecationWarning(in.pos, "`&f' has been deprecated; use `f _' instead") + deprecationWarning(in.currentPos, "`&f' has been deprecated; use `f _' instead") val pos = inCurrentPos val name = ident() atPos(pos) { Typed(stripParens(simpleExpr()), Function(List(), EmptyTree)) } @@ -1162,6 +1164,7 @@ trait Parsers { simpleExpr() } } + def xmlLiteral(): Tree /* SimpleExpr ::= new (ClassTemplate | TemplateBody) * | BlockExpr @@ -1181,14 +1184,12 @@ trait Parsers { case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL => t = literal(false, false) - case XMLSTART if xmlp != null => - assert(xmlp != null) - t = xmlp.xLiteral + case XMLSTART => t = xmlLiteral() case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER => t = path(true, false) case USCORE => - val pname = freshName("x$") val pos = inSkipToken + val pname = freshName(pos, "x$") val param = atPos(pos){ makeSyntheticParam(pname) } placeholderParams = param :: placeholderParams t = atPos(pos) { Ident(pname) } @@ -1196,7 +1197,7 @@ trait Parsers { val pos = inSkipToken val ts = if (inToken == RPAREN) List() else exprs() accept(RPAREN) - t = Parens(ts) setPos g2p(pos) + t = Parens(ts) setPos (pos) case LBRACE => t = blockExpr() canApply = false @@ -1222,12 +1223,15 @@ trait Parsers { val t1 = stripParens(t) t1 match { case Ident(_) | Select(_, _) => - simpleExprRest(atPos(inCurrentPos) { TypeApply(t1, typeArgs(false, true)) }, true) + val pos = if (t1.pos == NoPosition) i2p(inCurrentPos) else t1.pos + simpleExprRest(atPos(pos) { TypeApply(t1, typeArgs(false, true)) }, true) case _ => t1 } case LPAREN | LBRACE if (canApply) => - simpleExprRest(atPos(inCurrentPos) { Apply(stripParens(t), argumentExprs()) }, true) + // again, position should be on idetifier, not ( + var pos = if (t.pos == NoPosition) i2p(inCurrentPos) else t.pos + simpleExprRest(atPos(pos) { Apply(stripParens(t), argumentExprs()) }, true) case USCORE => atPos(inSkipToken) { Typed(stripParens(t), Function(List(), EmptyTree)) } case _ => @@ -1242,9 +1246,7 @@ trait Parsers { if (inToken == LBRACE) { List(blockExpr()) } else { - accept(LPAREN) - val ts = if (inToken == RPAREN) List() else exprs() - accept(RPAREN) + val ts = surround(LPAREN,RPAREN)(if (inToken == RPAREN) List() else exprs(), List()) ts } } @@ -1252,7 +1254,8 @@ trait Parsers { /** BlockExpr ::= `{' (CaseClauses | Block) `}' */ def blockExpr(): Tree = { - val res = atPos(accept(LBRACE)) { + assert(inToken == LBRACE) + val res = atPos(accept(LBRACE)) { // no need to surround if (inToken == CASE) Match(EmptyTree, caseClauses()) else block() } @@ -1302,7 +1305,7 @@ trait Parsers { inNextToken if (newStyle) { if (inToken == IF) enums += Filter(guard()) - else generator(enums, true) + else generator(enums, true) } else { if (inToken == VAL) generator(enums, true) else enums += Filter(expr()) @@ -1314,8 +1317,8 @@ trait Parsers { /** Generator ::= val Pattern1 `<-' Expr [Guard] */ def generator(enums: ListBuffer[Enumerator], eqOK: Boolean) { - val pos = inCurrentPos; if (inToken == VAL) inNextToken + val pos = inCurrentPos; val pat = pattern1(false) val tok = inToken if (tok == EQUALS && eqOK) inNextToken @@ -1335,9 +1338,10 @@ trait Parsers { def patterns(seqOK: Boolean): List[Tree] = { val ts = new ListBuffer[Tree] + pattern(seqOK) while (inToken == COMMA) { - inNextToken; + val pos = inCurrentPos + inNextToken if (inToken == RPAREN) { - in.deprecationWarning(in.pos, "Trailing commas have been deprecated") + deprecationWarning(pos, "Trailing commas have been deprecated") return ts.toList } else { ts += pattern(seqOK) @@ -1435,6 +1439,8 @@ trait Parsers { stripParens(reduceStack(false, base, top, 0, true)) } + def xmlLiteralPattern() : Tree + /** SimplePattern ::= varid * | `_' * | literal @@ -1474,7 +1480,7 @@ trait Parsers { } else */ if (inToken == LPAREN) { - atPos(inCurrentPos) { Apply(t, argumentPatterns()) } + atPos(t.pos) { Apply(t, argumentPatterns()) } } else t case USCORE => atPos(inSkipToken) { Ident(nme.WILDCARD) } @@ -1484,10 +1490,8 @@ trait Parsers { val pos = inSkipToken val ps = if (inToken == RPAREN) List() else patterns(false) accept(RPAREN) - Parens(ps) setPos g2p(pos) - case XMLSTART if xmlp != null => - assert(xmlp != null) - xmlp.xLiteralPattern + Parens(ps) setPos (pos) + case XMLSTART => xmlLiteralPattern() case _ => syntaxErrorOrIncomplete("illegal start of simple pattern", true) errorPatternTree @@ -1597,7 +1601,7 @@ trait Parsers { def annotations(): List[Annotation] = { var annots = new ListBuffer[Annotation] if (inToken == LBRACKET) { - in.deprecationWarning(in.pos, "The [attribute] syntax has been deprecated; use @annotation instead") + deprecationWarning(in.currentPos, "The [attribute] syntax has been deprecated; use @annotation instead") while (inToken == LBRACKET) { inNextToken annots += annotation() @@ -1681,7 +1685,9 @@ trait Parsers { var implicitmod = 0 var caseParam = ofCaseClass def param(): ValDef = { - atPos(inCurrentPos) { + var pos = inCurrentPos + + { val annots = annotations() var mods = Modifiers(Flags.PARAM) if (owner.isTypeName) { @@ -1698,7 +1704,9 @@ trait Parsers { } if (caseParam) mods = mods | Flags.CASEACCESSOR } + val namePos = inCurrentPos val name = ident() + if (name != nme.ERROR) pos = namePos var bynamemod = 0 val tpt = if (settings.Xexperimental.value && !owner.isTypeName && inToken != COLON) { @@ -1715,7 +1723,9 @@ trait Parsers { } paramType() } - ValDef((mods | implicitmod | bynamemod) withAnnotations annots, name, tpt, EmptyTree) + atPos(pos){ + ValDef((mods | implicitmod | bynamemod) withAnnotations annots, name, tpt, EmptyTree) + } } } def paramClause(): List[ValDef] = { @@ -1751,7 +1761,7 @@ trait Parsers { if (inToken == LBRACKET) syntaxError(pos, "no type parameters allowed here", false) else if(inToken == EOF) - incompleteInputError(pos, "auxiliary constructor needs non-implicit parameter list") + incompleteInputError("auxiliary constructor needs non-implicit parameter list") else syntaxError(pos, "auxiliary constructor needs non-implicit parameter list", false) addImplicitViews(owner, result, implicitViews) @@ -1855,7 +1865,8 @@ trait Parsers { def importExpr(): Tree = atPos(inCurrentPos) { var t: Tree = null - var pos : ScanPosition = null.asInstanceOf[ScanPosition] + //var pos : ScanPosition = null.asInstanceOf[ScanPosition] + var pos : Int = -1 if (inToken == THIS) { t = atPos(inCurrentPos) { This(nme.EMPTY.toTypeName) } t = atPos(accept(DOT)) { selector(t) } @@ -1879,7 +1890,9 @@ trait Parsers { } else if (inToken == LBRACE) { Import(t, importSelectors()) } else { - val name = ident() + val identPos = inCurrentPos + val name = ident() // @S: use position of identifier, not dot! + pos = if (name == nme.ERROR) pos else identPos if (inToken == DOT) { t = atPos(pos) { Select(t, name) } pos = accept(DOT) @@ -1932,7 +1945,6 @@ trait Parsers { * | var ValDcl * | def FunDcl * | type [nl] TypeDcl - * XXX: Hook for IDE. */ def defOrDcl(mods: Modifiers): List[Tree] = { if ((mods.hasFlag(Flags.LAZY)) && in.token != VAL) @@ -1952,6 +1964,11 @@ trait Parsers { List(tmplDef(mods)) } } + /** IDE hook: for non-local defs or dcls with modifiers and annotations */ + def nonLocalDefOrDcl : List[Tree] = { + val annots = annotations() + defOrDcl(modifiers() withAnnotations annots) + } /** PatDef ::= Pattern2 {`,' Pattern2} [`:' Type] `=' Expr * ValDcl ::= Id {`,' Id} `:' Type @@ -1981,6 +1998,7 @@ trait Parsers { newmods = newmods | Flags.DEFERRED EmptyTree } + var originalUsed = false def mkDefs(p: Tree): List[Tree] = { //Console.println("DEBUG: p = "+p.toString()); // DEBUG val trees = @@ -1989,7 +2007,12 @@ trait Parsers { p else Typed(p, tp), - rhs.duplicate) map atPos(p.pos) + if (inIDE && !originalUsed) { + // because duplicates have weaker status than originals + // need an original. + originalUsed = true + rhs + } else rhs.duplicate) map atPos(p.pos) if (newmods.hasFlag(Flags.DEFERRED)) { trees match { case List(ValDef(_, _, _, EmptyTree)) => @@ -2009,9 +2032,10 @@ trait Parsers { */ def varDefOrDcl(mods: Modifiers): List[Tree] = { var newmods = mods | Flags.MUTABLE - val lhs = new ListBuffer[(ScanPosition, Name)] + val lhs = new ListBuffer[(Int, Name)] do { - lhs += (inSkipToken, ident()) + inNextToken + lhs += (inCurrentPos, ident()) } while (inToken == COMMA) val tp = typedOpt() val rhs = if (tp.isEmpty || inToken == EQUALS) { @@ -2026,8 +2050,13 @@ trait Parsers { newmods = newmods | Flags.DEFERRED EmptyTree } - for ((pos, name) <- lhs.toList) yield - atPos(pos) { ValDef(newmods, name, tp.duplicate, rhs.duplicate) } + var originalUsed = false + for ((pos, name) <- lhs.toList) yield atPos(pos) { + if (inIDE && !originalUsed) { + originalUsed = true + ValDef(newmods, name, tp, rhs) + } else ValDef(newmods, name, tp.duplicate, rhs.duplicate) + } } /** FunDef ::= FunSig `:' Type `=' Expr @@ -2036,18 +2065,23 @@ trait Parsers { * FunDcl ::= FunSig [`:' Type] * FunSig ::= id [FunTypeParamClause] ParamClauses */ - def funDefOrDcl(mods: Modifiers): Tree = - atPos(inSkipToken) { - if (inToken == THIS) { + def funDefOrDcl(mods: Modifiers): Tree = { + var pos = inSkipToken + if (inToken == THIS) { + atPos(inCurrentPos) { inNextToken val vparamss = paramClauses(nme.CONSTRUCTOR, implicitClassViews map (_.duplicate), false) newLineOptWhenFollowedBy(LBRACE) val rhs = if (inToken == LBRACE) constrBlock(vparamss) else { accept(EQUALS); constrExpr(vparamss) } DefDef(mods, nme.CONSTRUCTOR, List(), vparamss, TypeTree(), rhs) - } else { - var newmods = mods - val name = ident() + } + } else { + var newmods = mods + val namePos = inCurrentPos + val name = ident() + if (name != nme.ERROR) pos = namePos + atPos(pos) { val implicitViewBuf = new ListBuffer[Tree] val tparams = typeParamClauseOpt(name, implicitViewBuf) val vparamss = paramClauses(name, implicitViewBuf.toList, false) @@ -2065,6 +2099,8 @@ trait Parsers { DefDef(newmods, name, tparams, vparamss, restype, rhs) } } + } + /** ConstrExpr ::= SelfInvocation * | ConstrBlock @@ -2125,8 +2161,12 @@ trait Parsers { } } - /** XXX: Hook for IDE? */ - def tmplDefHooked(mods: Modifiers): Tree = tmplDef(mods) + /** Hook for IDE, for top-level classes/objects */ + def topLevelTmplDef: Tree = { + val annots = annotations() + val mods = modifiers() withAnnotations annots + tmplDef(mods) + } /** TmplDef ::= [case] class ClassDef * | [case] object ObjectDef @@ -2155,9 +2195,12 @@ trait Parsers { [AccessModifier] ClassParamClauses RequiresTypeOpt ClassTemplateOpt * TraitDef ::= Id [TypeParamClause] RequiresTypeOpt TraitTemplateOpt */ - def classDef(mods: Modifiers): ClassDef = - atPos(inSkipToken) { - val name = ident().toTypeName + def classDef(mods: Modifiers): ClassDef = { + var pos = inSkipToken + var namePos = inCurrentPos + val name = ident().toTypeName + if (name != nme.ERROR) pos = namePos + atPos(pos) { val savedViews = implicitClassViews val implicitViewBuf = new ListBuffer[Tree] val tparams = typeParamClauseOpt(name, implicitViewBuf) @@ -2186,15 +2229,20 @@ trait Parsers { implicitClassViews = savedViews result } + } /** ObjectDef ::= Id ClassTemplateOpt */ - def objectDef(mods: Modifiers): ModuleDef = - atPos(inSkipToken) { - val name = ident() + def objectDef(mods: Modifiers): ModuleDef = { + var pos = inSkipToken + var namePos = inCurrentPos + val name = ident().toTermName + if (name != nme.ERROR) pos = namePos + atPos(pos) { val template = templateOpt(mods, name, NoMods, List()) ModuleDef(mods, name, template) } + } /** ClassParents ::= AnnotType {`(' [Exprs [`,']] `)'} {with AnnotType} @@ -2261,7 +2309,12 @@ trait Parsers { var parents = parents0 if (name != nme.ScalaObject.toTypeName) parents = parents ::: List(scalaScalaObjectConstr) if (mods.hasFlag(Flags.CASE)) parents = parents ::: List(productConstr) - atPos(pos) { Template(parents, self, constrMods, vparamss, argss, body) } + val tree = Template(parents, self, constrMods, vparamss, argss, body) + // @S: if nothing parsed, don't use next position! + // @S: if primary constructor does not always have the same position, then the IDE gets confused. + // @S: since build compiler is used to generate IDE files, don't set position here! + tree + // if (pos == inCurrentPos || inIDE) tree else atPos(pos) {tree} } ////////// TEMPLATES //////////////////////////////////////////////////////////// @@ -2301,8 +2354,10 @@ trait Parsers { /** Packaging ::= package QualId [nl] `{' TopStatSeq `}' */ def packaging(): Tree = { - atPos(accept(PACKAGE)) { - val pkg = qualId() + val pkgPos = accept(PACKAGE) + val pkg = qualId() + val pos = if (pkg.pos != NoPosition) pkg.pos else i2p(pkgPos) + atPos(pos) { newLineOptWhenFollowedBy(LBRACE) accept(LBRACE) val stats = topStatSeq() @@ -2324,6 +2379,7 @@ trait Parsers { stats += packaging() } else if (inToken == IMPORT) { stats ++= importClause() + // XXX: IDE hook this all. } else if (inToken == CLASS || inToken == CASECLASS || inToken == TRAIT || @@ -2332,8 +2388,7 @@ trait Parsers { inToken == LBRACKET || //todo: remove inToken == AT || isModifier) { - val annots = annotations() - stats ++ joinComment(List(tmplDefHooked(modifiers() withAnnotations annots))) + stats ++ joinComment(List(topLevelTmplDef)) } else if (!isStatSep) { syntaxErrorOrIncomplete("expected class or object definition", true) } @@ -2354,11 +2409,11 @@ trait Parsers { var self: ValDef = emptyValDef val stats = new ListBuffer[Tree] if (isExprIntro) { - val first = expr(InTemplate) + val first = expr(InTemplate) // @S: first statement is potentially converted so cannot be stubbed. if (inToken == ARROW) { convertToParam(first) match { - case ValDef(_, name, tpt, EmptyTree) if (name != nme.ERROR) => - self = makeSelfDef(name, tpt) + case tree @ ValDef(_, name, tpt, EmptyTree) if (name != nme.ERROR) => + self = makeSelfDef(name, tpt).setPos(tree.pos) case _ => } inNextToken @@ -2368,10 +2423,9 @@ trait Parsers { if (inToken == IMPORT) { stats ++= importClause() } else if (isExprIntro) { - stats += expr(InTemplate) + stats += statement(InTemplate) } else if (isDefIntro || isModifier || inToken == LBRACKET /*todo: remove */ || inToken == AT) { - val annots = annotations() - stats ++ joinComment(defOrDcl(modifiers() withAnnotations annots)) + stats ++= joinComment(nonLocalDefOrDcl) } else if (!isStatSep) { syntaxErrorOrIncomplete("illegal start of definition", true) } @@ -2380,6 +2434,8 @@ trait Parsers { (self, stats.toList) } + + /** RefineStatSeq ::= RefineStat {semi RefineStat} * RefineStat ::= Dcl * | type TypeDef @@ -2388,7 +2444,7 @@ trait Parsers { def refineStatSeq(): List[Tree] = checkNoEscapingPlaceholders { val stats = new ListBuffer[Tree] while (inToken != RBRACE && inToken != EOF) { - if (isDclIntro) { + if (isDclIntro) { // don't IDE hook stats ++= joinComment(defOrDcl(NoMods)) } else if (!isStatSep) { syntaxErrorOrIncomplete("illegal start of declaration", true) @@ -2398,6 +2454,14 @@ trait Parsers { stats.toList } + /** overridable IDE hook for local definitions of blockStatSeq */ + def localDef : List[Tree] = { + val annots = annotations() + val mods = localModifiers() withAnnotations annots + if (!(mods hasFlag ~(Flags.IMPLICIT | Flags.LAZY))) defOrDcl(mods) + else List(tmplDef(mods)) + } + /** BlockStatSeq ::= { BlockStat semi } [ResultExpr] * BlockStat ::= Import * | Annotations [implicit] [lazy] Def @@ -2406,27 +2470,20 @@ trait Parsers { * | */ def blockStatSeq(stats: ListBuffer[Tree]): List[Tree] = checkNoEscapingPlaceholders { - def localDef(mods: Modifiers) = { - if (!(mods hasFlag ~(Flags.IMPLICIT | Flags.LAZY))) stats ++= defOrDcl(mods) - else stats += tmplDefHooked(mods) - if (inToken == RBRACE || inToken == CASE) - syntaxError("block must end in result expression, not in definition", false) - else - acceptStatSep() - if (inToken == RBRACE || inToken == CASE) - stats += Literal(()).setPos(inCurrentPos) - } var last = false while ((inToken != RBRACE) && (inToken != EOF) && (inToken != CASE) && !last) { if (inToken == IMPORT) { stats ++= importClause() acceptStatSep() } else if (isExprIntro) { - stats += expr(InBlock) + stats += statement(InBlock) if (inToken != RBRACE && inToken != CASE) acceptStatSep() } else if (isDefIntro || isLocalModifier || in.token == AT) { - val annots = annotations() - localDef(localModifiers() withAnnotations annots) + stats ++= localDef + if (inToken == RBRACE || inToken == CASE) { + syntaxError("block must end in result expression, not in definition", false) + stats += Literal(()).setPos(inCurrentPos) + } else acceptStatSep() } else if (isStatSep) { inNextToken } else { @@ -2437,12 +2494,14 @@ trait Parsers { } /** CompilationUnit ::= [package QualId semi] TopStatSeq - * - * XXX: hook in IDE? */ - def compilationUnit(): Tree = - atPos(inCurrentPos) { + def compilationUnit(): Tree = { + var pos = inCurrentPos; + { val ts = new ListBuffer[Tree] + // @S: the IDE can insert phantom semi-colons before package during editing + // @S: just eat them (doesn't really change the grammar) + while (inToken == SEMI) inNextToken if (inToken == PACKAGE) { inNextToken val pkg = qualId() @@ -2464,10 +2523,12 @@ trait Parsers { assert(placeholderParams.isEmpty) assert(placeholderTypes.isEmpty) val stats = ts.toList - stats match { + val usePos = if (stats.isEmpty || stats.head.pos == NoPosition) i2p(pos) else stats.head.pos + atPos(usePos) { stats match { case List(stat @ PackageDef(_, _)) => stat case _ => makePackaging(Ident(nme.EMPTY_PACKAGE_NAME), stats) - } + }} } + } } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index d55f97ae08..2ac58e4a0d 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -6,17 +6,13 @@ package scala.tools.nsc.ast.parser -import scala.tools.nsc.util.{CharArrayReader, Position, OffsetPosition, - SourceFile} +import scala.tools.nsc.util._ import SourceFile.{LF, FF, CR, SU} import Tokens._ trait Scanners { - self: SyntaxAnalyzer => + val global : Global import global._ - - /** ... - */ abstract class AbstractTokenData { def token: Int type ScanPosition @@ -60,7 +56,6 @@ trait Scanners { abstract class AbstractScanner extends AbstractTokenData { implicit def p2g(pos: Position): ScanPosition implicit def g2p(pos: ScanPosition): Position - def configuration: ScannerConfiguration def warning(pos: ScanPosition, msg: String): Unit def error (pos: ScanPosition, msg: String): Unit def incompleteInputError(pos: ScanPosition, msg: String): Unit @@ -81,7 +76,7 @@ trait Scanners { def flushDoc: String } - trait ScannerConfiguration { + object ScannerConfiguration { // Keywords ----------------------------------------------------------------- /** Keyword array; maps from name indices to tokens */ private var key: Array[Byte] = _ @@ -268,9 +263,6 @@ trait Scanners { ret } - /** Process comments and strings in scanner */ - protected def matchInScanner = true - /** add the given character to the documentation buffer */ protected def putDocChar(c: Char) { @@ -288,6 +280,16 @@ trait Scanners { */ var sepRegions: List[Int] = List() + /** A new line was inserted where in version 1.0 it would not be. + * Only significant if settings.migrate.value is set + */ + var newNewLine = false + + /** Parser is currently skipping ahead because of an error. + * Only significant if settings.migrate.value is set + */ + var skipping = false + // Get next token ------------------------------------------------------------ /** read next token and return last position @@ -421,23 +423,6 @@ trait Scanners { in.next getOperatorRest; // XXX return - - case '/' if !matchInScanner => - in.next - if (in.ch == '/') { - in.next; token = LINE_COMMENT - return - } else if (in.ch == '*') { - in.next - if (in.ch == '*') { - in.next; token = DOC_START - } else token = COMMENT_START - return - } else { - putChar('/') - getOperatorRest - return - } case '/' => in.next if (!skipComment()) { @@ -461,27 +446,10 @@ trait Scanners { base = 10 getNumber return - case '`' if !matchInScanner => - in.next; token = BACK_QUOTE - return case '`' => in.next getStringLit('`', BACKQUOTED_IDENT) return - case '\"' if !matchInScanner => - in.next - if (in.ch == '\"') { - in.next - if (in.ch == '\"') { - in.next; token = MULTI_QUOTE - } else { - token = throw new Error - } - return - } else { - token = DOUBLE_QUOTE - return - } case '\"' => in.next if (in.ch == '\"') { @@ -577,7 +545,8 @@ trait Scanners { in.next; token = RPAREN return case '}' => - in.next; token = RBRACE + in.next; + token = RBRACE return case '[' => in.next; token = LBRACKET @@ -611,7 +580,6 @@ trait Scanners { } private def skipComment(): Boolean = { - assert(matchInScanner) if (in.ch == '/') { do { in.next @@ -710,6 +678,7 @@ trait Scanners { '5' | '6' | '7' | '8' | '9' => putChar(in.ch) in.next + case '_' => putChar(in.ch) in.next @@ -717,7 +686,7 @@ trait Scanners { return case SU => setName - token = configuration.name2token(name) + token = ScannerConfiguration.name2token(name) return case _ => if (Character.isUnicodeIdentifierPart(in.ch)) { @@ -725,7 +694,7 @@ trait Scanners { in.next } else { setName - token = configuration.name2token(name) + token = ScannerConfiguration.name2token(name) return } } @@ -743,14 +712,9 @@ trait Scanners { in.next case '/' => in.next - if (matchInScanner && skipComment) { - setName - token = configuration.name2token(name) - return - } else if (!matchInScanner && (in.ch == '*' || in.ch == '/')) { - in.rewind + if (skipComment) { setName - token = configuration.name2token(name) + token = ScannerConfiguration.name2token(name) return } else putChar('/') case _ => @@ -759,7 +723,7 @@ trait Scanners { in.next } else { setName - token = configuration.name2token(name) + token = ScannerConfiguration.name2token(name) return } } @@ -779,13 +743,12 @@ trait Scanners { if (isSpecial(in.ch)) getOperatorRest else { setName - token = configuration.name2token(name) + token = ScannerConfiguration.name2token(name) } } } private def getStringLit(delimiter: Char, litType: Int) { - assert(matchInScanner) //assert((litType==STRINGLIT) || (litType==IDENTIFIER)) while (in.ch != delimiter && (in.isUnicode || in.ch != CR && in.ch != LF && in.ch != SU)) { getlitch() @@ -801,7 +764,6 @@ trait Scanners { } private def getMultiLineStringLit { - assert(matchInScanner) if (in.ch == '\"') { in.next if (in.ch == '\"') { @@ -1049,7 +1011,7 @@ trait Scanners { case COMMA => "," case _ => - configuration.token2string(token) + ScannerConfiguration.token2string(token) } /** INIT: read lookahead character and token. @@ -1062,9 +1024,8 @@ trait Scanners { /** ... */ - class UnitScanner(unit: CompilationUnit) extends Scanner with ScannerConfiguration { - override def configuration = this - val in = new CharArrayReader(unit.source.getContent(), !settings.nouescape.value, syntaxError) + class UnitScanner(unit: CompilationUnit) extends Scanner { + val in = new CharArrayReader(unit.source.asInstanceOf[BatchSourceFile].content, !settings.nouescape.value, syntaxError) def warning(pos: Int, msg: String) = unit.warning(pos, msg) def error (pos: Int, msg: String) = unit. error(pos, msg) def incompleteInputError(pos: Int, msg: String) = unit.incompleteInputError(pos, msg) diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala index 7d2e51b240..baa7eabaef 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala @@ -8,7 +8,7 @@ package scala.tools.nsc.ast.parser /** An nsc sub-component. */ -abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParsers with Scanners { +abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParsers with NewScanners { val phaseName = "parser" @@ -17,7 +17,8 @@ abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParse class ParserPhase(prev: scala.tools.nsc.Phase) extends StdPhase(prev) { def apply(unit: global.CompilationUnit) { global.informProgress("parsing " + unit) - unit.body = new UnitParser(unit).parse() + val parser = new UnitParser(unit) + unit.body = parser.parse() } } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala index 959fba033e..1f04ad22de 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala @@ -31,6 +31,16 @@ object Tokens { def isIdentifier(code : Int) = code >= IDENTIFIER && code <= BACKQUOTED_IDENT + def canBeginExpression(code : Int) = code match { + case IDENTIFIER|BACKQUOTED_IDENT|USCORE => true + case LBRACE|LPAREN|LBRACKET|COMMENT|STRINGLIT => true + case IF|DO|WHILE|FOR|NEW|TRY|THROW => true + case NULL|THIS|TRUE|FALSE => true + case code if isLiteral(code) => true + case _ => false + } + + /** keywords */ final val IF = 20 final val FOR = 21 @@ -79,6 +89,14 @@ object Tokens { def isKeyword(code : Int) = code >= IF && code <= LAZY + def isDefinition(code : Int) = code match { + case CLASS|TRAIT|OBJECT => true + case CASECLASS|CASEOBJECT => true + case DEF|VAL|VAR => true + case TYPE => true + case _ => false + } + /** special symbols */ final val COMMA = 70 @@ -100,7 +118,6 @@ object Tokens { def isSymbol(code : Int) = code >= COMMA && code <= VIEWBOUND - /** parenthesis */ final val LPAREN = 90 final val RPAREN = 91 @@ -109,24 +126,29 @@ object Tokens { final val LBRACE = 94 final val RBRACE = 95 - def isParen(code : Int) = + def isBrace(code : Int) = code >= LPAREN && code <= RBRACE + def isOpenBrace(code : Int) = isBrace(code) && (code % 2 == 0) + def isCloseBrace(code : Int) = isBrace(code) && (code % 2 == 1) /** XML mode */ final val XMLSTART = 96 /** for IDE only */ - final val LINE_COMMENT = 97 - final val COMMENT_START = 98 - final val COMMENT_END = 99 - final val DOC_START = 100 - final val DOUBLE_QUOTE = 101 - final val BACK_QUOTE = 102 - final val MULTI_QUOTE = 103 - //final val EMPTY_STRING = 104 + final val COMMENT = 97 + final val WHITESPACE = 105 final val IGNORE = 106 - final val XML_SINGLEEND = 107 - final val XML_STARTEND = 108 final val ESCAPE = 109 + + def isSpace(at : Char) = at match { + case ' ' | '\t' => true + case _ => false + } + import scala.tools.nsc.util.SourceFile._ + + def isNewLine(at : Char) = at match { + case CR | LF | FF => true + case _ => false + } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 0ba8c78e5d..240c2519d2 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -15,9 +15,8 @@ abstract class TreeBuilder { val global: Global import global._ import posAssigner.atPos; - def freshName(prefix: String, pos: Position): Name - - def freshName(pos : Position): Name = freshName("x$", pos) + def freshName(pos : Position, prefix: String): Name + def freshName(pos : Position): Name = freshName(pos, "x$") def scalaDot(name: Name): Tree = Select(Ident(nme.scala_) setSymbol definitions.ScalaPackage, name) @@ -57,16 +56,16 @@ abstract class TreeBuilder { /** Traverse pattern and collect all variable names with their types in buffer */ private object getvarTraverser extends Traverser { - val buf = new ListBuffer[(Name, Tree)] + val buf = new ListBuffer[(Name, Tree, Position)] def init: Traverser = { buf.clear; this } override def traverse(tree: Tree): Unit = tree match { case Bind(name, Typed(tree1, tpt)) => if ((name != nme.WILDCARD) && (buf.elements forall (name !=))) - buf += (name, if (treeInfo.mayBeTypePat(tpt)) TypeTree() else tpt) + buf += (name, if (treeInfo.mayBeTypePat(tpt)) TypeTree() else tpt, tree.pos) traverse(tree1) case Bind(name, tree1) => if ((name != nme.WILDCARD) && (buf.elements forall (name !=))) - buf += (name, TypeTree()) + buf += (name, TypeTree(), tree.pos) traverse(tree1) case _ => super.traverse(tree) @@ -76,7 +75,7 @@ abstract class TreeBuilder { /** Returns list of all pattern variables, possibly with their types, * without duplicates */ - private def getVariables(tree: Tree): List[(Name, Tree)] = { + private def getVariables(tree: Tree): List[(Name, Tree,Position)] = { getvarTraverser.init.traverse(tree) getvarTraverser.buf.toList } @@ -378,7 +377,7 @@ abstract class TreeBuilder { /** Create visitor <x => x match cases> */ def makeVisitor(cases: List[CaseDef], checkExhaustive: Boolean, prefix: String): Tree = { - val x = freshName(prefix, posAssigner.pos) + val x = freshName(posAssigner.pos, prefix) val sel = if (checkExhaustive) Ident(x) else makeUnchecked(Ident(x)) Function(List(makeSyntheticParam(x)), Match(sel, cases)) } @@ -394,7 +393,7 @@ abstract class TreeBuilder { /** Create tree for pattern definition <mods val pat0 = rhs> */ def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree): List[Tree] = matchVarPattern(pat) match { case Some((name, tpt)) => - List(ValDef(mods, name, tpt, rhs)) + List(ValDef(mods, name, tpt, rhs).setPos(pat.pos)) case None => // in case there are no variables in pattern @@ -418,14 +417,14 @@ abstract class TreeBuilder { vars match { case List() => List(matchExpr) - case List((vname, tpt)) => - List(ValDef(mods, vname, tpt, matchExpr)) + case List((vname, tpt, pos)) => + List(ValDef(mods, vname, tpt, matchExpr).setPos(pos)) case _ => val tmp = freshName(pat1.pos) val firstDef = ValDef(Modifiers(PRIVATE | LOCAL | SYNTHETIC | (mods.flags & LAZY)), tmp, TypeTree(), matchExpr) var cnt = 0 - val restDefs = for (val (vname, tpt) <- vars) yield { + val restDefs = for (val (vname, tpt, pos) <- vars) yield atPos(pos) { cnt = cnt + 1 ValDef(mods, vname, tpt, Select(Ident(tmp), newTermName("_" + cnt))) } @@ -446,7 +445,7 @@ abstract class TreeBuilder { /** Append implicit view section if for `implicitViews' if nonempty */ def addImplicitViews(owner: Name, vparamss: List[List[ValDef]], implicitViews: List[Tree]): List[List[ValDef]] = { val mods = Modifiers(if (owner.isTypeName) PARAMACCESSOR | LOCAL | PRIVATE else PARAM) - def makeViewParam(tpt: Tree) = ValDef(mods | IMPLICIT, freshName("view$", tpt.pos), tpt, EmptyTree) + def makeViewParam(tpt: Tree) = ValDef(mods | IMPLICIT, freshName(tpt.pos, "view$"), tpt, EmptyTree) if (implicitViews.isEmpty) vparamss else vparamss ::: List(implicitViews map makeViewParam) } @@ -454,9 +453,9 @@ abstract class TreeBuilder { /** Create a tree representing a packaging */ def makePackaging(pkg: Tree, stats: List[Tree]): PackageDef = pkg match { case Ident(name) => - PackageDef(name, stats) + PackageDef(name, stats).setPos(pkg.pos) case Select(qual, name) => - makePackaging(qual, List(PackageDef(name, stats))) + makePackaging(qual, List(PackageDef(name, stats).setPos(pkg.pos))) } case class Parens(args: List[Tree]) extends Tree diff --git a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala index 90fec80c0b..a6a7174181 100644 --- a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala +++ b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala @@ -623,6 +623,7 @@ abstract class ScalaPrimitives { } case LENGTH => + assert(elem != null) toTypeKind(elem) match { case BOOL => ZARRAY_LENGTH case BYTE => BARRAY_LENGTH diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index ce917e5386..4d1e646b95 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -83,7 +83,7 @@ abstract class GenICode extends SubComponent { addClassFields(ctx, tree.symbol); classes += tree.symbol -> ctx.clazz unit.icode += ctx.clazz - gen(impl, ctx) + gen(impl, ctx) ctx setClass null // !! modules should be eliminated by refcheck... or not? @@ -417,7 +417,7 @@ abstract class GenICode extends SubComponent { var thenCtx = ctx.newBlock var elseCtx = ctx.newBlock val contCtx = ctx.newBlock - genCond(cond, ctx, thenCtx, elseCtx) + genCond(cond, ctx, thenCtx, elseCtx) val ifKind = toTypeKind(tree.tpe) val thenKind = toTypeKind(thenp.tpe) @@ -1427,6 +1427,8 @@ abstract class GenICode extends SubComponent { ctx.method.symbol.newVariable(l.pos, eqEqTempName).setFlag(Flags.SYNTHETIC) eqEqTempVar.setInfo(definitions.AnyRefClass.typeConstructor) val local = ctx.method.addLocal(new Local(eqEqTempVar, REFERENCE(definitions.AnyRefClass), false)) + assert(l.pos.source.get == unit.source) + assert(r.pos.source.get == unit.source) local.start = (l.pos).line.get local.end = (r.pos).line.get local diff --git a/src/compiler/scala/tools/nsc/backend/icode/Printers.scala b/src/compiler/scala/tools/nsc/backend/icode/Printers.scala index d5c158f3a6..d74b77efd6 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Printers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Printers.scala @@ -127,7 +127,7 @@ trait Printers { self: ICodes => if (settings.Xdce.value) print(if (i.useful) " " else " * "); if (settings.debug.value) - print(i.pos.line) + print(i.pos.line.map(_.toString).getOrElse("No line")) println(i.toString()); } } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index d8a8d8b2c9..726bc6d69c 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -974,6 +974,8 @@ abstract class GenJVM extends SubComponent { } crtPC = jcode.getPC() + + assert(instr.pos.source.isEmpty || instr.pos.source.get == (clasz.cunit.source), "sources don't match") val crtLine = instr.pos.line.get(lastLineNr); /* val crtLine = try { @@ -1148,7 +1150,7 @@ abstract class GenJVM extends SubComponent { log("Converting from: " + src + " to: " + dst); if (dst == BOOL) { Console.println("Illegal conversion at: " + clasz + - " at: " + method.sourceFile + ":" + pos.line.get(-1)); + " at: " + pos.source.get + ":" + pos.line.get(-1)); } else jcode.emitT2T(javaType(src), javaType(dst)); diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala index 4111f2ec84..047bf656eb 100644 --- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala +++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala @@ -1205,7 +1205,7 @@ abstract class GenMSIL extends SubComponent { needAdditionalRet = false - val currentLineNr = (instr.pos).line match { + val currentLineNr = (instr.pos).line match { case Some(line) => line case None => log("Warning: wrong position in: " + method) @@ -1659,8 +1659,8 @@ abstract class GenMSIL extends SubComponent { case DOUBLE => mcode.Emit(OpCodes.Conv_R8) case _ => Console.println("Illegal conversion at: " + clasz + - " at: " + method.sourceFile + ":" + - pos.line.get) + " at: " + pos.source.get + ":" + + pos.line.get) } case ArrayLength(_) => diff --git a/src/compiler/scala/tools/nsc/doc/DocDriver.scala b/src/compiler/scala/tools/nsc/doc/DocDriver.scala index 819591aaef..e4ee365c5d 100644 --- a/src/compiler/scala/tools/nsc/doc/DocDriver.scala +++ b/src/compiler/scala/tools/nsc/doc/DocDriver.scala @@ -17,7 +17,6 @@ import scala.xml._ */ abstract class DocDriver extends ModelFrames with ModelToXML { import global._ - object additions extends jcl.LinkedHashSet[Symbol] object additions0 extends ModelAdditions(global) { override def addition(sym: global.Symbol) = { @@ -42,7 +41,7 @@ abstract class DocDriver extends ModelFrames with ModelToXML { case _ => } } - def f(pkg: Package, tree: Tree): Unit = if (!tree.symbol.hasFlag(symtab.Flags.PRIVATE)) tree match { + def f(pkg: Package, tree: Tree): Unit = if (tree != EmptyTree && !tree.symbol.hasFlag(symtab.Flags.PRIVATE)) tree match { case tree : PackageDef => val pkg1 = new Package(tree.symbol.asInstanceOf[ModuleSymbol]); tree.stats.foreach(stat => f(pkg1, stat)) diff --git a/src/compiler/scala/tools/nsc/doc/ModelFrames.scala b/src/compiler/scala/tools/nsc/doc/ModelFrames.scala index d2b86c3bd6..f93e502baf 100644 --- a/src/compiler/scala/tools/nsc/doc/ModelFrames.scala +++ b/src/compiler/scala/tools/nsc/doc/ModelFrames.scala @@ -23,6 +23,7 @@ trait ModelFrames extends ModelExtractor { val SyntheticClasses = new scala.collection.mutable.HashSet[global.Symbol]; { import global.definitions._ + global.definitions.init SyntheticClasses ++= List( AllClass, AllRefClass, AnyClass, AnyRefClass, AnyValClass, //value classes diff --git a/src/compiler/scala/tools/nsc/io/AbstractFile.scala b/src/compiler/scala/tools/nsc/io/AbstractFile.scala index 8c084c8266..36c17ef6c9 100644 --- a/src/compiler/scala/tools/nsc/io/AbstractFile.scala +++ b/src/compiler/scala/tools/nsc/io/AbstractFile.scala @@ -102,7 +102,10 @@ abstract class AbstractFile extends AnyRef with Iterable[AbstractFile] { /** Returns the path of this abstract file. */ def path: String - /** Returns the underlying File if any and <code>null</code> otherwise. */ + /** Returns the containing directory of this abstract file */ + def container : AbstractFile + + /** Returns the underlying File if any and null otherwise. */ def file: File /** Is this abstract file a directory? */ diff --git a/src/compiler/scala/tools/nsc/io/PlainFile.scala b/src/compiler/scala/tools/nsc/io/PlainFile.scala index c69123a19e..a8eba28f05 100644 --- a/src/compiler/scala/tools/nsc/io/PlainFile.scala +++ b/src/compiler/scala/tools/nsc/io/PlainFile.scala @@ -37,6 +37,8 @@ class PlainFile(val file: File) extends AbstractFile { /** Returns the path of this abstract file. */ def path = file.getPath() + override def container : AbstractFile = new PlainFile(file.getParentFile) + override def input = new FileInputStream(file) override def size = Some(file.length.toInt) diff --git a/src/compiler/scala/tools/nsc/io/VirtualFile.scala b/src/compiler/scala/tools/nsc/io/VirtualFile.scala index c1a49067e8..ec1e4396c7 100644 --- a/src/compiler/scala/tools/nsc/io/VirtualFile.scala +++ b/src/compiler/scala/tools/nsc/io/VirtualFile.scala @@ -30,6 +30,12 @@ class VirtualFile(val name: String, _path: String) extends AbstractFile { */ def this(name: String) = this(name, name) + override def hashCode = name.hashCode + override def equals(that : Any) = that match { + case that : VirtualFile => name == that.name + case _ => false + } + //######################################################################## // Public Methods @@ -38,7 +44,9 @@ class VirtualFile(val name: String, _path: String) extends AbstractFile { /** Returns null. */ final def file: File = null - def input: InputStream = throw new Error("not supported") + def input : InputStream = throw new Error("not supported"); + + def container : AbstractFile = throw new Error("not supported") /** Is this abstract file a directory? */ def isDirectory: Boolean = false diff --git a/src/compiler/scala/tools/nsc/io/ZipArchive.scala b/src/compiler/scala/tools/nsc/io/ZipArchive.scala index 575e2ec854..50c783857d 100644 --- a/src/compiler/scala/tools/nsc/io/ZipArchive.scala +++ b/src/compiler/scala/tools/nsc/io/ZipArchive.scala @@ -106,7 +106,7 @@ final class ZipArchive(file: File, val archive: ZipFile) extends PlainFile(file) /** Loads the archive and creates the root directory. */ private def load() { - this.root = new DirEntry("<root>", "/") + this.root = new DirEntry(this, "<root>", "/") // A path to DirEntry map val dirs: Map[String, DirEntry] = new HashMap() dirs.update("/", root) @@ -126,7 +126,7 @@ final class ZipArchive(file: File, val archive: ZipFile) extends PlainFile(file) val home = if (index < 0) "/" else path.substring(0, index + 1) val parent: DirEntry = getDir(dirs, home) assert(!parent.entries.contains(path), this.toString() + " - " + path) - parent.entries.update(name, new FileEntry(name, path, entry)) + parent.entries.update(name, new FileEntry(parent, name, path, entry)) } } } @@ -141,32 +141,33 @@ final class ZipArchive(file: File, val archive: ZipFile) extends PlainFile(file) dirs.get(path) match { case Some(dir) => dir case None => - val index = path.lastIndexOf('/', path.length() - 2) - val name = if (index < 0) path else path.substring(index + 1) - val home = if (index < 0) "/" else path.substring(0, index + 1) - val parent: DirEntry = getDir(dirs, home) - val dir = new DirEntry(name.substring(0, name.length() - 1), path) - parent.entries.update(name, dir) - dirs.update(path, dir) + val index = path.lastIndexOf('/', path.length() - 2); + val name = if (index < 0) path else path.substring(index + 1); + val home = if (index < 0) "/" else path.substring(0, index + 1); + val parent: DirEntry = getDir(dirs, home); + val dir = new DirEntry(parent, name.substring(0, name.length() - 1), path); + parent.entries.update(name, dir); + dirs.update(path, dir); dir - } + } //######################################################################## // Private Class - Entry /** Superclass of archive entries */ - abstract class Entry(name: String, path: String) - extends VirtualFile(name, path) { - final override def path = ZipArchive.this.toString() + "(" + super.path + ")" + abstract class Entry(override val container : AbstractFile, name: String, path: String) + extends VirtualFile(name, path) { + final override def path = ZipArchive.this.toString() + "(" + pathInArchive + ")" final def getArchive = ZipArchive.this.archive + def pathInArchive = super.path } //######################################################################## // Private Class - DirEntry /** A directory archive entry */ - private final class DirEntry(name: String, path: String) - extends Entry(name, path) + private final class DirEntry(container : AbstractFile, name: String, path: String) + extends Entry(container, name, path) { val entries: Map[String, Entry] = new HashMap() @@ -185,15 +186,15 @@ final class ZipArchive(file: File, val archive: ZipFile) extends PlainFile(file) entries.get(if (directory) name + "/" else name) match { case Some(dir) => dir case None => null - } + } } //######################################################################## // Private Class - FileEntry /** A regular file archive entry */ - final class FileEntry(name: String, path: String, val entry: ZipEntry) - extends Entry(name, path) { + final class FileEntry(container : AbstractFile, name: String, path: String, val entry: ZipEntry) + extends Entry(container, name, path) { def archive = ZipArchive.this.archive override def lastModified: Long = entry.getTime() override def input = archive.getInputStream(entry) @@ -213,6 +214,8 @@ final class URLZipArchive(url: URL) extends AbstractFile { private var root: DirEntry = _ + def container = throw new Error("unsupported") + def name: String = url.getFile() def path: String = url.getPath() diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 5c0e05ebfc..ba7c802464 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -899,8 +899,8 @@ trait ParallelMatching { //Console.println("case temps"+caseTemps.toString) try{ - var vdefs = caseTemps map { - case (tmp,accessorMethod) => + var vdefs = caseTemps map {p => + val tmp = p._1; val accessorMethod = p._2 //Console.println("tmp: "+tmp+":"+tmp.tpe) //Console.println("accessorMethod: "+accessorMethod+":"+accessorMethod.tpe) val untypedAccess = Apply(Select(mkIdent(casted), accessorMethod),List()) diff --git a/src/compiler/scala/tools/nsc/models/SemanticTokens.scala b/src/compiler/scala/tools/nsc/models/SemanticTokens.scala index 61095aeb83..f8b6f26545 100644 --- a/src/compiler/scala/tools/nsc/models/SemanticTokens.scala +++ b/src/compiler/scala/tools/nsc/models/SemanticTokens.scala @@ -11,7 +11,7 @@ import java.lang.Character.isJavaIdentifierPart import scala.collection.mutable.{HashMap,HashSet} import scala.tools.nsc.Global import scala.tools.nsc.symtab.{Flags,Names} -import scala.tools.nsc.util.{NameTransformer,Position,SourceFile,NoPosition} +import scala.tools.nsc.util.{NameTransformer,Position,SourceFile,BatchSourceFile, NoPosition} import scala.tools.nsc.symtab.Flags.DEFERRED class SemanticTokens(val compiler: Global) { @@ -35,10 +35,10 @@ class SemanticTokens(val compiler: Global) { def next: HasPrev } - def eatKeyword(source: SourceFile, pos: Int, keywords: List[String]) : Int = { + def eatKeyword(source: BatchSourceFile, pos: Int, keywords: List[String]) : Int = { if (keywords.isEmpty) pos - else if (pos == source.content.length) + else if (pos == source.length) -1 else if (source.beginsWith(pos, " ")) eatKeywords(source, pos + 1) @@ -48,7 +48,7 @@ class SemanticTokens(val compiler: Global) { eatKeyword(source, pos, keywords.tail) } - def eatKeywords(source: SourceFile, pos: Int): Int = { + def eatKeywords(source: BatchSourceFile, pos: Int): Int = { val keywords = "package" :: "val" :: "var" :: "def" :: "class" :: "trait" :: "override" :: "case" :: "object" :: "sealed" :: "private" :: "protected" :: Nil @@ -202,12 +202,10 @@ class SemanticTokens(val compiler: Global) { def build(tree0: Tree) : Unit = try { /* if (tree0.pos != NoPosition) */ tree0 match { case tree: ImplDef => - val pos = eatKeywords(unit.source, tree.pos.offset.get) + val pos = eatKeywords(unit.source.asInstanceOf[BatchSourceFile], tree.pos.offset.get) if (pos == -1) { - // inner types. - // Console.err.println("NOPOS: " + tree.getClass() + " " + (new Position(unit.source, tree.pos)).dbgString); - //Thread.dumpStack(); - } else buildDef(tree.symbol, eatKeywords(unit.source, tree.pos.offset.get)); + + } else buildDef(tree.symbol, eatKeywords(unit.source.asInstanceOf[BatchSourceFile], tree.pos.offset.get)); tree match { case cdef: ClassDef => build(cdef.tparams) case _ => ; @@ -222,7 +220,7 @@ class SemanticTokens(val compiler: Global) { // todo: review whether this is correct, or whether abstract getters should be included. { val pos : Int = if (tree.name.toString().equals("<init>")) -1 else - eatKeywords(unit.source, tree.pos.offset.get); + eatKeywords(unit.source.asInstanceOf[BatchSourceFile], tree.pos.offset.get); if (false) Console.err.println("VALDEF: tree=" + tree + " sym=" + tree.symbol + " pos0=" + tree.symbol.pos + " alias=" + tree.symbol.alias + " pos1=" + pos + " pos2=" + tree.pos.dbgString + " " + tree.symbol.hasFlag(Flags.SYNTHETIC)); @@ -261,7 +259,7 @@ class SemanticTokens(val compiler: Global) { case tree: PackageDef => //Console.err.println("PACKAGE: " + tree.name); if (false) { - val pos = eatKeywords(unit.source, tree.pos.offset.get(-1)) + val pos = eatKeywords(unit.source.asInstanceOf[BatchSourceFile], tree.pos.offset.get(-1)) if (pos != -1) buildDef(tree.symbol, pos) } @@ -272,9 +270,9 @@ class SemanticTokens(val compiler: Global) { val pos: Int = if (unit.source.beginsWith(arg.pos.offset.get(-1), "val ")) unit.source.skipWhitespace(arg.pos.offset.get(-1) + ("val ").length()) - else if (unit.source.content(arg.pos.offset.get) == ':') { + else if (unit.source.asInstanceOf[BatchSourceFile].content(arg.pos.offset.get) == ':') { var posx : Int = arg.pos.offset.get - while (unit.source.content(posx - 1).isWhitespace) posx = posx - 1 + while (unit.source.asInstanceOf[BatchSourceFile].content(posx - 1).isWhitespace) posx = posx - 1 posx - name.length() } else arg.pos.offset.get buildDef(arg.symbol, pos) @@ -303,7 +301,6 @@ class SemanticTokens(val compiler: Global) { case ident : Ident => buildUse(tpe0.sym, ident.pos.offset.get(-1), tpe0); case select : Select => if (select.symbol == NoSymbol) - if (false) Console.err.println("BUILD_SELECT: " + select + " @ " + tpe0 + " SYM=" + select.symbol + " " + (select.pos).dbgString); try { // build(select); buildUse(tpe0.typeSymbol, selectPos(select), tpe0); @@ -377,8 +374,6 @@ class SemanticTokens(val compiler: Global) { } case ctype : ConstantType => - if (false) Console.err.println("UNKNOWN CONSTANT_TYPE: " + tree + " " + ctype + " " + (tree.pos).dbgString); - case ErrorType => case _ => { if (false) Console.err.println("UNKNOWN TPE4: " + tree + " " + tpe + " " + tpe.getClass() + " " + (tree.pos).dbgString); @@ -419,7 +414,7 @@ class SemanticTokens(val compiler: Global) { case e : Error => Console.err.println("SELECTQ: " + tree + " " + tree.qualifier + " " + (tree.qualifier.pos).dbgString); throw e; } try { - if (tree.pos.offset.get >= unit.source.content.length) { + if (tree.pos.offset.get >= unit.source.length) { if (false) Console.err.println("BAD_SELECT_QUALIFIER " + tree + " @ " + (tree.pos).dbgString); } else { @@ -437,11 +432,11 @@ class SemanticTokens(val compiler: Global) { build(tree.fun) build(tree.args) case tree: Apply => - //Console.err.println("NORM_APPLY: " + tree + " " + tree.pos.dbgString); + build(tree.fun) build(tree.args) case tree: GenericApply => - //Console.err.println("GEN_APPLY: " + tree + " " + tree.pos.dbgString); + build(tree.fun) build(tree.args) case tree: Typed => @@ -472,7 +467,7 @@ class SemanticTokens(val compiler: Global) { case tree : Try => build(tree.block); build(tree.catches); build(tree.finalizer); case tree : Alternative => build(tree.trees); case tree : This => - //Console.err.println("THIS: " + tree.symbol + " " + tree.qual + " " + tree.pos.dbgString + " " + tree.tpe); + if (tree.symbol ne null) buildUse(tree.symbol, tree.pos.offset.get(-1), tree.tpe); //Thread.dumpStack(); case tree : TypeDef => @@ -506,7 +501,7 @@ class SemanticTokens(val compiler: Global) { } else if (term != NoSymbol) { val name = NameTransformer.decode(term.name.toString()).toString().trim() - val buf = unit.source.content + val buf = unit.source.asInstanceOf[BatchSourceFile].content val cs = name.toChars var idx = 0 if (cs.length + pos > buf.length) return @@ -532,7 +527,7 @@ class SemanticTokens(val compiler: Global) { } def selectPos(tree : Select): Int = if (tree.pos == NoPosition) -1 else { - val buf = unit.source.content + val buf = unit.source.asInstanceOf[BatchSourceFile].content if (tree.pos.offset.get >= buf.length) { if (false) { Console.err.println("" + tree + "@" + tree.pos + " not in " + @@ -598,16 +593,6 @@ class SemanticTokens(val compiler: Global) { if (sem.symbol != tok.symbol && sem.symbol.getClass() == tok.symbol.getClass() && sem.symbol.pos == tok.symbol.pos) return; - - if (false) { - Console.err.println("NOT_GAP: " + sem.symbol + " " + sem.symbol.getClass() + " " + (sem.symbol.pos).dbgString + " " + sem.symbol.flags); - Console.err.println("NOT_GAP: " + tok.symbol + " " + tok.symbol.getClass() + " " + (tok.symbol.pos).dbgString + " " + tok.symbol.flags); - Console.err.println("LIST: " + this); - Console.err.println("POS: " + unit.source.dbg(offset)); - - Thread.dumpStack(); - throw new Error(); - } } else { val gap = cursor.token.asInstanceOf[Gap]; if (!(offset - cursor.offset + tok.length <= gap.length)) { diff --git a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala index 536cbe7e15..7ec8b688e7 100644 --- a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala @@ -44,9 +44,11 @@ abstract class AbstractReporter extends Reporter { */ private def testAndLog(pos: Position): Boolean = { if (pos eq null) return false - if (pos.column == 0) return false + if (pos.offset.isEmpty) return false if (positions contains pos) return true + //Console.println("ERROR @ " + pos + " into " + positions) positions += pos + return false } diff --git a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala index a038959056..519ae106f7 100644 --- a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala @@ -7,7 +7,7 @@ package scala.tools.nsc.reporters import java.io.{BufferedReader, InputStreamReader, IOException, PrintWriter} -import util.{FakePos,Position,NoPosition} +import util._ import compat.StringBuilder @@ -48,20 +48,24 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr /** Prints the message with the given position indication. */ def printMessage(posIn: Position, msg: String): Unit = if (posIn ne null) { - val pos = posIn.inUltimateSource + val pos = posIn.inUltimateSource(posIn.source.getOrElse(null)) val buf = new StringBuilder(msg) - buf.insert(0, " ") - buf.insert(0, pos.line.map(ln => ":" + pos.line.get + ":").get(":")) + if (!pos.source.isEmpty) { + buf.insert(0, " ") + buf.insert(0, pos.line.map(ln => ":" + pos.line.get + ":").get(":")) + } + //println(getSource.file) pos match { - case NoPosition => - case FakePos(msg) => - buf.insert(0, msg) - case _ if !pos.source.isEmpty => - val file = pos.source.get.file - buf.insert(0, if (shortname) file.name else file.path) + case FakePos(msg) => + buf.insert(0, msg) + case _ if !pos.source.isEmpty => + val file = pos.source.get.file + buf.insert(0, if (shortname) file.name else file.path) + case _ => } printMessage(buf.toString()) - printSourceLine(pos) + if (!pos.line.isEmpty) + printSourceLine(pos) } else printMessage(msg) diff --git a/src/compiler/scala/tools/nsc/reporters/Reporter.scala b/src/compiler/scala/tools/nsc/reporters/Reporter.scala index 5a65087a70..6eb4401c49 100644 --- a/src/compiler/scala/tools/nsc/reporters/Reporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/Reporter.scala @@ -6,7 +6,7 @@ package scala.tools.nsc.reporters -import scala.tools.nsc.util.Position +import scala.tools.nsc.util._ /** * This interface provides methods to issue information, warning and @@ -37,6 +37,10 @@ abstract class Reporter { protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit + private var source : SourceFile = _ + def setSource(source : SourceFile) : Unit = this.source = source + def getSource : SourceFile = source + def info(pos: Position, msg: String, force: Boolean): Unit = info0(pos, msg, INFO, force) def warning(pos: Position, msg: String ): Unit = info0(pos, msg, WARNING, false) def error(pos: Position, msg: String ): Unit = info0(pos, msg, ERROR, false) diff --git a/src/compiler/scala/tools/nsc/reporters/StoreReporter.scala b/src/compiler/scala/tools/nsc/reporters/StoreReporter.scala index 26453c7748..41f1bde6da 100644 --- a/src/compiler/scala/tools/nsc/reporters/StoreReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/StoreReporter.scala @@ -6,13 +6,13 @@ // $Id$ -package scala.tools.nsc.reporters; -import scala.collection.mutable.HashSet; -import scala.tools.nsc.util.Position -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.io.IOException; -import java.io.PrintWriter; +package scala.tools.nsc.reporters +import scala.collection.mutable.HashSet +import scala.tools.nsc.util.{Position,SourceFile} +import java.io.BufferedReader +import java.io.InputStreamReader +import java.io.IOException +import java.io.PrintWriter /** * This class implements a Reporter that displays messages on a text @@ -20,17 +20,15 @@ import java.io.PrintWriter; */ class StoreReporter extends Reporter { class Info(val pos: Position, val msg: String, val severity: Severity) { - override def toString() = "pos: " + pos + " " + msg + " " + severity; + override def toString() = "pos: " + pos + " " + msg + " " + severity } - val infos = new HashSet[Info]; - protected def info0(pos : Position, msg : String, severity : Severity, force : Boolean) : Unit = if (!force) { - infos += new Info(pos, msg, severity); + infos += new Info(pos, msg, severity) (severity).count = severity.count + 1 } override def reset = { - super.reset; - infos.clear; + super.reset + infos.clear } } diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index fc3572b8f1..13180aade2 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -356,7 +356,7 @@ trait Definitions { private def newClass(owner: Symbol, name: Name, parents: List[Type]): Symbol = { val clazz = owner.newClass(NoPosition, name.toTypeName) - clazz.setInfo(ClassInfoType(parents, newScope, clazz)) + clazz.setInfo(ClassInfoType(parents, newClassScope, clazz)) owner.info.decls.enter(clazz) clazz } @@ -367,7 +367,7 @@ trait Definitions { clazz.setInfo( PolyType( List(tparam), - ClassInfoType(List(parent(tparam)), newScope, clazz))) + ClassInfoType(List(parent(tparam)), newClassScope, clazz))) } private def newAlias(owner: Symbol, name: Name, alias: Type): Symbol = { @@ -442,7 +442,7 @@ trait Definitions { val module = ScalaPackageClass.newModule(NoPosition, name) ScalaPackageClass.info.decls.enter(module) val mclass = module.moduleClass - mclass.setInfo(ClassInfoType(List(), newScope, mclass)) + mclass.setInfo(ClassInfoType(List(), newClassScope, mclass)) module.setInfo(mclass.tpe) val box = newMethod(mclass, nme.box, List(clazz.typeConstructor), @@ -645,7 +645,7 @@ trait Definitions { if (isInitialized) return isInitialized = true - EmptyPackageClass.setInfo(ClassInfoType(List(), newScope, EmptyPackageClass)) + EmptyPackageClass.setInfo(ClassInfoType(List(), newClassScope, EmptyPackageClass)) EmptyPackage.setInfo(EmptyPackageClass.tpe) RootClass.info.decls.enter(EmptyPackage) RootClass.info.decls.enter(RootPackage) @@ -696,7 +696,7 @@ trait Definitions { EqualsPatternClass.setInfo( PolyType( List(tparam), - ClassInfoType(List(AnyClass.typeConstructor), newScope, EqualsPatternClass))) + ClassInfoType(List(AnyClass.typeConstructor), newClassScope, EqualsPatternClass))) } /* <unapply> */ diff --git a/src/compiler/scala/tools/nsc/symtab/GenerateIdeMaps.scala b/src/compiler/scala/tools/nsc/symtab/GenerateIdeMaps.scala new file mode 100644 index 0000000000..6f265a379f --- /dev/null +++ b/src/compiler/scala/tools/nsc/symtab/GenerateIdeMaps.scala @@ -0,0 +1,546 @@ +package scala.tools.nsc.symtab; +import scala.tools.nsc.io.{PlainFile,AbstractFile} +import scala.tools.nsc.util._ +import java.io._ +import java.util.zip._ +import scala.collection.jcl.{LinkedHashMap,LinkedHashSet} +import scala.tools.nsc.symtab.Flags._ + +abstract class GenerateIdeMaps extends SubComponent { + val phaseName = "gen-ide-map" + def newPhase(prev: Phase): StdPhase = new GenIdeMapPhase(prev) + import global._ + private def assert(b : Boolean) : Unit = { + if (!b) { + assert(true) + throw new AssertionError + } + } + + object sourceFiles extends LinkedHashMap[AbstractFile,AbstractFile] { + override def update(sourceFile : AbstractFile, classDir : AbstractFile) = { + ideMaps.get(sourceFile) match { + case Some(map) if map.isEmpty => ideMaps.removeKey(sourceFile) + case _ => + } + super.update(sourceFile, classDir) + } + } + object ideMaps extends LinkedHashMap[AbstractFile, LinkedHashMap[Int,IdeRef]] + def getIdeMap(sourceFile : SourceFile, pkg : => Option[String], defaultClassDir : => Option[AbstractFile]) = ideMaps.get(sourceFile.file) match { + case Some(map) if !map.isEmpty => map + case _ => + val ret0 = try { + readIdeMap(sourceFile, pkg, defaultClassDir) + } catch { + case _ => Nil + } + val ret = new LinkedHashMap[Int,IdeRef] + ret0.foreach{ + case (offset,ref) => ret(offset) = ref + } + //if (!ret.isEmpty) + ideMaps(sourceFile.file) = ret + ret + } + def symToPackage(sym : Symbol) : String = { + var pkg = sym.fullNameString + if (pkg.indexOf('$') != -1) pkg = pkg.substring(pkg.indexOf('$')) + if (pkg.indexOf('.') != -1) pkg = pkg.substring(pkg.lastIndexOf('.')) + pkg + } + + abstract class IdeRef + object NoRef extends IdeRef + case class Internal(offset : Int) extends IdeRef + case class External(sym : Symbol) extends IdeRef + class Definition(sym : Symbol) extends External(sym) { + override def toString = "Definition(" + sym + ")" + } + def readIdeMap(sourceFile : SourceFile, pkg : => Option[String], defaultClassDir : => Option[AbstractFile]) : List[(Int,IdeRef)] = { + // need to find the place where the class file was loaded.... + var name = sourceFile.file.name + assert(name.endsWith(".scala")) + name = name.substring(0, name.length - (".scala").length) + ".ide" + val classDir= sourceFiles.get(sourceFile.file) orElse ((defaultClassDir,pkg) match { + case (Some(root),Some(pkg)) => + var file = root + pkg.split('.').foreach{name => + if (file != null) file = file.lookupName(name, true) + } + if (file != null) Some(file) else None + case _ => None + }) + if (classDir.isEmpty) return Nil + val ideFile = classDir.get.lookupPath(name, false) + if (ideFile == null) return Nil + try { + val fis = new ByteArrayInputStream(ideFile.toByteArray) + val gis = new GZIPInputStream(fis) + val array = new Array[Byte](100) + val buf = new scala.collection.mutable.ArrayBuffer[Byte] + while ({ + val read = gis.read(array) + if (read == -1) false else { + buf ++= array.projection.take(read) + true + } + }) {} + val input = new ObjectInputStream(new ByteArrayInputStream(buf.toArray)) + def read : List[(Int,String)] = { + val array0 = input.readObject.asInstanceOf[Array[Int]] + val array1 = input.readObject.asInstanceOf[Array[String]] + assert(array0.length == array1.length) + val buf = new ListBuffer[(Int,String)] + val i = array0.elements + val j = array1.elements + while (i.hasNext) buf += (i.next,j.next) + buf.toList + } + val uses = read + val defs = read + val defs0 = new LinkedHashMap[Int,Symbol] + val ret = new scala.collection.jcl.LinkedHashMap[Int,IdeRef] + implicit val cache = new LinkedHashMap[String,Symbol] + defs.foreach{ + case (offset,url) => + val sym = url2sym(url) + //assert(sym != null) + if (sym != null) { + sym.setPos(new OffsetPosition(sourceFile, offset)) + ret += ((offset,new Definition(sym))) + defs0(offset) = sym + } else { + assert(true) + assert(true) + } + if (sym != null) { + } + } + uses.foreach{ + case (offset,url) => + if (url.startsWith(":")) { + val offset0 = Integer.parseInt(url.substring(1)) + ret(offset) = (defs0.get(offset0) match { + case Some(sym) => new Definition(sym) + case None => Internal(offset0) + }) + } else { + val sym = url2sym(url) + if (sym != null) { + ret(offset) = (External(sym)) + } else { + assert(true) + assert(true) + } + } + } + ret.toList + } catch { + case ex => + //ex.printStackTrace + Nil + } + } + + def decodeIdeName(string : String) : (Name,String) = { + val idx = string.indexOf('[') + if (idx != -1) { // a method + return (newTermName(string.substring(0, idx)), string.substring(idx)) + } else if (string.endsWith(";")) { + return (newTermName(string.substring(0, string.length - (";").length)), null) + } else return (newTypeName(string), null) + } + def lookupIdeName(owner : Symbol, scope : Scope, string : String) : Symbol = { + val (name,params) = decodeIdeName(string) + var e = scope.lookupEntry(name) + while ((e ne null) && params != null && methodSig(e.sym.info) != params) + e = scope.lookupNextEntry(e) + if (e != null) return (e.sym) + val isPC = owner.isPackageClass + if (isPC) { + assert(params == null) + assert(true) + val info = owner.info.asInstanceOf[PackageClassInfoType] + val loader = info.loader.asInstanceOf[global.loaders.PackageLoader] + if (loader ne null) loader.refresh + e = scope.lookupEntry(name) + if (e ne null) return (e.sym) + } + assert(true) // not found! + return null + } + def walk(sourceFile : SourceFile, tree: Tree, uses : scala.collection.mutable.Map[Position,Symbol], defs : LinkedHashMap[Symbol,Position]) : Unit = { + def f(t : Tree) : Unit = { + def fs(l : List[Tree]) : Unit = { + val i = l.elements + while (i.hasNext) f(i.next) + } + def fss(l : List[List[Tree]]) : Unit = { + val i = l.elements + while (i.hasNext) fs(i.next) + } + if (t.isInstanceOf[StubTree]) return + def asTypeRef = t.tpe.asInstanceOf[TypeRef] + val sym = (t,t.tpe) match { + case (Super(_,_),SuperType(_,supertp)) if supertp.typeSymbol != NoSymbol && supertp.typeSymbol != null => supertp.typeSymbol + case _ if t.symbol != NoSymbol && t.symbol != null => t.symbol + case (t : TypeTree, tp) if tp != null && tp.typeSymbol != null && tp.typeSymbol != NoSymbol => tp.typeSymbol + case (t : TypeTree, tp) if tp != null && tp.resultType != null && tp.resultType.typeSymbol != null => tp.resultType.typeSymbol + case (t, tpe : Type) if tpe != null && (t.symbol eq NoSymbol) && t.isTerm && tpe.termSymbol != null => + assert(true) + tpe.termSymbol + case (t, tpe : Type) if tpe != null && (t.symbol eq NoSymbol) && tpe.typeSymbol != null => + if (t.tpe.isInstanceOf[TypeRef]) asTypeRef.sym // XXX: looks like a bug + else tpe.typeSymbol + case _ => NoSymbol + } + if (sym != null && sym != NoSymbol /* && !sym.hasFlag(SYNTHETIC) */) { + var id = sourceFile.identifier(t.pos, global) + val doAdd = if (id.isDefined) { + if (id.get.charAt(0) == '`') id = Some(id.get.substring(1, id.get.length - 1)) + val name = sym.name.decode.trim + if (name == id.get) true + else if (name.endsWith("_=")) { + val name1 = name.substring(0, name.length - ("_=").length) + name1 == id.get + } else false + //if (sym.name.toString.contains(id.get)) true else false + } else false + if (doAdd) { + + if (!uses.contains(t.pos)) { + uses(t.pos) = sym + } else { + val existing = uses(t.pos) + if (sym.sourceFile != existing.sourceFile || sym.pos != existing.pos) { + (sym,existing) match { + case (sym,existing) if sym.pos == existing.pos => + case (sym : TypeSymbol ,_ : ClassSymbol) => uses(t.pos) = sym + case (_ : ClassSymbol,_ : TypeSymbol) => // nothing + case _ if sym.isModule && existing.isValue => // nothing + case _ if sym.isClass && existing.isMethod => // nothing + case _ => + assert(true) + } + } + }} + } + assert(true) + t match { + case t : DefTree if defs != null && t.symbol != NoSymbol => + if (t.pos != NoPosition) + defs.put(t.symbol, t.pos) + if (t.symbol.isClass) { + val factory = t.symbol.caseFactory + if (factory != NoSymbol) { + assert(true) + defs.put(factory, t.pos) + } + } + else { + assert(true) + assert(true) + } + case t : TypeBoundsTree => f(t.lo); f(t.hi) + case t : TypeTree if t.original != null => + def h(original : Tree, tpe : Type): Unit = try { + if (original.tpe == null) + original.tpe = tpe + (original) match { + case (AppliedTypeTree(_,trees)) if tpe.isInstanceOf[TypeRef] => + val types = tpe.asInstanceOf[TypeRef].args + trees.zip(types).foreach{ + case (tree,tpe) => assert(tree != null && tpe != null); h(tree, tpe) + case _ => + } + case _ => + } + } + if (t.original.tpe == null) { + val dup = t.original.duplicate + h(dup,t.tpe) + f(dup) + } else f(t.original) + () + case _ => + } + (t) match { + case (t : MemberDef) if t.symbol != null && t.symbol != NoSymbol => + val annotated = if (sym.isModule) sym.moduleClass else sym + val i = t.mods.annotations.elements + val j = annotated.attributes.elements + while (i.hasNext && j.hasNext) { + val tree = i.next.constr + val ainfo = j.next + val sym = ainfo.atp.typeSymbol + tree.setType(ainfo.atp) + tree.setSymbol(sym) + f(tree) + } + + case _ => + } + t match { + case tree: ImplDef => + fs(tree.impl.parents); f(tree.impl.self); fs(tree.impl.body) + tree match { + case tree : ClassDef => fs(tree.tparams) + case _ => + } + case tree: PackageDef => fs(tree.stats) + case tree: ValOrDefDef => + f(tree.rhs); + if (tree.tpt != null) { + assert(true) + f(tree.tpt) + } + tree match { + case tree : DefDef => fs(tree.tparams); fss(tree.vparamss) + case _ => + } + case tree: Function => fs(tree.vparams); f(tree.body) + case tree : Bind => f(tree.body) + case tree : Select => + val qualifier = if (tree.tpe != null && tree.qualifier.tpe == null) { + val pre = tree.tpe.prefix + val qualifier = tree.qualifier.duplicate + qualifier.tpe = pre + qualifier + } else tree.qualifier + + f(qualifier) + case tree : Annotation => f(tree.constr) + case tree : Annotated => f(tree.annot); f(tree.arg) + case tree : GenericApply => f(tree.fun); fs(tree.args) + case tree : UnApply => f(tree.fun); fs(tree.args) + case tree : AppliedTypeTree => + if (tree.tpe != null) { + val i = tree.tpe.typeArgs.elements + val j = tree.args.elements + while (i.hasNext && j.hasNext) { + val tpe = i.next + val arg = j.next + if (arg.tpe == null) { + arg.tpe = tpe + } + } + } + f(tree.tpt); fs(tree.args) + case tree : SingletonTypeTree => + if (tree.ref.tpe == null) { + val dup = tree.ref.duplicate + dup.tpe = tree.tpe + f(dup) + } else f(tree.ref) + case tree : SelectFromTypeTree => f(tree.qualifier) + case tree : Typed => f(tree.expr); f(tree.tpt) + case tree : Block => fs(tree.stats); f(tree.expr) + case tree: CaseDef => f(tree.pat);f(tree.guard);f(tree.body) + case tree : Sequence => fs(tree.trees); + case tree : Assign => f(tree.lhs); f(tree.rhs); + case tree : If => f(tree.cond); f(tree.thenp); f(tree.elsep); + case tree : New => f(tree.tpt); + case tree : Match => f(tree.selector); fs(tree.cases); + case tree : Return => f(tree.expr); + case tree : LabelDef => f(tree.rhs); + case tree : Throw => f(tree.expr); + case tree : Try => f(tree.block); fs(tree.catches); f(tree.finalizer); + case tree : Alternative => fs(tree.trees); + case tree : TypeDef => f(tree.rhs); fs(tree.tparams) + case tree : DocDef => f(tree.definition); + case tree: Import => f(tree.expr) + case _ => + } + } + f(tree) + } + def isRoot(sym : Symbol) = sym == definitions.RootPackage || sym == definitions.RootClass || sym == NoSymbol + private var depth = 0 + + def methodSig(info : Type) : String = info match { + case PolyType(_, result) => methodSig(result) + case info => + info.paramTypes.map{t => + if (depth >= 10) { + assert(true) + assert(true) + } + assert(!isRoot(t.typeSymbol)) + //assert(t.symbol != sym && t.symbol != sym.owner) + depth += 1 + val ret = sym2url(t.typeSymbol) + + (t match { + case TypeRef(_,_,tparams) if !tparams.isEmpty => + tparams.map{t => sym2url(t.typeSymbol)}.mkString("<",":",">") + case _ => "" + }) + depth -= 1 + ret + }.mkString("[",":","]") + (info.resultType match { + case MethodType(args,result) => "*" + case tpe => sym2url(tpe.typeSymbol) + }) + } + + def sym2url(sym : Symbol) : String = { + assert(!isRoot(sym)) + assert(sym != sym.owner) + if (sym.isModuleClass) { + if (sym.linkedModuleOfClass eq NoSymbol) { + if (isRoot(sym.owner)) { + return sym.name.toString + } + throw new Error(sym + " " + sym.moduleClass + " " + sym.isPackage + " " + sym.owner) + } + return sym2url(sym.linkedModuleOfClass) + } + (if (isRoot(sym.owner) || sym.owner.isTerm) "" + else sym2url(sym.owner) + ".") + sym.name.toString + { + //assert(!sym.owner.isTerm) + if (sym.isMethod) methodSig(sym.info) + else if (!sym.name.isTypeName) ";" else "" + } + } + def url2sym(paths : List[String], owner : Symbol) : Symbol = { + if (paths.isEmpty) owner + else { + // decode name + val owner0 = if (owner.isModule) { + assert(owner.moduleClass ne NoSymbol) + owner.moduleClass + } else owner + + val sym = lookupIdeName(owner0, owner0.info.decls, paths.head) + if (sym == null) { + assert(true) + return null + } + else url2sym(paths.tail, sym) + } + } + def url2sym(url : String)(implicit cache : LinkedHashMap[String,Symbol]) : Symbol = { + if (cache != null) cache.get(url) match { + case Some(sym) => return sym + case _ => + } + + + // decode the string. + var url0 = url + var idx = url.lastIndexOf('[') // could be method + val paths = new scala.collection.mutable.ListBuffer[String] + while (url0 ne null) { + val jdx = url0.indexOf('.') + if (jdx == -1 || (idx != -1 && jdx > idx)) { + paths append url0 + url0 = null + } else { + paths append url0.substring(0, jdx) + if (idx != -1) idx = idx - (jdx + 1) + url0 = url0.substring(jdx + 1) + } + } + if (definitions.RootClass eq null) new global.Run + val result = url2sym(paths.toList, definitions.RootClass) + if (result != null && cache != null) cache(url) = result + return result + } + class GenIdeMapPhase(prev: Phase) extends StdPhase(prev) { + def apply(unit: global.CompilationUnit): Unit = { + if (global.settings.noide.value) return + global.informProgress("gen-ide-map for " + unit) + val path = unit.source.file match { + case file : PlainFile => file.path + case _ => return // don't do anything. + } + assert(path.endsWith(".scala")) + + val sources = global.settings.sourcepath.value.split(File.pathSeparator) + val i = sources.elements + while (i.hasNext) { + val sourcePath = i.next + if (path.startsWith(sourcePath)) { + val usePath = path.substring(sourcePath.length, path.length - (".scala").length) + ".ide" + val uses = new LinkedHashMap[Position,Symbol] + val defs = new LinkedHashMap[Symbol,Position] + walk(unit.source, unit.body, uses, defs) + // all populated, now what? + // populate ownerTree + + val writeUses = uses.projection.filter(_._1 != NoPosition).map{ + case (p : OffsetPosition, sym) => + (p.offset0, if (sym.sourceFile == unit.source.file) { + // internal reference + if (!sym.pos.offset.isDefined) Console.println("ERROR: " + sym + " in " + sym.sourceFile) + ":" + sym.pos.offset.getOrElse(0) + } else { + val url = sym2url(sym) + url + }) + }.toList + object okDefs extends LinkedHashMap[Symbol,Boolean] { + def has(sym : Symbol) : Boolean = get(sym) match { + case Some(value) => value + case _ => + if (sym eq definitions.RootClass) return true + if (sym.isModuleClass) { + if (sym.linkedModuleOfClass ne NoSymbol) + return has(sym.linkedModuleOfClass) + //System.err.println(sym + " is module class") + return false + } + val owner = sym.owner + if (owner eq NoSymbol) return false + if (!owner.isClass && !owner.isStable) return false + def fail = { + put(sym, false) + false + } + if (!has(owner)) return fail + var e = owner.info.decls.lookupEntry(sym.name) + while (e != null&&e.sym != sym) e = owner.info.decls.lookupNextEntry(e) + if (e == null) return fail + put(sym, true) + return true + } + } + + val writeDefs = defs.projection.filter{ + case (sym,OffsetPosition(_,_)) if okDefs.has(sym) => true + case _ => false + }.map{ + case (sym,OffsetPosition(source,offset)) if unit.source == source => (offset,sym2url(sym)) + }.toList + + val file = new File(global.settings.outdir.value, usePath) + file.mkdirs + if (file.exists) file.delete + + val out = new ObjectOutputStream(new GZIPOutputStream(new FileOutputStream(file))) + //Console.println("GZIP: " + out) + def write(list : List[(Int,String)]) = { + val array0 = list.projection.map(_._1).toArray + val array1 = list.projection.map(_._2).toArray + out.writeObject(array0) + out.writeObject(array1) + } + write(writeUses) + write(writeDefs) + out.close + ideMaps.removeKey(unit.source.file) + return + } + } + //Console.println("Cannot find root source of " + path + " so cannot generate map file") + } + } + case class ProjectAdapter(other : Global) { + def translate(sym : global.Symbol) : other.Symbol = { + assert(sym != NoSymbol) + val from = sym2url(sym) + // ya, its this easy! + return other.generateIdeMaps.url2sym(from)(null) + } + } +} diff --git a/src/compiler/scala/tools/nsc/symtab/Scopes.scala b/src/compiler/scala/tools/nsc/symtab/Scopes.scala index c0817a65e8..afdd284629 100644 --- a/src/compiler/scala/tools/nsc/symtab/Scopes.scala +++ b/src/compiler/scala/tools/nsc/symtab/Scopes.scala @@ -10,10 +10,6 @@ trait Scopes { self: SymbolTable => class ScopeEntry(val sym: Symbol, val owner: Scope) { - /** hook to notify IDE that new symbol has been added to this scope */ - owner.enter00(sym); - - /** the next entry in the hash bucket */ var tail: ScopeEntry = _ @@ -46,13 +42,16 @@ trait Scopes { */ def newScope(initElems: ScopeEntry): Scope = new NormalScope(initElems) final def newScope: Scope = newScope(null: ScopeEntry) - //final def newScope(base: Scope) : Scope = newScope(base.elems) - final def newScope(base: Scope) : Scope = if(base eq null) newScope else newScope(base.elems) + def newClassScope = newScope // for use in ClassInfoType creation + def newTempScope = newScope(null : ScopeEntry) + + final def newScope(base: Scope) : Scope = newScope(base.elems) final def newScope(decls: List[Symbol]) : Scope = { val ret = newScope decls.foreach(d => ret.enter(d)) ret } + def newThrowAwayScope(decls : List[Symbol]) : Scope = newScope(decls) private class NormalScope(initElems: ScopeEntry) extends Scope(initElems) @@ -60,11 +59,6 @@ trait Scopes { var elems: ScopeEntry = initElems - /** hook for IDE - */ - protected def enter0(sym: Symbol) {} - private[Scopes] def enter00(sym: Symbol) = enter0(sym) - /** The number of times this scope is neted in another */ private var nestinglevel = 0 @@ -104,13 +98,13 @@ trait Scopes { def this(decls: List[Symbol]) = { this() - decls foreach enter + decls.foreach(sym => enter(sym)) } /** Returns a new scope with the same content as this one. */ def cloneScope: Scope = { val clone = newScope - this.toList foreach clone.enter + this.toList.foreach(sym => clone.enter(sym)) clone } @@ -147,7 +141,7 @@ trait Scopes { * * @param sym ... */ - def enter(sym: Symbol) { enter(newScopeEntry(sym, this)) } + def enter(sym: Symbol) : Symbol = { enter(newScopeEntry(sym, this)); sym } /** enter a symbol, asserting that no symbol with same name exists in scope * diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 450695b80e..3f251d477a 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -99,6 +99,9 @@ abstract class SymbolLoaders { protected var root: Symbol = _ def enterPackage(name: String, completer: SymbolLoader) { + if (inIDE && root.info.decls.lookup(newTermName(name)) != NoSymbol) { + return // refresh + } val pkg = root.newPackage(NoPosition, newTermName(name)) pkg.moduleClass.setInfo(completer) pkg.setInfo(pkg.moduleClass.tpe) @@ -109,6 +112,10 @@ abstract class SymbolLoaders { def enterClassAndModule(name: String, completer: SymbolLoader): Symbol = { val owner = if (root.isRoot) definitions.EmptyPackageClass else root val className = newTermName(name) + if (inIDE && owner.info.decls.lookup(name) != NoSymbol) { + // refresh + return owner.info.decls.lookup(name) + } assert(owner.info.decls.lookup(name) == NoSymbol, owner.fullNameString + "." + name) val clazz = owner.newClass(NoPosition, name.toTypeName) val module = owner.newModule(NoPosition, name) @@ -126,13 +133,20 @@ abstract class SymbolLoaders { //System.out.println("Added class " + clazz.fullNameString); clazz } - + def checkAdd(name0 : String) = { + var name = name0 + while (name.indexOf('$') != -1) { + name = name.substring(0, name.indexOf('$')) + } + } protected def doComplete(root: Symbol) { assert(root.isPackageClass, root) this.root = root val scope = newScope - root.setInfo(new PackageClassInfoType(scope, root)) - + root.setInfo(new PackageClassInfoType(scope, root, this)) + refresh + } + def refresh = { /** Is the given name a valid input file base name? */ def isValid(name: String): Boolean = name.length() > 0 && !name.endsWith("$class") && (settings.XbytecodeRead.value || @@ -246,23 +260,31 @@ abstract class SymbolLoaders { val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global } protected def doComplete(root: Symbol) { - typeParser.parse(typ, root) + typeParser.parse(typ, root.asInstanceOf) } protected def kindString: String = typ.FullName protected def sourceString = typ.Assembly.FullName } + // IDE hook. + protected def completeClassfile(root : Symbol, loader : ClassfileLoader)(f : => Unit) : Unit = f + protected def completeSourcefile(root : Symbol, loader : SourcefileLoader)(f : => Unit) : Unit = f - class ClassfileLoader(classFile: AbstractFile, override val sourceFile: AbstractFile, sourcePath0: AbstractFile) extends SymbolLoader { - //throw new Error("classfile = " + classFile + "; sourcefile = " + sourceFile + "; sourcepath = " + sourcePath0) + class ClassfileLoader(val classFile: AbstractFile, override val sourceFile: AbstractFile, sourcePath0: AbstractFile) extends SymbolLoader { private object classfileParser extends ClassfileParser { val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global override def sourcePath = sourcePath0 /* could be null */ } protected def doComplete(root: Symbol) { - classfileParser.parse(classFile, root) - if (sourceFile ne null) root match { - case clazz : ClassSymbol => clazz.sourceFile = sourceFile - case _ => + completeClassfile(root, this) { + classfileParser.parse(classFile, root) + } + root match { + case clazz : ClassSymbol => + global.attachSourceToClass(clazz, this, if (sourceFile ne null) sourceFile else clazz.sourceFile) + case _ => + } + if (root.sourceFile ne null) { + global.generateIdeMaps.sourceFiles(root.sourceFile) = classFile.container } } protected def kindString: String = "class file" @@ -275,8 +297,9 @@ abstract class SymbolLoaders { } */ class SourcefileLoader(override val sourceFile: AbstractFile) extends SymbolLoader { - protected def doComplete(root: Symbol): Unit = + protected def doComplete(root: Symbol): Unit = completeSourcefile(root, this){ global.currentRun.compileLate(sourceFile) + } protected def kindString: String = "source file" protected def sourceString = sourceFile.toString() } diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala index 87808a45fb..d324bf6312 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala @@ -28,8 +28,10 @@ abstract class SymbolTable extends Names /** Are we compiling for .NET*/ def forMSIL: Boolean - /** are we in a lampion presentation compiler? then disable caching. */ + /** are we in a lampion presentation compiler? cannot get inIDE flag from global */ def inIDE : Boolean + protected def trackTypeIDE(sym : Symbol) : Boolean = true + protected def recycle(sym : Symbol) : Symbol = sym /** A period is an ordinal number for a phase in a run. * Phases in later runs have higher periods than phases in earlier runs. diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 5cba998f38..cb990a0d27 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -7,7 +7,7 @@ package scala.tools.nsc.symtab import scala.tools.nsc.io.AbstractFile -import scala.tools.nsc.util.{Position, NoPosition, SourceFile} +import scala.tools.nsc.util.{Position, NoPosition, SourceFile, BatchSourceFile} import Flags._ trait Symbols { @@ -50,7 +50,7 @@ trait Symbols { def pos = rawpos def setPos(pos: Position): this.type = { this.rawpos = pos; this } - def namePos(source: SourceFile) = { + def namePos(source: BatchSourceFile) = { val pos: Int = this.pos.offset.get(-1) val buf = source.content if (pos == -1) -1 @@ -496,6 +496,9 @@ trait Symbols { this } + /** check if info has been set before, used in the IDE */ + def rawInfoSafe : Option[Type] = if (infos == null) None else Some(rawInfo) + /** Return info without checking for initialization or completing */ def rawInfo: Type = { var infos = this.infos @@ -503,7 +506,7 @@ trait Symbols { val curPeriod = currentPeriod val curPid = phaseId(curPeriod) - if (validTo != NoPeriod) { + if (!inIDE && validTo != NoPeriod) { // skip any infos that concern later phases while (curPid < phaseId(infos.validFrom) && infos.prev != null) @@ -670,6 +673,10 @@ trait Symbols { def suchThat(cond: Symbol => Boolean): Symbol = { val result = filter(cond) + // @S: seems like NoSymbol has the overloaded flag???? + if (inIDE && (this eq result) && result != NoSymbol && (result hasFlag OVERLOADED)) { + return result + } assert(!(result hasFlag OVERLOADED), result.alternatives) result } @@ -698,10 +705,12 @@ trait Symbols { /** The primary constructor of a class */ def primaryConstructor: Symbol = { - val c = info.decl( + var c = info.decl( if (isTrait || isImplClass) nme.MIXIN_CONSTRUCTOR else nme.CONSTRUCTOR) - if (c hasFlag OVERLOADED) c.alternatives.head else c + c = if (c hasFlag OVERLOADED) c.alternatives.head else c + //assert(c != NoSymbol) + c } /** The self symbol of a class with explicit self type, or else the @@ -953,8 +962,15 @@ trait Symbols { newTermName(fullNameString('$') + nme.EXPAND_SEPARATOR_STRING + name) } - def sourceFile: AbstractFile = - (if (isModule) moduleClass else toplevelClass).sourceFile + def sourceFile: AbstractFile = { + var ret = (if (isModule) moduleClass else toplevelClass).sourceFile + if (ret == null && inIDE && !isModule) this match { + case sym : ModuleSymbol if sym.referenced != null => + ret = sym.referenced.sourceFile + case _ => + } + ret + } def sourceFile_=(f: AbstractFile): Unit = throw new Error("sourceFile_= inapplicable for " + this) @@ -1164,7 +1180,8 @@ trait Symbols { } def setLazyAccessor(sym: Symbol): TermSymbol = { - assert(hasFlag(LAZY) && referenced == NoSymbol, this) + // @S: in IDE setLazyAccessor can be called multiple times on same sym + assert(hasFlag(LAZY) && (referenced == NoSymbol || referenced == sym), this) referenced = sym this } diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 3cdcc226e8..af9d7550ad 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -125,8 +125,12 @@ trait Types { override def isError = underlying.isError override def isErroneous = underlying.isErroneous override def isStable: Boolean = underlying.isStable + override def finalResultType = underlying.finalResultType + override def paramSectionCount = underlying.paramSectionCount + override def paramTypes = underlying.paramTypes override def termSymbol = underlying.termSymbol override def termSymbolDirect = underlying.termSymbolDirect + override def typeParams = underlying.typeParams override def typeSymbol = underlying.typeSymbol override def typeSymbolDirect = underlying.typeSymbolDirect @deprecated override def symbol = underlying.symbol @@ -389,6 +393,7 @@ trait Types { /** The type of `sym', seen as a member of this type. */ def memberType(sym: Symbol): Type = { + trackTypeIDE(sym) //@M don't prematurely instantiate higher-kinded types, they will be instantiated by transform, typedTypeApply, etc. when really necessary sym.tpeHK match { case ov @ OverloadedType(pre, alts) => @@ -596,7 +601,7 @@ trait Types { e = decls.lookupNextEntry(e) } if (alts.isEmpty) sym - else baseClasses.head.newOverloaded(this, alts) + else (baseClasses.head.newOverloaded(this, alts)) } /** @@ -648,7 +653,7 @@ trait Types { if (self eq null) self = this.narrow; (self.memberType(member) matches self.memberType(sym)) })) { - members = newScope(List(member, sym)) + members = newThrowAwayScope(List(member, sym)) } } else { var prevEntry = members lookupEntry sym.name @@ -684,7 +689,7 @@ trait Types { } else { if (util.Statistics.enabled) multMemberCount = multMemberCount + 1; //val pre = if (this.typeSymbol.isClass) this.typeSymbol.thisType else this; - baseClasses.head.newOverloaded(this, members.toList) + (baseClasses.head.newOverloaded(this, members.toList)) } } @@ -724,7 +729,11 @@ trait Types { override def baseType(clazz: Symbol): Type = supertype.baseType(clazz) override def closure: Array[Type] = supertype.closure override def closureDepth: Int = supertype.closureDepth - override def baseClasses: List[Symbol] = supertype.baseClasses + override def baseClasses: List[Symbol] = { + val supertype = this.supertype + if (inIDE && supertype == null) Nil + else supertype.baseClasses + } override def isNotNull = supertype.isNotNull } @@ -852,6 +861,7 @@ trait Types { private var underlyingCache: Type = _ private var underlyingPeriod = NoPeriod override def underlying: Type = { + // this kind of caching here won't work in the IDE if (inIDE) return pre.memberType(sym).resultType val period = underlyingPeriod if (period != currentPeriod) { @@ -998,7 +1008,7 @@ trait Types { "\n --- because ---\n" + ex.getMessage()) } val period = closurePeriod; - if (period != currentPeriod) { + if (period != currentPeriod) { // no caching in IDE closurePeriod = currentPeriod if (!isValidForBaseClasses(period)) { closureCache = null @@ -1234,7 +1244,7 @@ trait Types { override def kind = "ClassInfoType" } - class PackageClassInfoType(decls: Scope, clazz: Symbol) + class PackageClassInfoType(decls: Scope, clazz: Symbol, val loader : LazyType) extends ClassInfoType(List(), decls, clazz) /** A class representing a constant type. @@ -1562,6 +1572,10 @@ A type's typeSymbol should never be inspected directly. override def baseType(clazz: Symbol): Type = resultType.baseType(clazz) override def narrow: Type = resultType.narrow + override def deconst = + if (inIDE) PolyType(typeParams, resultType.deconst) + else super.deconst + override def finalResultType: Type = resultType.finalResultType /** @M: abstractTypeSig now wraps a TypeBounds in a PolyType @@ -1780,8 +1794,10 @@ A type's typeSymbol should never be inspected directly. } /** The canonical creator for this-types */ - def mkThisType(sym: Symbol): Type = - if (phase.erasedTypes) sym.tpe else unique(new ThisType(sym) with UniqueType) + def mkThisType(sym: Symbol): Type = { + class UniqueThisType extends ThisType(sym) with UniqueType + if (phase.erasedTypes) sym.tpe else unique(new UniqueThisType) + } /** The canonical creator for single-types */ def singleType(pre: Type, sym: Symbol): Type = { @@ -1795,32 +1811,41 @@ A type's typeSymbol should never be inspected directly. if (pre1 ne pre) sym1 = rebind(pre1, sym1) if (checkMalformedSwitch && !pre1.isStable && !pre1.isError) throw new MalformedType(pre, sym.nameString) - else - unique(new SingleType(pre1, sym1) with UniqueType) + else { + class UniqueSingleType extends SingleType(pre1, sym1) with UniqueType + unique(new UniqueSingleType) + } } } /** The canonical creator for super-types */ def mkSuperType(thistp: Type, supertp: Type): Type = if (phase.erasedTypes) supertp - else unique(new SuperType(thistp, supertp) with UniqueType) + else { + class UniqueSuperType extends SuperType(thistp, supertp) with UniqueType + unique(new UniqueSuperType) + } /** The canonical creator for type bounds */ - def mkTypeBounds(lo: Type, hi: Type): TypeBounds = - unique(new TypeBounds(lo, hi) with UniqueType) + def mkTypeBounds(lo: Type, hi: Type): TypeBounds = { + class UniqueTypeBounds extends TypeBounds(lo, hi) with UniqueType + unique(new UniqueTypeBounds) + } - def refinementOfClass(clazz: Symbol, parents: List[Type], decls: Scope) = - new RefinedType(parents, decls) { + def refinementOfClass(clazz: Symbol, parents: List[Type], decls: Scope) = { + class RefinementOfClass extends RefinedType(parents, decls) { override def typeSymbol: Symbol = clazz @deprecated override def symbol: Symbol = clazz } + new RefinementOfClass + } /** the canonical creator for a refined type with a given scope */ def refinedType(parents: List[Type], owner: Symbol, decls: Scope): Type = { if (phase.erasedTypes) if (parents.isEmpty) ObjectClass.tpe else parents.head else { - val clazz = owner.newRefinementClass(NoPosition) + val clazz = recycle(owner.newRefinementClass(if (inIDE) owner.pos else NoPosition)) val result = refinementOfClass(clazz, parents, decls) clazz.setInfo(result) result @@ -1834,7 +1859,7 @@ A type's typeSymbol should never be inspected directly. * @return ... */ def refinedType(parents: List[Type], owner: Symbol): Type = - refinedType(parents, owner, newScope) + refinedType(parents, owner, newTempScope) def copyRefinedType(original: RefinedType, parents: List[Type], decls: Scope) = if ((parents eq original.parents) && (decls eq original.decls)) original @@ -1851,8 +1876,10 @@ A type's typeSymbol should never be inspected directly. } /** the canonical creator for a constant type */ - def mkConstantType(value: Constant): ConstantType = - unique(new ConstantType(value) with UniqueType) + def mkConstantType(value: Constant): ConstantType = { + class UniqueConstantType extends ConstantType(value) with UniqueType + unique(new UniqueConstantType) + } /** The canonical creator for typerefs * todo: see how we can clean this up a bit @@ -1892,8 +1919,10 @@ A type's typeSymbol should never be inspected directly. } /** create a type-ref as found, without checks or rebinds */ - def rawTypeRef(pre: Type, sym: Symbol, args: List[Type]): Type = - unique(new TypeRef(pre, sym, args) with UniqueType) + def rawTypeRef(pre: Type, sym: Symbol, args: List[Type]): Type = { + class rawTypeRef extends TypeRef(pre, sym, args) with UniqueType + unique(new rawTypeRef) + } /** The canonical creator for implicit method types */ def ImplicitMethodType(paramTypes: List[Type], resultType: Type): ImplicitMethodType = @@ -2279,9 +2308,14 @@ A type's typeSymbol should never be inspected directly. if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) mapOver(tp) //@M! see test pos/tcpoly_return_overriding.scala why mapOver is necessary else { - def throwError = - throw new Error("" + tp + sym.locationString + - " cannot be instantiated from " + pre.widen); + def throwError : Nothing = + // IDE: in the IDE, this will occur because we complete everything + // too eagerly. It doesn't matter, the error will be fixed when + // the node is re-typed. + if (inIDE) throw new TypeError("internal error: " + tp + " in " + sym.owner + + " cannot be instantiated from " + pre.widen) + else throw new Error("" + tp + sym.locationString + + " cannot be instantiated from " + pre.widen) def instParam(ps: List[Symbol], as: List[Type]): Type = if (ps.isEmpty) throwError else if (sym eq ps.head) @@ -2564,7 +2598,8 @@ A type's typeSymbol should never be inspected directly. object adaptToNewRunMap extends TypeMap { private def adaptToNewRun(pre: Type, sym: Symbol): Symbol = { - if (sym.isModuleClass && !phase.flatClasses) { + if (inIDE) sym // dependecies adapted at a finer granularity in IDE + else if (sym.isModuleClass && !phase.flatClasses) { adaptToNewRun(pre, sym.sourceModule).moduleClass } else if ((pre eq NoPrefix) || (pre eq NoType) || sym.owner.isPackageClass) { sym @@ -2972,8 +3007,6 @@ A type's typeSymbol should never be inspected directly. if (subsametypeRecursions == 0) undoLog = List() } - /** hook for IDE */ - protected def trackTypeIDE(sym : Symbol) : Boolean = true; /** Does this type have a prefix that begins with a type variable */ def beginsWithTypeVar(tp: Type): Boolean = tp match { @@ -3473,7 +3506,7 @@ A type's typeSymbol should never be inspected directly. else { def lubBounds(bnds: List[TypeBounds]): TypeBounds = mkTypeBounds(glb(bnds map (_.lo), depth-1), lub(bnds map (_.hi), depth-1)) - proto.owner.newAbstractType(proto.pos, proto.name) + recycle(proto.owner.newAbstractType(proto.pos, proto.name)) .setInfo(lubBounds(symtypes map (_.bounds))) } } @@ -3656,10 +3689,11 @@ A type's typeSymbol should never be inspected directly. val g = glb(as, depth-1) if (l <:< g) l else { + val owner = commonOwner(as) val qvar = - commonOwner(as).newAbstractType(NoPosition, freshTypeName()) + recycle(owner.newAbstractType(if (inIDE) owner.pos else NoPosition, freshTypeName()).setFlag(EXISTENTIAL)) .setInfo(TypeBounds(g, l)) - .setFlag(EXISTENTIAL) + capturedParams += qvar qvar.tpe } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index bf3118b07f..ec00809529 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -49,7 +49,7 @@ abstract class ClassfileParser { protected var hasMeta: Boolean = _ // does class file contain jaco meta attribute?s protected var busy: Boolean = false // lock to detect recursive reads protected var classTParams = Map[Name,Symbol]() - protected val fresh = new FreshNameCreator + protected val fresh = new FreshNameCreator.Default private object metaParser extends MetaParser { val global: ClassfileParser.this.global.type = ClassfileParser.this.global @@ -59,7 +59,7 @@ abstract class ClassfileParser { val global: ClassfileParser.this.global.type = ClassfileParser.this.global } - def parse(file: AbstractFile, root: Symbol) { + def parse(file: AbstractFile, root: Symbol) = try { def handleError(e: Exception) = { if (settings.debug.value) e.printStackTrace() //debug throw new IOException("class file '" + in.file + "' is broken\n(" + { @@ -96,6 +96,7 @@ abstract class ClassfileParser { case e: FatalError => handleError(e) case e: RuntimeException => handleError(e) } + } finally { busy = false } @@ -345,8 +346,8 @@ abstract class ClassfileParser { if (isAnnotation) ifaces = definitions.ClassfileAnnotationClass.tpe :: ifaces val parents = superType :: ifaces - instanceDefs = newScope - staticDefs = newScope + instanceDefs = newClassScope + staticDefs = newClassScope val classInfo = ClassInfoType(parents, instanceDefs, clazz) val staticInfo = ClassInfoType(List(), staticDefs, statics) @@ -632,7 +633,8 @@ abstract class ClassfileParser { if ((sourceFile0 ne null) && (clazz.sourceFile eq null)) { clazz.sourceFile = sourceFile0 } - staticModule.moduleClass.sourceFile = clazz.sourceFile + if (!inIDE || staticModule.moduleClass != NoSymbol) + staticModule.moduleClass.sourceFile = clazz.sourceFile } case nme.AnnotationDefaultATTR => sym.attributes = diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index 84f7d37f83..a60333f005 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -47,6 +47,14 @@ abstract class Pickler extends SubComponent { add(sym, pickle) add(sym.linkedSym, pickle) pickle.finish + val doPickleHash = global.doPickleHash + if (doPickleHash) { + var i = 0 + while (i < pickle.writeIndex) { + unit.pickleHash += pickle.bytes(i).toLong // toLong needed to work around bug + i = i + 1 + } + } case _ => } } @@ -56,10 +64,10 @@ abstract class Pickler extends SubComponent { private class Pickle(rootName: Name, rootOwner: Symbol) extends PickleBuffer(new Array[Byte](4096), -1, 0) { - import scala.collection.mutable.HashMap + import scala.collection.jcl.LinkedHashMap private var entries = new Array[AnyRef](256) private var ep = 0 - private val index = new HashMap[AnyRef, int] + private val index = new LinkedHashMap[AnyRef, int] /** Is root in symbol.owner*? * @@ -326,10 +334,6 @@ abstract class Pickler extends SubComponent { */ private def writeSymInfo(sym: Symbol): Int = { var posOffset = 0 - if (sym.pos != NoPosition && sym.owner.isClass && !sym.pos.offset.isEmpty) { - writeNat(sym.pos.offset.get) - posOffset = PosOffset - } writeRef(sym.name) writeRef(sym.owner) writeNat((sym.flags & PickledFlags).asInstanceOf[int]) diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala index b140da032c..c8fbe40009 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala @@ -66,8 +66,8 @@ abstract class UnPickler { } /** The scope associated with given symbol */ - private def symScope(sym: Symbol) = symScopes.get(sym) match { - case None => val s = newScope; symScopes(sym) = s; s + private def symScope(sym: Symbol)(f : => Scope) = symScopes.get(sym) match { + case None => val s = f; symScopes(sym) = s; s case Some(s) => s } @@ -164,7 +164,6 @@ abstract class UnPickler { if (tag > PosOffset) readNat else -1 } - val pos: Position = NoPosition val name = readNameRef() val owner = readSymbolRef() val flags = readNat() @@ -176,17 +175,17 @@ abstract class UnPickler { } (tag % PosOffset) match { case TYPEsym => - sym = owner.newAbstractType(pos, name) + sym = owner.newAbstractType(NoPosition, name) case ALIASsym => - sym = owner.newAliasType(pos, name) + sym = owner.newAliasType(NoPosition, name) case CLASSsym => sym = if (name == classRoot.name && owner == classRoot.owner) (if ((flags & MODULE) != 0) moduleRoot.moduleClass - else classRoot).setPos(pos) + else classRoot) else - if ((flags & MODULE) != 0) owner.newModuleClass(pos, name) - else owner.newClass(pos, name) + if ((flags & MODULE) != 0) owner.newModuleClass(NoPosition, name) + else owner.newClass(NoPosition, name) if (readIndex != end) sym.typeOfThis = new LazyTypeRef(readNat()) case MODULEsym => val clazz = at(inforef, readType).typeSymbol @@ -195,13 +194,13 @@ abstract class UnPickler { else { assert(clazz.isInstanceOf[ModuleClassSymbol], clazz) val mclazz = clazz.asInstanceOf[ModuleClassSymbol] - val m = owner.newModule(pos, name, mclazz) + val m = owner.newModule(NoPosition, name, mclazz) mclazz.setSourceModule(m) m } case VALsym => sym = if (name == moduleRoot.name && owner == moduleRoot.owner) moduleRoot.resetFlag(MODULE) - else owner.newValue(pos, name) + else owner.newValue(NoPosition, name) case _ => errorBadSignature("bad symbol tag: " + tag) } @@ -214,7 +213,7 @@ abstract class UnPickler { else new LazyTypeRef(inforef)) if (sym.owner.isClass && sym != classRoot && sym != moduleRoot && !sym.isModuleClass && !sym.isRefinementClass && !sym.isTypeParameter) - symScope(sym.owner) enter sym + symScope(sym.owner)(newScope) enter sym } sym } @@ -245,13 +244,13 @@ abstract class UnPickler { val dcls = symScope(clazz) new RefinedType(ps, dcls) { override def symbol = clazz } */ - new RefinedType(until(end, readTypeRef), symScope(clazz)) { - @deprecated override def symbol = clazz - override def typeSymbol = clazz + new RefinedType(until(end, readTypeRef), symScope(clazz)(newTempScope)) { + @deprecated override def symbol = clazz + override def typeSymbol = clazz } case CLASSINFOtpe => val clazz = readSymbolRef() - ClassInfoType(until(end, readTypeRef), symScope(clazz), clazz) + ClassInfoType(until(end, readTypeRef), symScope(clazz)(newClassScope), clazz) case METHODtpe => val restpe = readTypeRef() MethodType(until(end, readTypeRef), restpe) @@ -556,14 +555,17 @@ abstract class UnPickler { at(readNat(), readTreeAttrib) private def errorBadSignature(msg: String) = - throw new RuntimeException("malformed Scala signature of " + classRoot.name + " at " + readIndex + "; " + msg) + if (inIDE) throw new TypeError(msg) + else throw new RuntimeException("malformed Scala signature of " + classRoot.name + " at " + readIndex + "; " + msg) private class LazyTypeRef(i: Int) extends LazyType { private val definedAtRunId = currentRunId + // In IDE, captures class files dependencies so they can be reloaded when their dependencies change. + private val ideHook = unpickleIDEHook override def complete(sym: Symbol) { - val tp = at(i, readType) + val tp = ideHook(at(i, readType)) sym setInfo tp - if (currentRunId != definedAtRunId) sym.setInfo(adaptToNewRunMap(tp)) + if (!inIDE && currentRunId != definedAtRunId) sym.setInfo(adaptToNewRunMap(tp)) } override def load(sym: Symbol) { complete(sym) } } diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala index 784a89658a..26747e58dc 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala @@ -20,9 +20,8 @@ import classfile.UnPickler abstract class TypeParser { val global: Global - - import global._ - import loaders.clrTypes + import global.loaders.clrTypes + import clrTypes.global._ //########################################################################## @@ -75,7 +74,7 @@ abstract class TypeParser { val a = attrs(0).asInstanceOf[MSILAttribute]; assert (a.getConstructor() == clrTypes.SYMTAB_CONSTR); val symtab = a.getConstructorArguments()(0).asInstanceOf[Array[Byte]] - unpickler.unpickle(symtab, 0, clazz, staticModule, typ.FullName); + unpickler.unpickle(symtab, 0, clazz.asInstanceOf, staticModule.asInstanceOf, typ.FullName); val mClass = clrTypes.getType(typ.FullName + "$"); if (mClass != null) { clrTypes.types(statics) = mClass; @@ -91,8 +90,8 @@ abstract class TypeParser { else if (typ.IsInterface()) definitions.ObjectClass.tpe else definitions.AnyClass.tpe; // this is System.Object val parents = superType :: ifaces.map(getCLRType).toList - instanceDefs = newScope - staticDefs = newScope + instanceDefs = newClassScope + staticDefs = newClassScope val classInfo = ClassInfoType(parents, instanceDefs, clazz) val staticInfo = ClassInfoType(List(), staticDefs, statics) @@ -110,7 +109,7 @@ abstract class TypeParser { || ntype.IsNestedFamANDAssem) || ntype.IsInterface) { - val loader = new loaders.MSILTypeLoader(ntype) + val loader = new global.loaders.MSILTypeLoader(ntype) val nclazz = statics.newClass(NoPosition, ntype.Name.toTypeName) val nmodule = statics.newModule(NoPosition, ntype.Name) nclazz.setInfo(loader) diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 5efd37cf68..2bff857011 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -14,7 +14,10 @@ import Flags._ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { import global._ // the global environment import definitions._ // standard classes and methods - import typer.{typed} // methods to type trees + // @S: XXX: why is this here? earsure is a typer, if you comment this + // out erasure still works, uses its own typed methods. + lazy val typerXXX = this.typer + import typerXXX.{typed} // methods to type trees import posAssigner.atPos // for filling in tree positions val phaseName: String = "erasure" @@ -501,6 +504,11 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { //if (settings.debug.value) Console.println("exception when typing " + tree); throw ex + case er: TypeError => + Console.println("exception when typing " + tree) + Console.println(er.msg + " in file " + context.owner.sourceFile) + er.printStackTrace + throw new Error } def adaptCase(cdef: CaseDef): CaseDef = { val body1 = adaptToType(cdef.body, tree1.tpe) @@ -560,16 +568,16 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { val tpe2 = atPhase(currentRun.refchecksPhase.next)(root.thisType.memberType(sym2)) if (!tpe1.isErroneous && !tpe2.isErroneous) unit.error( - if (sym1.owner == root) sym1.pos else root.pos, - (if (sym1.owner == sym2.owner) "double definition:\n" - else if (sym1.owner == root) "name clash between defined and inherited member:\n" - else "name clash between inherited members:\n") + - sym1 + ":" + tpe1 + - (if (sym1.owner == root) "" else sym1.locationString) + " and\n" + - sym2 + ":" + tpe2 + - (if (sym2.owner == root) " at line " + (sym2.pos).line.get else sym2.locationString) + - "\nhave same type" + - (if (tpe1 =:= tpe2) "" else " after erasure: " + atPhase(phase.next)(sym1.tpe))) + if (sym1.owner == root) sym1.pos else root.pos, + (if (sym1.owner == sym2.owner) "double definition:\n" + else if (sym1.owner == root) "name clash between defined and inherited member:\n" + else "name clash between inherited members:\n") + + sym1 + ":" + tpe1 + + (if (sym1.owner == root) "" else sym1.locationString) + " and\n" + + sym2 + ":" + tpe2 + + (if (sym2.owner == root) " at line " + (sym2.pos).line.get else sym2.locationString) + + "\nhave same type" + + (if (tpe1 =:= tpe2) "" else " after erasure: " + atPhase(phase.next)(sym1.tpe))) sym1.setInfo(ErrorType) } @@ -873,7 +881,19 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { tpt.tpe = erasure(tree.symbol.tpe).resultType result case _ => - super.transform(tree1) setType null + case class MyError(count : Int, ex : AssertionError) extends Error(ex.getMessage) + try { + super.transform(tree1) setType null + } catch { + case e @ MyError(n, ex) if n > 5 => throw e + case MyError(n,ex) => + Console.println(tree1) + throw MyError(n + 1, ex) + case ex : AssertionError => + Console.println(tree1) + throw MyError(0, ex) + case ex => throw ex + } } } } diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index ccf14b17c6..8c6a5a585c 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -309,9 +309,11 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter if (mixinClass.owner.isTerm) gen.mkAttributedThis(mixinClass.owner.enclClass) else gen.mkAttributedQualifier(currentClass.thisType.baseType(mixinClass).prefix) val rhs = ExplicitOuterTransformer.this.transform(path) + rhs.setPos(currentClass.pos) // see note below localTyper.typed { atPos(currentClass.pos) { - DefDef(outerAcc, {vparamss=>rhs}) + // @S: atPos not good enough because of nested atPos in DefDef method, which gives position from wrong class! + DefDef(outerAcc, {vparamss=>rhs}).setPos(currentClass.pos) } } } diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala index b66be5d98c..ae695f587f 100644 --- a/src/compiler/scala/tools/nsc/transform/Flatten.scala +++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala @@ -41,7 +41,7 @@ abstract class Flatten extends InfoTransform { var parents1 = parents val decls1 = newScope if (clazz.isPackageClass) { - atPhase(phase.next)(decls.toList foreach (decls1 enter)) + atPhase(phase.next)(decls.toList foreach (sym => decls1 enter sym)) } else { val oldowner = clazz.owner atPhase(phase.next)(oldowner.info) diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/transform/LiftCode.scala index ccd35442fb..91caf14b8c 100644 --- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala +++ b/src/compiler/scala/tools/nsc/transform/LiftCode.scala @@ -88,6 +88,7 @@ abstract class LiftCode extends Transform { if (rsym == reflect.NoSymbol) throw new TypeError("cannot reify symbol: " + tree.symbol) else reflect.Select(reify(qual), reify(tree.symbol)) + case _ : StubTree => reflect.Literal(0) case Literal(constant) => reflect.Literal(constant.value) @@ -250,7 +251,7 @@ abstract class LiftCode extends Transform { new Reifier(new ReifyEnvironment(), reflect.NoSymbol).reify(tree) def inject(code: reflect.Tree): Tree = - new Injector(ListMap.empty, new FreshNameCreator).inject(code) + new Injector(ListMap.empty, new FreshNameCreator.Default).inject(code) def codify (tree: Tree): Tree = New(TypeTree(appliedType(definitions.CodeClass.typeConstructor, diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala index 6d95b1a762..1ec4da1a54 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala @@ -26,7 +26,7 @@ trait Analyzer extends AnyRef val phaseName = "namer" def newPhase(_prev: Phase): StdPhase = new StdPhase(_prev) { def apply(unit: CompilationUnit): unit = - new Namer(rootContext(unit)).enterSym(unit.body) + newNamer(rootContext(unit)).enterSym(unit.body) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 734c29e2cf..ee1637c65a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -86,9 +86,12 @@ trait Contexts { self: Analyzer => sc = sc.outer } } - class Context { + // IDE hooks + protected def sanitize(tree : Tree) : Tree = tree + protected def scopeFor(old : Scope, tree : Tree) : Scope = newScope(old) + class Context private[typechecker] { var unit: CompilationUnit = _ - var tree: Tree = _ // Tree associated with this context + var tree: Tree = _ // Tree associated with this context var owner: Symbol = NoSymbol// The current owner var scope: Scope = _ // The current scope var outer: Context = _ // The next outer context @@ -113,39 +116,88 @@ trait Contexts { self: Analyzer => var savedTypeBounds: List[(Symbol, Type)] = List() - override def equals(that : Any) = that match { - case that if (super.equals(that)) => true - case NoContext => false + + def intern0 : Context = { + if (this eq NoContext) return this + val txt = new Context + txt.unit = unit + txt.tree = tree + txt.owner = owner + txt.scope = scope + assert(outer ne this) // stupid + txt.outer = outer // already interned + def f(what : Context) = + if (what eq this) txt + else what + txt.enclClass = f(enclClass) + txt.enclMethod = f(enclMethod) + txt.implicitsEnabled = implicitsEnabled + txt.variance = variance + txt._undetparams = _undetparams + txt.depth = depth + txt.imports = imports + txt.prefix = prefix + txt.inConstructorSuffix = inConstructorSuffix + txt.returnsSeen = returnsSeen + txt.reportGeneralErrors = reportGeneralErrors + txt.checking = checking + txt.retyping = retyping + txt.savedTypeBounds = savedTypeBounds + txt + } + override def equals(that : Any) : Boolean = that match { + case that : AnyRef if (this eq that) => true + case that if !inIDE => super.equals(that) + //case NoContext => false case that : Context => - val a0 = if (tree eq null) tree == that.tree else tree equalsStructure that.tree; - val a1 = owner == that.owner - val a2 = scope == that.scope - val a3 = outer == that.outer - val a4 = { - if (enclClass eq this) { - that.enclClass eq that; - } else enclClass == that.enclClass; + if (that eq NoContext) return this eq NoContext + assert(that ne NoContext) + if (this eq NoContext) return false + assert(inIDE) + def eq[T](x : T, y : T) = x == y + val a0 = { + if (tree ne null) tree.setType(null) + if ((tree eq null) || (that.tree eq null)) tree == that.tree else + tree equalsStructure that.tree; + } + val a1 = eq(owner, that.owner) + val a2 = eq(scope, that.scope) + def f(txt0 : Context, txt1 : Context) = + ((this eq txt0) && (that eq txt1)) || (txt0 eq txt1) + + val a3 = f(outer, that.outer) + val a4 = f(enclClass, that.enclClass) + val a5 = f(enclMethod, that.enclMethod) + val a6 = eq(variance, that.variance) + val a7 = eq(_undetparams, that._undetparams) + val a8 = eq(depth, that.depth) + val a9 = eq(imports, that.imports) + + val a10 = eq(prefix, that.prefix) + val a11 = eq(inConstructorSuffix, that.inConstructorSuffix) + val a12 = eq(implicitsEnabled, that.implicitsEnabled) + val a13 = eq(checking, that.checking) + val a14 = eq(retyping, that.retyping) + val a15 = eq(savedTypeBounds, that.savedTypeBounds) + val a16 = eq(unit, that.unit) + val ret = a0 && a1 && a2 && a3 && a4 && a5 && a6 && a7 && a8 && a9 && a10 && a11 && a12 && a13 && a14 && a15 && a16 + val a17 = { + if (implicitsRunId > that.implicitsRunId) { + that.implicitsRunId = NoRunId + that.implicitsCache = null + } + else if (that.implicitsRunId > implicitsRunId) { + implicitsRunId = NoRunId + implicitsCache = null + } + implicitsCache == that.implicitsCache } - val a5 = { - if (enclMethod eq this) - that.enclMethod eq that; - else enclMethod == that.enclMethod; + if (ret) { + if (!a17) { + assert(this.implicitsCache == null || that.implicitsCache == null) + } } - val a6 = variance == that.variance; - val a7 = _undetparams == that._undetparams; - val a8 = depth == that.depth; - val a9 = if (imports.length != that.imports.length) false else - (for (x <- imports.zip(that.imports)) yield - (x._1.tree equalsStructure x._2.tree) && x._1.depth == x._2.depth). - foldLeft(true)((x,y) => x && y); - - val a10 = prefix == that.prefix - val a11 = inConstructorSuffix == that.inConstructorSuffix - val a12 = implicitsEnabled == that.implicitsEnabled - val a13 = checking == that.checking - val a14 = retyping == that.retyping - val a15 = savedTypeBounds == that.savedTypeBounds - a0 && a1 && a2 && a3 && a4 && a5 && a6 && a7 && a8 && a9 && a10 && a11 && a12 && a13 && a14 && a15 + ret case _ => false } @@ -168,16 +220,23 @@ trait Contexts { self: Analyzer => scope: Scope, imports: List[ImportInfo]): Context = { val c = new Context c.unit = unit - c.tree = tree + c.tree = sanitize(tree) c.owner = owner c.scope = scope + + c.outer = intern(this) + def internIf(txt : Context) = { + if (txt eq this) c.outer // already interned! + else txt + } + tree match { case Template(_, _, _) | PackageDef(_, _) => c.enclClass = c c.prefix = c.owner.thisType c.inConstructorSuffix = false case _ => - c.enclClass = this.enclClass + c.enclClass = internIf(this.enclClass) c.prefix = if (c.owner != this.owner && c.owner.isTerm) NoPrefix else this.prefix @@ -187,7 +246,7 @@ trait Contexts { self: Analyzer => case DefDef(_, _, _, _, _, _) => c.enclMethod = c case _ => - c.enclMethod = this.enclMethod + c.enclMethod = internIf(this.enclMethod) } c.variance = this.variance c.depth = if (scope == this.scope) this.depth else this.depth + 1 @@ -197,7 +256,6 @@ trait Contexts { self: Analyzer => c.implicitsEnabled = this.implicitsEnabled c.checking = this.checking c.retyping = this.retyping - c.outer = this c } @@ -212,14 +270,21 @@ trait Contexts { self: Analyzer => def makeNewImport(imp: Import): Context = make(unit, imp, owner, scope, new ImportInfo(imp, depth) :: imports) - def make(tree: Tree, owner: Symbol, scope: Scope): Context = + + + def make(tree: Tree, owner: Symbol, scope: Scope): Context = { + if (tree == this.tree && owner == this.owner && scope == this.scope) this + else make0(tree, owner, scope) + } + private def make0(tree : Tree, owner : Symbol, scope : Scope) : Context = { make(unit, tree, owner, scope, imports) + } def makeNewScope(tree: Tree, owner: Symbol): Context = - make(tree, owner, newScope(scope)) + make(tree, owner, scopeFor(scope, tree)) def make(tree: Tree, owner: Symbol): Context = - make(tree, owner, scope) + make0(tree, owner, scope) def make(tree: Tree): Context = make(tree, owner) @@ -242,7 +307,7 @@ trait Contexts { self: Analyzer => //todo: find out why we need next line while (baseContext.tree.isInstanceOf[Template]) baseContext = baseContext.outer - val argContext = Contexts.this.makeNewScope(baseContext, tree, owner) + val argContext = baseContext.makeNewScope(tree, owner) argContext.reportGeneralErrors = this.reportGeneralErrors argContext.reportAmbiguousErrors = this.reportAmbiguousErrors def enterElems(c: Context) { @@ -364,6 +429,8 @@ trait Contexts { self: Analyzer => def accessWithin(owner: Symbol): Boolean = { var c = this while (c != NoContext && c.owner != owner) { + if (false && inIDE) // XXX: we didn't get to update these syms.... + assert(c.owner.fullNameString != owner.fullNameString) if (c.outer eq null) assert(false, "accessWithin(" + owner + ") " + c);//debug if (c.outer.enclClass eq null) assert(false, "accessWithin(" + owner + ") " + c);//debug c = c.outer.enclClass @@ -422,6 +489,11 @@ trait Contexts { self: Analyzer => private var implicitsCache: List[List[ImplicitInfo]] = null private var implicitsRunId = NoRunId + def resetCache : Unit = { + implicitsRunId = NoRunId + implicitsCache = null + if (outer != null && outer != this) outer.resetCache + } private def collectImplicits(syms: List[Symbol], pre: Type): List[ImplicitInfo] = for (sym <- syms if sym.hasFlag(IMPLICIT) && isAccessible(sym, pre, false)) yield new ImplicitInfo(sym.name, pre, sym) @@ -473,10 +545,33 @@ trait Contexts { self: Analyzer => } implicitsCache } - } + override def hashCode = { + var hc = 0 + implicit def b2i(b : Boolean) = if (b) 1 else 0 + // assum enclClass/enclMethod/outer are all interned already. + hc += tree.hashCodeStructure + def f(txt : Context) = if (txt eq this) 0 else System.identityHashCode(txt) + hc += f(enclClass) + hc += f(enclMethod) + hc += f(outer) + hc += owner.hashCode + hc += scope.hashCode + hc += variance.hashCode + hc += _undetparams.hashCode + hc += depth + hc += imports.hashCode + hc += prefix.hashCode + hc += inConstructorSuffix + hc += checking + hc += retyping + hc += savedTypeBounds.hashCode + hc += (if (unit eq null) 0 else unit.hashCode) + hc + } + } + def notifyImport(what : Name, container : Type, from : Name, to : Name) : Unit = {} class ImportInfo(val tree: Import, val depth: Int) { - /** The prefix expression */ def qual: Tree = tree.symbol.info match { case ImportType(expr) => expr @@ -495,6 +590,9 @@ trait Contexts { self: Analyzer => var renamed = false var selectors = tree.selectors while (selectors != Nil && result == NoSymbol) { + if (selectors.head._1 != nme.WILDCARD) + notifyImport(name, qual.tpe, selectors.head._1, selectors.head._2) + if (selectors.head._2 == name.toTermName) result = qual.tpe.member( if (name.isTypeName) selectors.head._1.toTypeName else selectors.head._1) @@ -508,6 +606,13 @@ trait Contexts { self: Analyzer => } override def toString() = tree.toString() + + override def hashCode = tree.hashCodeStructure + depth + override def equals(that : Any) = that match { + case that : ImportInfo => + depth == that.depth && (tree equalsStructure that.tree) + case _ => false + } } class ImplicitInfo(val name: Name, val pre: Type, val sym: Symbol) { @@ -521,5 +626,31 @@ trait Contexts { self: Analyzer => val NoImplicitInfo = new ImplicitInfo(null, null, null) - case class ImportType(expr: Tree) extends Type + case class ImportType(expr: Tree) extends Type { + override def equals(that : Any) = that match { + case ImportType(expr) => + if (inIDE) this.expr equalsStructure expr + else this.expr == expr + case _ => false + } + override def hashCode = if (inIDE) expr.hashCodeStructure else expr.hashCode + } + + /* APIs for interning contexts */ + import scala.collection.jcl + import scala.ref + protected def intern(txt : Context) = txt + class ContextInternMap extends jcl.WeakHashMap[Context,ref.WeakReference[Context]] { + var last : Context = _ + override def default(txt : Context) : ref.WeakReference[Context] = { + if (txt eq NoContext) new ref.WeakReference(NoContext) + val txt0 = txt.intern0 + last = txt0 // to prevent collection + val ret = new ref.WeakReference(txt0) + this(txt0) = ret + ret + } + def intern(txt : Context) = this(txt).get.get + } + } diff --git a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala index 1cdcf6210a..938a07f5bf 100644 --- a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala +++ b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala @@ -34,10 +34,21 @@ trait EtaExpansion { self: Analyzer => * tree is already attributed * </p> */ - def etaExpand(tree: Tree): Tree = { + def etaExpand(unit : CompilationUnit, tree: Tree): Tree = { val tpe = tree.tpe - var cnt = 0 - def freshName() = { cnt = cnt + 1; newTermName("eta$" + cnt) } + val symbolHash = if (!inIDE) "" else Integer.toString(tree.symbol.hashCode, 10 + ('z' - 'a')) + "$" + var cnt = 0 // for NoPosition + def freshName(pos : util.Position, n : Int) = { + cnt += 1 + if (pos == util.NoPosition) { + newTermName("eta$" + symbolHash + (cnt - 1)) + } else if (n == 0) { + newTermName(unit.fresh.newName(pos, "eta$" + symbolHash)) + } else { + newTermName(unit.fresh.newName(pos, "eta$" + symbolHash + n + "$")) + } + } + // { cnt = cnt + 1; newTermName("eta$" + cnt) } val defs = new ListBuffer[Tree] /** Append to <code>defs</code> value definitions for all non-stable @@ -50,7 +61,7 @@ trait EtaExpansion { self: Analyzer => def liftout(tree: Tree): Tree = if (treeInfo.isPureExpr(tree)) tree else { - val vname: Name = freshName() + val vname: Name = freshName(tree.pos, 0) defs += atPos(tree.pos)(ValDef(Modifiers(SYNTHETIC), vname, TypeTree(), tree)) Ident(vname) setPos tree.pos } @@ -76,8 +87,13 @@ trait EtaExpansion { self: Analyzer => case mt: ImplicitMethodType => tree case MethodType(formals, restpe) => + var cnt0 = 0 + def cnt = { + cnt0 += 1 + cnt0 - 1 + } val params = formals map (formal => - ValDef(Modifiers(SYNTHETIC | PARAM), freshName(), TypeTree() + ValDef(Modifiers(SYNTHETIC | PARAM), freshName(tree.pos, cnt), TypeTree() .setType(formal), EmptyTree)) val args = params map (param => Ident(param.name)) val applyArgs = diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index b79fca75f9..015c0636c8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -245,7 +245,7 @@ trait Infer { private def withDisambiguation[T](tp1: Type, tp2: Type)(op: => T): T = { def explainName(sym: Symbol) = { - if (!sym.name.toString.endsWith(")")) { + if (!sym.name.toString.endsWith(")") && !inIDE) { sym.name = newTypeName(sym.name.toString+"(in "+sym.owner+")") } } @@ -259,7 +259,7 @@ trait Infer { val name = sym1.name explainName(sym1) explainName(sym2) - if (sym1.owner == sym2.owner) sym2.name = newTypeName("(some other)"+sym2.name) + if (sym1.owner == sym2.owner && !inIDE) sym2.name = newTypeName("(some other)"+sym2.name) patches += (sym1, sym2, name) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 9138b2d412..a6409c6398 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -39,14 +39,18 @@ trait Namers { self: Analyzer => } } /** overridden by IDE to not manually enter value parameters */ - protected final def doEnterValueParams = !inIDE; - protected def inIDE = false; + protected final def doEnterValueParams = true // !inIDE; + // can't use the other ones. + protected def newDecls(classSym : Symbol) : Scope = newClassScope - class Namer(val context: Context) { + private class NormalNamer(context : Context) extends Namer(context) + def newNamer(context : Context) : Namer = new NormalNamer(context) + + abstract class Namer(val context: Context) { val typer = newTyper(context) - def setPrivateWithin(tree: Tree, sym: Symbol, mods: Modifiers): Symbol = { + def setPrivateWithin[Sym <: Symbol](tree: Tree, sym: Sym, mods: Modifiers): Sym = { if (!mods.privateWithin.isEmpty) sym.privateWithin = typer.qualifyingClassContext(tree, mods.privateWithin).owner sym @@ -75,6 +79,10 @@ trait Namers { self: Analyzer => } private var innerNamerCache: Namer = null + protected def makeConstructorScope(classContext : Context) : Context = { + val outerContext = classContext.outer.outer + outerContext.makeNewScope(outerContext.tree, outerContext.owner) + } def namerOf(sym: Symbol): Namer = { @@ -82,46 +90,51 @@ trait Namers { self: Analyzer => if (innerNamerCache eq null) innerNamerCache = if (!isTemplateContext(context)) this - else new Namer(context.make(context.tree, context.owner, newScope)) + else newNamer(context.make(context.tree, context.owner, scopeFor(context.tree))) innerNamerCache } def primaryConstructorParamNamer: Namer = { //todo: can we merge this with SCCmode? val classContext = context.enclClass - val outerContext = classContext.outer.outer - val paramContext = outerContext.makeNewScope(outerContext.tree, outerContext.owner) - classContext.owner.unsafeTypeParams foreach(sym => paramContext.scope.enter(sym)) - new Namer(paramContext) - } - - if (sym.isTerm && - (sym.hasFlag(PARAM) && sym.owner.isPrimaryConstructor || sym.hasFlag(PARAMACCESSOR))) - primaryConstructorParamNamer - else - innerNamer + val paramContext = makeConstructorScope(classContext) + val unsafeTypeParams = context.owner.unsafeTypeParams + unsafeTypeParams foreach(sym => paramContext.scope.enter(sym)) + newNamer(paramContext) + } + if (sym.isTerm) { + if (sym.hasFlag(PARAM) && sym.owner.isPrimaryConstructor) + primaryConstructorParamNamer + else if (sym.hasFlag(PARAMACCESSOR) && !inIDE) + primaryConstructorParamNamer + else innerNamer + } else innerNamer } + protected def conflict(newS : Symbol, oldS : Symbol) : Boolean = { + (!oldS.isSourceMethod || + nme.isSetterName(newS.name) || + newS.owner.isPackageClass) && + !((newS.owner.isTypeParameter || newS.owner.isAbstractType) && + newS.name.length==1 && newS.name(0)=='_') //@M: allow repeated use of `_' for higher-order type params + } + protected def setInfo[Sym <: Symbol](sym : Sym)(tpe : LazyType) : Sym = sym.setInfo(tpe) private def doubleDefError(pos: Position, sym: Symbol) { context.error(pos, sym.name.toString() + " is already defined as " + (if (sym.hasFlag(CASE)) "case class " + sym.name else sym.toString())) } - def enterInScope[A <: Symbol](sym: A): A = { + def enterInScope(sym: Symbol): Symbol = { // allow for overloaded methods if (!(sym.isSourceMethod && sym.owner.isClass && !sym.owner.isPackageClass)) { val prev = context.scope.lookupEntry(sym.name); - if ((prev ne null) && prev.owner == context.scope && - (!prev.sym.isSourceMethod || - nme.isSetterName(sym.name) || - sym.owner.isPackageClass) && - !((sym.owner.isTypeParameter || sym.owner.isAbstractType) - && sym.name.length==1 && sym.name(0)=='_')) { //@M: allow repeated use of `_' for higher-order type params + if ((prev ne null) && prev.owner == context.scope && conflict(sym, prev.sym)) { doubleDefError(sym.pos, prev.sym) - sym setInfo ErrorType + if (!inIDE) sym setInfo ErrorType // don't do this in IDE for stability + context.scope unlink prev.sym + context.scope enter sym } else context.scope enter sym } else context.scope enter sym - sym } def enterPackageSymbol(pos: Position, name: Name): Symbol = { @@ -133,79 +146,102 @@ trait Namers { self: Analyzer => } else { val cowner = if (context.owner == EmptyPackageClass) RootClass else context.owner val pkg = cowner.newPackage(pos, name) - pkg.moduleClass.setInfo(new PackageClassInfoType(newScope, pkg.moduleClass)) + // IDE: newScope should be ok because packages are never destroyed. + if (inIDE) assert(pkg.moduleClass.rawInfoSafe.isEmpty || !pkg.moduleClass.rawInfo.isComplete) + pkg.moduleClass.setInfo(new PackageClassInfoType(newScope, pkg.moduleClass, null)) pkg.setInfo(pkg.moduleClass.tpe) enterInScope(pkg) } } - def inConstructorFlag: long = + def inConstructorFlag: Long = if (context.owner.isConstructor && !context.inConstructorSuffix || context.owner.isEarly) INCONSTRUCTOR else 0l - private def enterClassSymbol(pos: Position, flags: long, name: Name): Symbol = { - var c: Symbol = context.scope.lookup(name) - if (c.isType && !currentRun.compiles(c) && context.scope == c.owner.info.decls) { - updatePosFlags(c, pos, flags) + def enterClassSymbol(tree : ClassDef): Symbol = { + var c: Symbol = context.scope.lookup(tree.name); + // Never take the first path in the IDE because we could be completing c.owner's type! + // the other path will handle symbol re-use well enough. + if (!inIDE && c.isType && context.scope == c.owner.info.decls && !currentRun.compiles(c)) { + updatePosFlags(c, tree.pos, tree.mods.flags) + setPrivateWithin(tree, c, tree.mods) } else { - c = enterInScope(context.owner.newClass(pos, name)).setFlag(flags | inConstructorFlag) + //if (inIDE && c != NoSymbol) currentRun.compiles(c) // in IDE, will unload/save non-source symbol + var sym = context.owner.newClass(tree.pos, tree.name) + sym = sym.setFlag(tree.mods.flags | inConstructorFlag) + sym = setPrivateWithin(tree, sym, tree.mods) + c = enterInScope(sym) } if (c.owner.isPackageClass) { - val file = context.unit.source.getFile() + val file = context.unit.source.file val clazz = c.asInstanceOf[ClassSymbol] if (settings.debug.value && (clazz.sourceFile ne null) && !clazz.sourceFile.equals(file)) { Console.err.println("SOURCE MISMATCH: " + clazz.sourceFile + " vs. " + file + " SYM=" + c); } clazz.sourceFile = file if (clazz.sourceFile ne null) { - assert(!currentRun.compiles(clazz) || clazz.sourceFile == currentRun.symSource(c)); + assert(inIDE || !currentRun.compiles(clazz) || clazz.sourceFile == currentRun.symSource(c)); currentRun.symSource(c) = clazz.sourceFile } } + assert(c.name.toString.indexOf('(') == -1) c } - - private def enterModuleSymbol(pos: Position, flags: long, name: Name): Symbol = { - var m: Symbol = context.scope.lookup(name) - if (m.isModule && !m.isPackage && !currentRun.compiles(m) && - (context.scope == m.owner.info.decls)) { - updatePosFlags(m, pos, flags) + def enterModuleSymbol(tree : ModuleDef): Symbol = { + // .pos, mods.flags | MODULE | FINAL, name + assert(tree.name.isTermName) + var m: Symbol = context.scope.lookup(tree.name) + if (!inIDE && m.isModule && !m.isPackage && (context.scope == m.owner.info.decls) && + !currentRun.compiles(m)) { + updatePosFlags(m, tree.pos, tree.mods.flags|MODULE|FINAL) + setPrivateWithin(tree, m, tree.mods) } else { - if (m.isTerm && !m.isPackage && !currentRun.compiles(m) && (context.scope == m.owner.info.decls)) + if (m.isTerm && !m.isPackage && currentRun.compiles(m) && (context.scope == m.owner.info.decls)) context.scope.unlink(m) - m = context.owner.newModule(pos, name) - m.setFlag(flags) - m.moduleClass.setFlag(flags | inConstructorFlag) - enterInScope(m) + + m = context.owner.newModule(tree.pos, tree.name) + m.setFlag(tree.mods.flags) + m = setPrivateWithin(tree, m, tree.mods) + m = enterInScope(m) + + m.moduleClass.setFlag(tree.mods.flags|MODULE|FINAL| inConstructorFlag) + setPrivateWithin(tree, m.moduleClass, tree.mods) } if (m.owner.isPackageClass) { - m.moduleClass.sourceFile = context.unit.source.getFile() + m.moduleClass.sourceFile = context.unit.source.file currentRun.symSource(m) = m.moduleClass.sourceFile } m } - private def enterCaseFactorySymbol(pos: Position, flags: long, name: Name): Symbol = { + def enterCaseFactorySymbol(tree : ClassDef): Symbol = { + val pos = tree.pos + val flags = tree.mods.flags & AccessFlags | METHOD | CASE + val name = tree.name.toTermName var m: Symbol = context.scope.lookup(name) - if (m.isTerm && !m.isPackage && !currentRun.compiles(m) && context.scope == m.owner.info.decls) { + if (!inIDE && m.isTerm && !m.isPackage && !currentRun.compiles(m) && context.scope == m.owner.info.decls) { updatePosFlags(m, pos, flags) + setPrivateWithin(tree, m, tree.mods) } else { - m = enterInScope(context.owner.newMethod(pos, name)).setFlag(flags) + // recycle the old fashion way. + m = enterInScope{ + var sym = context.owner.newMethod(pos, name).setFlag(flags) + sym = setPrivateWithin(tree, sym, tree.mods) + sym + } } if (m.owner.isPackageClass) - currentRun.symSource(m) = context.unit.source.getFile() + currentRun.symSource(m) = context.unit.source.file m } - def enterSyms(trees: List[Tree]): Namer = { var namer : Namer = this for (tree <- trees) { val txt = namer.enterSym(tree) - if (!(txt eq namer.context)) namer = new Namer(txt) + if (!(txt eq namer.context)) namer = newNamer(txt) } namer } - def newTypeSkolems(tparams: List[Symbol]): List[Symbol] = { val tskolems = tparams map (_.newTypeSkolem) val ltp = new LazyType { @@ -216,7 +252,6 @@ trait Namers { self: Analyzer => tskolems foreach (_.setInfo(ltp)) tskolems } - /** Replace type parameters with their TypeSkolems, which can later be deskolemized to the original type param * (a skolem is a representation of a bound variable when viewed outside its scope) */ @@ -237,10 +272,15 @@ trait Namers { self: Analyzer => override val typeParams: List[Symbol]= tparams map (_.symbol) //@M override def complete(sym: Symbol) { if(ownerSym.isAbstractType) //@M an abstract type's type parameters are entered -- TODO: change to isTypeMember ? - new Namer(ctx.makeNewScope(owner, ownerSym)).enterSyms(tparams) //@M + newNamer(ctx.makeNewScope(owner, ownerSym)).enterSyms(tparams) //@M restp.complete(sym) } } + def reuse[T <: Tree](tree: T) = if (!inIDE) tree else { + val tree0 = tree.duplicate + //tree0.symbol = tree.symbol + tree0 + } def enterSym(tree: Tree): Context = { @@ -253,11 +293,11 @@ trait Namers { self: Analyzer => //@M e.g., in [A[x <: B], B], A and B are entered first as both are in scope in the definition of x //@M x is only in scope in `A[x <: B]' if(!sym.isAbstractType) //@M TODO: change to isTypeMember ? - new Namer(context.makeNewScope(tree, sym)).enterSyms(tparams) + newNamer(context.makeNewScope(tree, sym)).enterSyms(tparams) ltype = new LazyPolyType(tparams, ltype, tree, sym, context) //@M if (sym.isTerm) skolemize(tparams) } - sym.setInfo(ltype) + setInfo(sym)(ltype) } def finish = finishWith(List()) @@ -267,45 +307,43 @@ trait Namers { self: Analyzer => tree match { case PackageDef(name, stats) => tree.symbol = enterPackageSymbol(tree.pos, name) - val namer = new Namer( + val namer = newNamer( context.make(tree, tree.symbol.moduleClass, tree.symbol.info.decls)) namer.enterSyms(stats) - case ClassDef(mods, name, tparams, impl) => + case tree @ ClassDef(mods, name, tparams, impl) => + tree.symbol = enterClassSymbol(tree) + finishWith(tparams) if ((mods.flags & CASE) != 0) { // enter case factory method. - tree.symbol = enterCaseFactorySymbol( - tree.pos, mods.flags & AccessFlags | METHOD | CASE, name.toTermName) - tree.symbol.setInfo(namerOf(tree.symbol).caseFactoryCompleter(tree)) - setPrivateWithin(tree, tree.symbol, mods) + val sym = enterCaseFactorySymbol(tree) + setInfo(sym)(namerOf(sym).caseFactoryCompleter(reuse(tree))) } - tree.symbol = enterClassSymbol(tree.pos, mods.flags, name) - setPrivateWithin(tree, tree.symbol, mods) - finishWith(tparams) - case ModuleDef(mods, name, _) => - tree.symbol = enterModuleSymbol(tree.pos, mods.flags | MODULE | FINAL, name) - setPrivateWithin(tree, tree.symbol, mods) - setPrivateWithin(tree, tree.symbol.moduleClass, mods) - tree.symbol.moduleClass.setInfo(namerOf(tree.symbol).moduleClassTypeCompleter(tree)) + case tree @ ModuleDef(mods, name, _) => + tree.symbol = enterModuleSymbol(tree) + // IDE: do not use the setInfo call for the module class as it is initialized + // through module symbol + tree.symbol.moduleClass.setInfo(namerOf(tree.symbol).moduleClassTypeCompleter(reuse(tree))) finish + case ValDef(mods, name, tp, rhs) => if (context.owner.isClass && (mods.flags & (PRIVATE | LOCAL)) != (PRIVATE | LOCAL) || (mods.flags & LAZY) != 0) { val accflags: Long = ACCESSOR | (if ((mods.flags & MUTABLE) != 0) mods.flags & ~MUTABLE & ~PRESUPER else mods.flags & ~PRESUPER | STABLE) - val getter = owner.newMethod(tree.pos, name).setFlag(accflags) - getter.setInfo(namerOf(getter).getterTypeCompleter(tree)) + var getter = owner.newMethod(tree.pos, name).setFlag(accflags) setPrivateWithin(tree, getter, mods) - enterInScope(getter) + getter = enterInScope(getter).asInstanceOf[TermSymbol] + setInfo(getter)(namerOf(getter).getterTypeCompleter(tree)) if ((mods.flags & MUTABLE) != 0) { - val setter = owner.newMethod(tree.pos, nme.getterToSetter(name)) + var setter = owner.newMethod(tree.pos, nme.getterToSetter(name)) .setFlag(accflags & ~STABLE & ~CASEACCESSOR) - setter.setInfo(namerOf(setter).setterTypeCompleter(tree)) setPrivateWithin(tree, setter, mods) - enterInScope(setter) + setter = enterInScope(setter).asInstanceOf[TermSymbol] + setInfo(setter)(namerOf(setter).setterTypeCompleter(tree)) } tree.symbol = - if ((mods.flags & DEFERRED) == 0) { - val vsym = + if ((mods.flags & DEFERRED) == 0) { // not deferred + var vsym = if (!context.owner.isClass) { assert((mods.flags & LAZY) != 0) // if not a field, it has to be a lazy val owner.newValue(tree.pos, name + "$lzy" ).setFlag(mods.flags | MUTABLE) @@ -313,39 +351,39 @@ trait Namers { self: Analyzer => owner.newValue(tree.pos, nme.getterToLocal(name)) .setFlag(mods.flags & FieldFlags | PRIVATE | LOCAL | (if ((mods.flags & LAZY) != 0) MUTABLE else 0)) } - val value = enterInScope(vsym) - value.setInfo(namerOf(value).typeCompleter(tree)) + vsym = enterInScope(vsym).asInstanceOf[TermSymbol] + setInfo(vsym)(namerOf(vsym).typeCompleter(tree)) if ((mods.flags & LAZY) != 0) - value.setLazyAccessor(getter) - value + vsym.setLazyAccessor(getter) + vsym } else getter; } else { - tree.symbol = enterInScope(owner.newValue(tree.pos, name)) - .setFlag(mods.flags) + tree.symbol = enterInScope(owner.newValue(tree.pos, name) + .setFlag(mods.flags)) finish } case DefDef(mods, nme.CONSTRUCTOR, tparams, _, _, _) => - tree.symbol = enterInScope(owner.newConstructor(tree.pos)) - .setFlag(mods.flags | owner.getFlag(ConstrFlags)) - setPrivateWithin(tree, tree.symbol, mods) + var sym = owner.newConstructor(tree.pos).setFlag(mods.flags | owner.getFlag(ConstrFlags)) + setPrivateWithin(tree, sym, mods) + tree.symbol = enterInScope(sym) finishWith(tparams) case DefDef(mods, name, tparams, _, _, _) => - tree.symbol = enterInScope(owner.newMethod(tree.pos, name)) - .setFlag(mods.flags) - setPrivateWithin(tree, tree.symbol, mods) + var sym = (owner.newMethod(tree.pos, name)).setFlag(mods.flags) + setPrivateWithin(tree, sym, mods) + tree.symbol = enterInScope(sym) finishWith(tparams) case TypeDef(mods, name, tparams, _) => var flags: Long = mods.flags if ((flags & PARAM) != 0) flags |= DEFERRED - tree.symbol = enterInScope(new TypeSymbol(owner, tree.pos, name)) - .setFlag(flags) - setPrivateWithin(tree, tree.symbol, mods) + var sym =new TypeSymbol(owner, tree.pos, name).setFlag(flags) + setPrivateWithin(tree, sym, mods) + tree.symbol = enterInScope(sym) finishWith(tparams) case DocDef(_, defn) => enterSym(defn) case imp @ Import(_, _) => tree.symbol = NoSymbol.newImport(tree.pos) - tree.symbol.setInfo(namerOf(tree.symbol).typeCompleter(tree)) + setInfo(tree.symbol)(namerOf(tree.symbol).typeCompleter(tree)) return (context.makeNewImport(imp)) case _ => } @@ -451,11 +489,20 @@ trait Namers { self: Analyzer => def enterValueParams(owner: Symbol, vparamss: List[List[ValDef]]): List[List[Symbol]] = { def enterValueParam(param: ValDef): Symbol = if (doEnterValueParams) { - param.symbol = owner.newValueParameter(param.pos, param.name) - .setInfo(typeCompleter(param)) - .setFlag(param.mods.flags & (BYNAMEPARAM | IMPLICIT)) - setPrivateWithin(param, param.symbol, param.mods) - enterInScope(param.symbol) + if (inIDE) param.symbol = { + var sym = owner.newValueParameter(param.pos, param.name). + setFlag(param.mods.flags & (BYNAMEPARAM | IMPLICIT)) + setPrivateWithin(param, sym, param.mods) + sym = enterInScope(sym).asInstanceOf[TermSymbol] + if (!sym.rawInfoSafe.isDefined || sym.rawInfo.isComplete) + setInfo(sym)(typeCompleter(param)) + sym + } else param.symbol = setInfo( + enterInScope{ + val sym = owner.newValueParameter(param.pos, param.name). + setFlag(param.mods.flags & (BYNAMEPARAM | IMPLICIT)) + setPrivateWithin(param, sym, param.mods) + })(typeCompleter(param)) param.symbol } else param.symbol vparamss.map(_.map(enterValueParam)) @@ -477,7 +524,7 @@ trait Namers { self: Analyzer => def enterSelf(self: ValDef) { if (!self.tpt.isEmpty) { clazz.typeOfThis = selfTypeCompleter(self.tpt) - self.symbol = clazz.thisSym + self.symbol = clazz.thisSym.setPos(self.pos) } else { self.tpt.tpe = NoType if (self.name != nme.WILDCARD) { @@ -489,13 +536,13 @@ trait Namers { self: Analyzer => } if (self.name != nme.WILDCARD) { self.symbol.name = self.name - context.scope enter self.symbol + self.symbol = context.scope enter self.symbol } } val parents = typer.parentTypes(templ) map checkParent enterSelf(templ.self) - val decls = newDecls(templ, clazz) - new Namer(context.make(templ, clazz, decls)).enterSyms(templ.body) + val decls = newDecls(clazz) + newNamer(context.make(templ, clazz, decls)).enterSyms(templ.body) ClassInfoType(parents, decls, clazz) } @@ -507,7 +554,14 @@ trait Namers { self: Analyzer => val meth = context.owner val tparamSyms = typer.reenterTypeParams(tparams) - var vparamSymss = enterValueParams(meth, vparamss) + var vparamSymss = + if (inIDE && meth.isPrimaryConstructor) { + // @S: because they have already been entered this way.... + assert(true) + enterValueParams(meth.owner.owner, vparamss) + } else { + enterValueParams(meth, vparamss) + } if (tpt.isEmpty && meth.name == nme.CONSTRUCTOR) tpt.tpe = context.enclClass.owner.tpe if (onlyPresentation) @@ -700,7 +754,7 @@ trait Namers { self: Analyzer => val ainfos = for { annot <- defn.mods.annotations val ainfo = typer.typedAnnotation(annot) - if !ainfo.atp.isError + if !ainfo.atp.isError && annot != null } yield ainfo if (!ainfos.isEmpty) { val annotated = if (sym.isModule) sym.moduleClass else sym @@ -712,17 +766,17 @@ trait Namers { self: Analyzer => try { tree match { case ClassDef(_, _, tparams, impl) => - new Namer(makeNewScope(context, tree, sym)).classSig(tparams, impl) + newNamer(context.makeNewScope(tree, sym)).classSig(tparams, impl) case ModuleDef(_, _, impl) => val clazz = sym.moduleClass - clazz.setInfo(new Namer(makeNewScope(context, tree, clazz)).templateSig(impl)) + clazz.setInfo(newNamer(context.makeNewScope(tree, clazz)).templateSig(impl)) //clazz.typeOfThis = singleType(sym.owner.thisType, sym); clazz.tpe; case DefDef(_, _, tparams, vparamss, tpt, rhs) => val result = - new Namer(makeNewScope(context, tree, sym)).methodSig(tparams, vparamss, tpt, rhs); + newNamer(context.makeNewScope(tree, sym)).methodSig(tparams, vparamss, tpt, rhs); checkContractive(sym, result) case vdef @ ValDef(mods, _, tpt, rhs) => @@ -741,7 +795,7 @@ trait Namers { self: Analyzer => } else typer1.typedType(tpt).tpe case TypeDef(_, _, tparams, rhs) => - new Namer(makeNewScope(context, tree, sym)).typeDefSig(sym, tparams, rhs) //@M! + newNamer(context.makeNewScope(tree, sym)).typeDefSig(sym, tparams, rhs) //@M! case Import(expr, selectors) => val expr1 = typer.typedQualifier(expr) @@ -813,7 +867,7 @@ trait Namers { self: Analyzer => } if (sym.hasFlag(IMPLICIT) && !sym.isTerm) context.error(sym.pos, "`implicit' modifier can be used only for values, variables and methods") - if (sym.hasFlag(IMPLICIT) && sym.owner.isPackageClass) + if (sym.hasFlag(IMPLICIT) && sym.owner.isPackageClass && !inIDE) context.error(sym.pos, "`implicit' modifier cannot be used for top-level objects") if (sym.hasFlag(ABSTRACT) && !sym.isClass) context.error(sym.pos, "`abstract' modifier can be used only for classes; " + diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index aa5a2909e1..7323529d94 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -84,7 +84,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT } } - override def transform(tree: Tree): Tree = tree match { + override def transform(tree: Tree): Tree = try { tree match { case ClassDef(_, _, _, _) => checkCompanionNameClashes(tree.symbol) val decls = tree.symbol.info.decls @@ -181,6 +181,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT super.transform(tree) case Apply(fn, args) => + assert(fn.tpe != null) copy.Apply(tree, transform(fn), transformArgs(args, fn.tpe.paramTypes)) case Function(vparams, body) => withInvalidOwner { @@ -188,6 +189,12 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT } case _ => super.transform(tree) + }} catch { + case ex : AssertionError => + if (tree.symbol != null && tree.symbol != NoSymbol) + Console.println("TRANSFORM: " + tree.symbol.sourceFile) + Console.println("TREE: " + tree) + throw ex } override def atOwner[A](owner: Symbol)(trans: => A): A = { diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 8fb892670b..d9ee9071cd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -29,7 +29,11 @@ import scala.collection.mutable.ListBuffer trait SyntheticMethods { self: Analyzer => import global._ // the global environment import definitions._ // standard classes and methods - import typer.{typed} // methods to type trees + //import global.typer.{typed} // methods to type trees + // @S: type hack: by default, we are used from global.analyzer context + // so this cast won't fail. If we aren't in global.analyzer, we have + // to override this method anyways. + protected def typer : Typer = global.typer.asInstanceOf[Typer] /** * @param templ ... @@ -42,15 +46,15 @@ trait SyntheticMethods { self: Analyzer => val localContext = if (reporter.hasErrors) context.makeSilent(false) else context val localTyper = newTyper(localContext) - def hasImplementation(name: Name): Boolean = { + def hasImplementation(name: Name): Boolean = if (inIDE) true else { val sym = clazz.info.nonPrivateMember(name) sym.isTerm && !(sym hasFlag DEFERRED) } - def hasOverridingImplementation(meth: Symbol): Boolean = { + def hasOverridingImplementation(meth: Symbol): Boolean = if (inIDE) true else { val sym = clazz.info.nonPrivateMember(meth.name) sym.alternatives exists { sym => - sym != meth && !(sym hasFlag DEFERRED) && + sym != meth && !(sym hasFlag DEFERRED) && !(sym hasFlag SYNTHETIC) && (clazz.thisType.memberType(sym) matches clazz.thisType.memberType(meth)) } } @@ -59,8 +63,11 @@ trait SyntheticMethods { self: Analyzer => newSyntheticMethod(name, flags | OVERRIDE, tpe) def newSyntheticMethod(name: Name, flags: Int, tpe: Type) = { - val method = clazz.newMethod(clazz.pos, name) setFlag (flags) setInfo tpe - clazz.info.decls.enter(method) + var method = clazz.newMethod(clazz.pos, name) setFlag ({ + if (inIDE) flags | SYNTHETIC + else flags + }) setInfo tpe + method = clazz.info.decls.enter(method).asInstanceOf[TermSymbol] method } @@ -72,18 +79,18 @@ trait SyntheticMethods { self: Analyzer => */ def productPrefixMethod: Tree = { val method = syntheticMethod(nme.productPrefix, FINAL, PolyType(List(), StringClass.tpe)) - typed(DefDef(method, vparamss => Literal(Constant(clazz.name.decode)))) + typer.typed(DefDef(method, vparamss => Literal(Constant(clazz.name.decode)))) } def productArityMethod(nargs:Int ): Tree = { val method = syntheticMethod(nme.productArity, FINAL, PolyType(List(), IntClass.tpe)) - typed(DefDef(method, vparamss => Literal(Constant(nargs)))) + typer.typed(DefDef(method, vparamss => Literal(Constant(nargs)))) } def productElementMethod(accs: List[Symbol]): Tree = { //val retTpe = lub(accs map (_.tpe.resultType)) val method = syntheticMethod(nme.productElement, FINAL, MethodType(List(IntClass.tpe), AnyClass.tpe/*retTpe*/)) - typed(DefDef(method, vparamss => Match(Ident(vparamss.head.head), { + typer.typed(DefDef(method, vparamss => Match(Ident(vparamss.head.head), { (for ((sym,i) <- accs.zipWithIndex) yield { CaseDef(Literal(Constant(i)),EmptyTree, Ident(sym)) }):::List(CaseDef(Ident(nme.WILDCARD), EmptyTree, @@ -95,12 +102,12 @@ trait SyntheticMethods { self: Analyzer => def moduleToStringMethod: Tree = { val method = syntheticMethod(nme.toString_, FINAL, MethodType(List(), StringClass.tpe)) - typed(DefDef(method, vparamss => Literal(Constant(clazz.name.decode)))) + typer.typed(DefDef(method, vparamss => Literal(Constant(clazz.name.decode)))) } def tagMethod: Tree = { val method = syntheticMethod(nme.tag, FINAL, MethodType(List(), IntClass.tpe)) - typed(DefDef(method, vparamss => Literal(Constant(clazz.tag)))) + typer.typed(DefDef(method, vparamss => Literal(Constant(clazz.tag)))) } def forwardingMethod(name: Name): Tree = { @@ -110,7 +117,7 @@ trait SyntheticMethods { self: Analyzer => else target.tpe.paramTypes.tail val method = syntheticMethod( name, 0, MethodType(paramtypes, target.tpe.resultType)) - typed(DefDef(method, vparamss => + typer.typed(DefDef(method, vparamss => Apply(gen.mkAttributedRef(target), This(clazz) :: (vparamss.head map Ident)))) } @@ -148,7 +155,7 @@ trait SyntheticMethods { self: Analyzer => val (pat, guard) = { val guards = new ListBuffer[Tree] val params = for ((acc, cpt) <- clazz.caseFieldAccessors zip constrParamTypes) yield { - val name = context.unit.fresh.newName(acc.name+"$") + val name = context.unit.fresh.newName(clazz.pos, acc.name+"$") val isVarArg = cpt.typeSymbol == RepeatedParamClass guards += Apply( Select( @@ -185,16 +192,16 @@ trait SyntheticMethods { self: Analyzer => // but then it is renamed !!! val method = newSyntheticMethod(nme.readResolve, PROTECTED, MethodType(List(), ObjectClass.tpe)) - typed(DefDef(method, vparamss => gen.mkAttributedRef(clazz.sourceModule))) + typer.typed(DefDef(method, vparamss => gen.mkAttributedRef(clazz.sourceModule))) } def newAccessorMethod(tree: Tree): Tree = tree match { case DefDef(_, _, _, _, _, rhs) => - val newAcc = tree.symbol.cloneSymbol - newAcc.name = context.unit.fresh.newName(tree.symbol.name + "$") + var newAcc = tree.symbol.cloneSymbol + newAcc.name = context.unit.fresh.newName(tree.symbol.pos, tree.symbol.name + "$") newAcc.setFlag(SYNTHETIC).resetFlag(ACCESSOR | PARAMACCESSOR | PRIVATE) - newAcc.owner.info.decls enter newAcc - val result = typed(DefDef(newAcc, vparamss => rhs.duplicate)) + newAcc = newAcc.owner.info.decls enter newAcc + val result = typer.typed(DefDef(newAcc, vparamss => rhs.duplicate)) log("new accessor method " + result) result } @@ -226,7 +233,7 @@ trait SyntheticMethods { self: Analyzer => def addBeanGetterMethod(sym: Symbol) = { val getter = beanSetterOrGetter(sym) if (getter != NoSymbol) - ts += typed(DefDef( + ts += typer.typed(DefDef( getter, vparamss => if (sym hasFlag DEFERRED) EmptyTree else gen.mkAttributedRef(sym))) } @@ -234,7 +241,7 @@ trait SyntheticMethods { self: Analyzer => def addBeanSetterMethod(sym: Symbol) = { val setter = beanSetterOrGetter(sym) if (setter != NoSymbol) - ts += typed(DefDef( + ts += typer.typed(DefDef( setter, vparamss => if (sym hasFlag DEFERRED) EmptyTree @@ -257,7 +264,7 @@ trait SyntheticMethods { self: Analyzer => } } - if (clazz.info.nonPrivateDecl(nme.tag) == NoSymbol) ts += tagMethod + if (!inIDE && clazz.info.nonPrivateDecl(nme.tag) == NoSymbol) ts += tagMethod if (clazz.isModuleClass) { if (!hasOverridingImplementation(Object_toString)) ts += moduleToStringMethod } else { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index cd852c8b50..1ef6b935e7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -44,7 +44,6 @@ trait Typers { self: Analyzer => superDefs.clear } - def newTyper(context: Context): Typer = new Typer(context) object UnTyper extends Traverser { override def traverse(tree: Tree) = { @@ -53,12 +52,20 @@ trait Typers { self: Analyzer => super.traverse(tree) } } - def makeNewScope(txt: Context, tree: Tree, sym: Symbol) = - txt.makeNewScope(tree, sym) + // IDE hooks + def newTyper(context: Context): Typer = new NormalTyper(context) + private class NormalTyper(context : Context) extends Typer(context) + def scopeFor(tree : Tree) : Scope = newScope + def newLocalDummy(clazz : Symbol, pos : Position) = clazz.newLocalDummy(pos) + def recycle(sym : Symbol) : Symbol = sym + // hooks for auto completion + def compare(sym : Symbol, name : Name) = sym.name == name + def verifyAndPrioritize[T](g : Symbol => Symbol)(pt : Type)(f : => T) = f + def trackSetInfo[T <: Symbol](sym : T)(info : Type) : T = { + sym.setInfo(info) + sym + } - def newDecls(tree: CompoundTypeTree) = newScope - def newDecls(tree: Template, clazz: Symbol) = newScope - def newTemplateScope(impl: Template, clazz: Symbol) = newScope // Mode constants @@ -132,7 +139,7 @@ trait Typers { self: Analyzer => private def argMode(fun: Tree, mode: Int) = if (treeInfo.isSelfOrSuperConstrCall(fun)) mode | SCCmode else mode - class Typer(context0: Context) { + abstract class Typer(context0: Context) { import context0.unit val infer = new Inferencer(context0) { @@ -177,9 +184,10 @@ trait Typers { self: Analyzer => */ private def inferView(pos: Position, from: Type, name: Name, tp: Type, reportAmbiguous: Boolean): Tree = { val to = refinedType(List(WildcardType), NoSymbol) - val psym = (if (name.isTypeName) to.typeSymbol.newAbstractType(pos, name) - else to.typeSymbol.newValue(pos, name)) setInfo tp - to.decls.enter(psym) + var psym = (if (name.isTypeName) to.typeSymbol.newAbstractType(pos, name) + else to.typeSymbol.newValue(pos, name)) + psym = to.decls enter psym + psym setInfo tp inferView(pos, from, to, reportAmbiguous) } @@ -188,7 +196,7 @@ trait Typers { self: Analyzer => private var namerCache: Namer = null def namer = { if ((namerCache eq null) || namerCache.context != context) - namerCache = new Namer(context) + namerCache = newNamer(context) namerCache } @@ -346,7 +354,7 @@ trait Typers { self: Analyzer => this.scope = scope hiddenSymbols = List() val tp1 = apply(tree.tpe) - if (hiddenSymbols.isEmpty) tree setType tp1 + if (hiddenSymbols.isEmpty || inIDE) tree setType tp1 // @S: because arguments of classes are owned by the classes' owner else if (hiddenSymbols exists (_.isErroneous)) setError(tree) else if (isFullyDefined(pt)) tree setType pt //todo: eliminate else if (tp1.typeSymbol.isAnonymousClass) // todo: eliminate @@ -412,7 +420,10 @@ trait Typers { self: Analyzer => def reenterTypeParams(tparams: List[TypeDef]): List[Symbol] = for (tparam <- tparams) yield { - context.scope enter tparam.symbol + val rawInfo = tparam.symbol.rawInfo + tparam.symbol = context.scope enter tparam.symbol + // hack, because the skolems are reused. + if (inIDE) tparam.symbol.setInfo(rawInfo) tparam.symbol.deSkolemize } @@ -446,7 +457,7 @@ trait Typers { self: Analyzer => */ def labelTyper(ldef: LabelDef): Typer = if (ldef.symbol == NoSymbol) { // labeldef is part of template - val typer1 = newTyper(makeNewScope(context, ldef, context.owner)) + val typer1 = newTyper(context.makeNewScope(ldef, context.owner)) typer1.enterLabelDef(ldef) typer1 } else this @@ -597,7 +608,7 @@ trait Typers { self: Analyzer => * If all this fails, error */ protected def adapt(tree: Tree, mode: int, pt: Type): Tree = tree.tpe match { - case ct @ ConstantType(value) if ((mode & TYPEmode) == 0 && (ct <:< pt)) => // (0) + case ct @ ConstantType(value) if ((mode & TYPEmode) == 0 && (ct <:< pt) && !inIDE) => // (0) copy.Literal(tree, value) case OverloadedType(pre, alts) if ((mode & FUNmode) == 0) => // (1) inferExprAlternative(tree, pt) @@ -641,7 +652,7 @@ trait Typers { self: Analyzer => (pt <:< functionType(mt.paramTypes map (t => WildcardType), WildcardType))) { // (4.2) if (settings.debug.value) log("eta-expanding "+tree+":"+tree.tpe+" to "+pt) checkParamsConvertible(tree.pos, tree.tpe) - typed(etaExpand(tree), mode, pt) + typed(etaExpand(context.unit, tree), mode, pt) } else if (!meth.isConstructor && mt.paramTypes.isEmpty) { // (4.3) adapt(typed(Apply(tree, List()) setPos tree.pos), mode, pt) } else if (context.implicitsEnabled) { @@ -781,9 +792,6 @@ trait Typers { self: Analyzer => } } } -// Console.println("adapt "+tree+":"+tree.tpe+", mode = "+mode+", pt = "+pt) -// adapt(tree, mode, pt) -// } /** * @param tree ... @@ -820,7 +828,8 @@ trait Typers { self: Analyzer => if (member(qual, name) != NoSymbol) qual else adaptToMember(qual, name, WildcardType) - private def typePrimaryConstrBody(cbody: Tree, tparams: List[Symbol], enclTparams: List[Symbol], vparamss: List[List[ValDef]]): Tree = { + private def typePrimaryConstrBody(clazz : Symbol, cbody: Tree, tparams: List[Symbol], enclTparams: List[Symbol], vparamss: List[List[ValDef]]): Tree = { + // XXX: see about using the class's symbol.... enclTparams foreach (sym => context.scope.enter(sym)) namer.enterValueParams(context.owner, vparamss) typed(cbody) @@ -879,8 +888,8 @@ trait Typers { self: Analyzer => val outercontext = context.outer val cbody2 = - newTyper(makeNewScope(outercontext, constr, outercontext.owner)) - .typePrimaryConstrBody( + newTyper(outercontext.makeNewScope(constr, outercontext.owner)) + .typePrimaryConstrBody(clazz, cbody1, supertparams, clazz.unsafeTypeParams, vparamss map (_.map(_.duplicate))) scall match { @@ -952,7 +961,8 @@ trait Typers { self: Analyzer => //Console.println(context.owner);//DEBUG //Console.println(context.owner.unsafeTypeParams);//DEBUG //Console.println(List.fromArray(context.owner.info.closure));//DEBUG - error(parent.pos, "illegal inheritance;\n self-type "+ + // disable in IDE, don't know how else to avoid it on refresh + if (!inIDE) error(parent.pos, "illegal inheritance;\n self-type "+ selfType+" does not conform to "+parent + "'s selftype "+parent.tpe.typeOfThis) if (settings.explaintypes.value) explainTypes(selfType, parent.tpe.typeOfThis) @@ -992,10 +1002,15 @@ trait Typers { self: Analyzer => def typedClassDef(cdef: ClassDef): Tree = { // attributes(cdef) val typedMods = typedModifiers(cdef.mods) - val clazz = cdef.symbol + val clazz = cdef.symbol; + if (inIDE && clazz == NoSymbol) { + assert(true) + throw new TypeError("type signature typing failed") + } + assert(clazz != NoSymbol) reenterTypeParams(cdef.tparams) val tparams1 = List.mapConserve(cdef.tparams)(typedTypeDef) - val impl1 = newTyper(context.make(cdef.impl, clazz, newTemplateScope(cdef.impl, clazz))) + val impl1 = newTyper(context.make(cdef.impl, clazz, scopeFor(cdef.impl))) .typedTemplate(cdef.impl, parentTypes(cdef.impl)) val impl2 = addSyntheticMethods(impl1, clazz, context) copy.ClassDef(cdef, typedMods, cdef.name, tparams1, impl2) @@ -1011,7 +1026,9 @@ trait Typers { self: Analyzer => // attributes(mdef) val typedMods = typedModifiers(mdef.mods) val clazz = mdef.symbol.moduleClass - val impl1 = newTyper(context.make(mdef.impl, clazz, newTemplateScope(mdef.impl, clazz))) + if (inIDE && clazz == NoSymbol) throw new TypeError("bad signature") + assert(clazz != NoSymbol) + val impl1 = newTyper(context.make(mdef.impl, clazz, scopeFor(mdef.impl))) .typedTemplate(mdef.impl, parentTypes(mdef.impl)) val impl2 = addSyntheticMethods(impl1, clazz, context) @@ -1029,7 +1046,10 @@ trait Typers { self: Analyzer => && !stat.symbol.hasFlag(LAZY) => val vdef = copy.ValDef(stat, mods | PRIVATE | LOCAL, nme.getterToLocal(name), tpt, rhs) val value = vdef.symbol - val getter = if ((mods hasFlag DEFERRED) || inIDE) value else value.getter(value.owner) + val getter = if ((mods hasFlag DEFERRED)) value else value.getter(value.owner) + // XXX: + if (inIDE && getter == NoSymbol) + return Nil assert(getter != NoSymbol, stat) if (getter hasFlag OVERLOADED) error(getter.pos, getter+" is defined twice") @@ -1080,7 +1100,7 @@ trait Typers { self: Analyzer => protected def enterSym(txt: Context, tree: Tree): Context = if (txt eq context) namer.enterSym(tree) - else new Namer(txt).enterSym(tree) + else newNamer(txt).enterSym(tree) /** * @param templ ... @@ -1090,7 +1110,7 @@ trait Typers { self: Analyzer => def typedTemplate(templ: Template, parents1: List[Tree]): Template = { val clazz = context.owner if (templ.symbol == NoSymbol) - templ setSymbol clazz.newLocalDummy(templ.pos) + templ setSymbol newLocalDummy(clazz, templ.pos) val self1 = templ.self match { case vd @ ValDef(mods, name, tpt, EmptyTree) => val tpt1 = checkNoEscaping.privates(clazz.thisSym, typedType(tpt)) @@ -1102,9 +1122,12 @@ trait Typers { self: Analyzer => intersectionType(clazz.info.parents, clazz.owner) else clazz.typeOfThis // the following is necessary for templates generated later - enterSyms(context.outer.make(templ, clazz, clazz.info.decls), templ.body) + assert(clazz.info.decls != EmptyScope) + // XXX: let namer in typeSig be definitive, duplicate to ensure typer context doesn't stick. + val templBody = if (inIDE) templ.body.map(_.duplicate : Tree) else templ.body + enterSyms(context.outer.make(templ, clazz, clazz.info.decls), templBody) validateParentClasses(parents1, selfType) - if (!phase.erasedTypes) + if (!phase.erasedTypes && !clazz.info.resultType.isError) // @S: prevent crash for duplicated type members checkFinitary(clazz.info.resultType.asInstanceOf[ClassInfoType]) val body = if (phase.id <= currentRun.typerPhase.id && !reporter.hasErrors) @@ -1131,7 +1154,10 @@ trait Typers { self: Analyzer => val typer1 = constrTyperIf(sym.hasFlag(PARAM) && sym.owner.isConstructor) val typedMods = typedModifiers(vdef.mods) - val tpt1 = checkNoEscaping.privates(sym, typer1.typedType(vdef.tpt)) + var tpt1 = checkNoEscaping.privates(sym, typer1.typedType({ + if (inIDE) vdef.tpt.duplicate // avoids wrong context sticking + else vdef.tpt + })) checkNonCyclic(vdef, tpt1) val rhs1 = if (vdef.rhs.isEmpty) { @@ -1139,7 +1165,9 @@ trait Typers { self: Analyzer => error(vdef.pos, "local variables must be initialized") vdef.rhs } else { - newTyper(typer1.context.make(vdef, sym)).transformedOrTyped(vdef.rhs, tpt1.tpe) + //assert(vdef.rhs.tpe == null) + val rhs = if (inIDE && vdef.rhs.tpe != null) vdef.rhs.duplicate else vdef.rhs + newTyper(typer1.context.make(vdef, sym)).transformedOrTyped(rhs, tpt1.tpe) } copy.ValDef(vdef, typedMods, vdef.name, tpt1, checkDead(rhs1)) setType NoType } @@ -1155,11 +1183,14 @@ trait Typers { self: Analyzer => def decompose(call: Tree): (Tree, List[Tree]) = call match { case Apply(fn, args) => val (superConstr, args1) = decompose(fn) - val formals = fn.tpe.paramTypes + val formals = (if (fn.tpe == null && inIDE) ErrorType else fn.tpe).paramTypes val args2 = if (formals.isEmpty || formals.last.typeSymbol != RepeatedParamClass) args else args.take(formals.length - 1) ::: List(EmptyTree) - if (args2.length != formals.length) - assert(false, "mismatch " + clazz + " " + formals + " " + args2);//debug + if (args2.length != formals.length) { + if (!inIDE) + assert(false, "mismatch " + clazz + " " + formals + " " + args2);//debug + else error(call.pos, "XXX: mismatch " + clazz + " " + formals + " " + args2) + } (superConstr, args1 ::: args2) case Block(stats, expr) if !stats.isEmpty => decompose(stats.last) @@ -1198,6 +1229,12 @@ trait Typers { self: Analyzer => } () } + } else if (inIDE) { // XXX: maybe add later + Console.println("" + superClazz + ":" + + superClazz.info.decls.toList.filter(_.hasFlag(PARAMACCESSOR))) + error(rhs.pos, "mismatch: " + superParamAccessors + + ";" + rhs + ";" + superClazz.info.decls)//debug + return } } } @@ -1215,6 +1252,7 @@ trait Typers { self: Analyzer => */ def typedDefDef(ddef: DefDef): DefDef = { val meth = ddef.symbol + if (inIDE && meth == NoSymbol) throw new TypeError("bad signature") reenterTypeParams(ddef.tparams) reenterValueParams(ddef.vparamss) val tparams1 = List.mapConserve(ddef.tparams)(typedTypeDef) @@ -1240,7 +1278,8 @@ trait Typers { self: Analyzer => error(ddef.pos, "constructor definition not allowed here") typed(ddef.rhs) } else { - transformedOrTyped(ddef.rhs, tpt1.tpe) + if (inIDE && ddef.rhs == EmptyTree) EmptyTree + else transformedOrTyped(ddef.rhs, tpt1.tpe) } if (meth.isPrimaryConstructor && meth.isClassConstructor && phase.id <= currentRun.typerPhase.id && !reporter.hasErrors) @@ -1310,8 +1349,7 @@ trait Typers { self: Analyzer => if (stat.isDef) context.scope.enter(stat.symbol) } } - if (!inIDE) - namer.enterSyms(block.stats) + namer.enterSyms(block.stats) block.stats foreach enterLabelDef val stats1 = typedStats(block.stats, context.owner) val expr1 = typed(block.expr, mode & ~(FUNmode | QUALmode), pt) @@ -1359,7 +1397,7 @@ trait Typers { self: Analyzer => def typedCases(tree: Tree, cases: List[CaseDef], pattp0: Type, pt: Type): List[CaseDef] = { var pattp = pattp0 List.mapConserve(cases) ( cdef => - newTyper(makeNewScope(context, cdef, context.owner)).typedCase(cdef, pattp, pt)) + newTyper(context.makeNewScope(cdef, context.owner)).typedCase(cdef, pattp, pt)) /* not yet! cdef.pat match { case Literal(Constant(null)) => @@ -1410,8 +1448,6 @@ trait Typers { self: Analyzer => vparam.symbol } // XXX: here to for IDE hooks. - if (inIDE) // HACK to process arguments types in IDE. - typedFunctionIDE(fun, context); val vparams = List.mapConserve(fun.vparams)(typedValDef) // for (val vparam <- vparams) { // checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); () @@ -1430,8 +1466,7 @@ trait Typers { self: Analyzer => } def typedRefinement(stats: List[Tree]): List[Tree] = { - if (!inIDE) - namer.enterSyms(stats) + namer.enterSyms(stats) val stats1 = typedStats(stats, NoSymbol) for (stat <- stats1 if stat.isDef) { val member = stat.symbol @@ -1457,14 +1492,21 @@ trait Typers { self: Analyzer => context = context.makeNewImport(imp0) imp0.symbol.initialize } - EmptyTree + if ((imp0 ne null) && inIDE) { + imp0.symbol.info match { + case ImportType(exr) => + imp0.expr.tpe = exr.tpe + case _ => + } + imp0 + } else EmptyTree case _ => val localTyper = if (inBlock || (stat.isDef && !stat.isInstanceOf[LabelDef])) this else newTyper(context.make(stat, exprOwner)) val result = checkDead(localTyper.typed(stat)) if (treeInfo.isSelfOrSuperConstrCall(result)) { context.inConstructorSuffix = true - if (treeInfo.isSelfConstrCall(result) && result.symbol.pos.offset.get(0) >= exprOwner.enclMethod.pos.offset.get(0)) + if (!inIDE && treeInfo.isSelfConstrCall(result) && result.symbol.pos.offset.get(0) >= exprOwner.enclMethod.pos.offset.get(0)) error(stat.pos, "called constructor's definition must precede calling constructor's definition") } result @@ -1482,7 +1524,7 @@ trait Typers { self: Analyzer => while ((e1 ne null) && e1.owner == scope) { if (!accesses(e.sym, e1.sym) && !accesses(e1.sym, e.sym) && (e.sym.isType || inBlock || (e.sym.tpe matches e1.sym.tpe))) - if (!e.sym.isErroneous && !e1.sym.isErroneous) + if (!e.sym.isErroneous && !e1.sym.isErroneous && !inIDE) error(e.sym.pos, e1.sym+" is defined twice"+ {if(!settings.debug.value) "" else " in "+unit.toString}); e1 = scope.lookupNextEntry(e1); @@ -1593,7 +1635,7 @@ trait Typers { self: Analyzer => } } - if (fun.symbol == List_apply && args.isEmpty) { + if (!inIDE && fun.symbol == List_apply && args.isEmpty) { atPos(tree.pos) { gen.mkNil setType restpe } } else constfold(copy.Apply(tree, fun, args2).setType(ifPatternSkipFormals(restpe))) @@ -1618,8 +1660,9 @@ trait Typers { self: Analyzer => else { if (settings.debug.value) log("infer method inst "+fun+", tparams = "+tparams+", args = "+args2.map(_.tpe)+", pt = "+pt+", lobounds = "+tparams.map(_.tpe.bounds.lo)+", parambounds = "+tparams.map(_.info));//debug val undetparams = inferMethodInstance(fun, tparams, args2, pt) - val result = doTypedApply(tree, fun, args2, mode, pt) - context.undetparams = undetparams + val result = if (!inIDE) doTypedApply(tree, fun, args2, mode, pt) + else doTypedApply(tree.duplicate,fun.duplicate,args2.map(_.duplicate),mode,pt) + context.undetparams = undetparams result } } @@ -1637,6 +1680,7 @@ trait Typers { self: Analyzer => assert(unapp.exists, tree) val unappType = otpe.memberType(unapp) val argDummyType = pt // was unappArg + // @S: do we need to memoize this? val argDummy = context.owner.newValue(fun.pos, nme.SELECTOR_DUMMY) .setFlag(SYNTHETIC) .setInfo(argDummyType) @@ -1659,7 +1703,7 @@ trait Typers { self: Analyzer => val (unappFormal, freeVars) = freshArgType(unappType) val context1 = context.makeNewScope(context.tree, context.owner) freeVars foreach(sym => context1.scope.enter(sym)) - val typer1 = new Typer(context1) + val typer1 = newTyper(context1) arg.tpe = typer1.infer.inferTypedPattern(tree.pos, unappFormal, arg.tpe) //todo: replace arg with arg.asInstanceOf[inferTypedPattern(unappFormal, arg.tpe)] instead. argDummy.setInfo(arg.tpe) // bq: this line fixed #1281. w.r.t. comment ^^^, maybe good enough? @@ -1833,10 +1877,10 @@ trait Typers { self: Analyzer => val typeParams: List[Symbol] = rawSyms map { sym => val name = if (sym.isType) sym.name else newTypeName(sym.name+".type") val bound = existentialBound(sym) - val quantified: Symbol = sym.owner.newAbstractType(sym.pos, name) - quantified setFlag EXISTENTIAL setInfo bound.cloneInfo(quantified) + val quantified: Symbol = recycle(sym.owner.newAbstractType(sym.pos, name)) + trackSetInfo(quantified setFlag EXISTENTIAL)(bound.cloneInfo(quantified)) } - val typeParamTypes = typeParams map (_.tpe) + val typeParamTypes = typeParams map (_.tpe) // don't trackSetInfo here, since type already set! for (tparam <- typeParams) tparam.setInfo(tparam.info.subst(rawSyms, typeParamTypes)) (typeParams, tp.subst(rawSyms, typeParamTypes)) } @@ -1916,10 +1960,9 @@ trait Typers { self: Analyzer => case t => t } - val local = sym.owner.newAbstractType( - sym.pos, unit.fresh.newName(sym.name.toString)) - .setFlag(sym.flags) - .setInfo(bound) + val local = trackSetInfo(recycle(sym.owner.newAbstractType( + sym.pos, unit.fresh.newName(sym.pos, sym.name.toString)) + .setFlag(sym.flags)))(bound) localInstances += (inst -> local) addLocals(bound) } @@ -2015,8 +2058,10 @@ trait Typers { self: Analyzer => else context.owner.newAbstractType(tree.pos, name) setInfo mkTypeBounds(AllClass.tpe, AnyClass.tpe) - if (vble.name == nme.WILDCARD.toTypeName) context.scope.enter(vble) - else namer.enterInScope(vble) + val rawInfo = vble.rawInfo + vble = if (vble.name == nme.WILDCARD.toTypeName) context.scope.enter(vble) + else namer.enterInScope(vble) + trackSetInfo(vble)(rawInfo) // vble could have been recycled, detect changes in type tree setSymbol vble setType vble.tpe } else { if (vble == NoSymbol) @@ -2031,10 +2076,10 @@ trait Typers { self: Analyzer => */ if ((mode & ALTmode) != 0) error(tree.pos, "illegal variable in pattern alternative") - namer.enterInScope(vble) + vble = namer.enterInScope(vble) } val body1 = typed(body, mode, pt) - vble.setInfo( + trackSetInfo(vble)( if (treeInfo.isSequenceValued(body)) seqType(body1.tpe) else body1.tpe) copy.Bind(tree, name, body1) setSymbol vble setType body1.tpe // buraq, was: pt @@ -2100,12 +2145,17 @@ trait Typers { self: Analyzer => errorTree(tree, "return outside method definition") } else { val DefDef(_, _, _, _, restpt, _) = enclMethod.tree - if (restpt.tpe eq null) { - errorTree(tree, "method " + enclMethod.owner + + var restpt0 = restpt + if (inIDE && (restpt0.tpe eq null)) { + assert(true) + restpt0 = typed(restpt0, TYPEmode, WildcardType) + } + if (restpt0.tpe eq null) { + errorTree(tree, "" + enclMethod.owner + " has return statement; needs result type") } else { context.enclMethod.returnsSeen = true - val expr1: Tree = typed(expr, restpt.tpe) + val expr1: Tree = typed(expr, restpt0.tpe) copy.Return(tree, checkDead(expr1)) setSymbol enclMethod.owner setType AllClass.tpe } } @@ -2372,7 +2422,7 @@ trait Typers { self: Analyzer => if ((mode & SUPERCONSTRmode) != 0) clazz.info.parents.head else intersectionType(clazz.info.parents) else { - val ps = clazz.info.parents filter (p => p.typeSymbol.name == mix) + val ps = clazz.info.parents filter (p => compare(p.typeSymbol, mix)) if (ps.isEmpty) { if (settings.debug.value) Console.println(clazz.info.parents map (_.typeSymbol.name))//debug @@ -2429,7 +2479,8 @@ trait Typers { self: Analyzer => } tree.symbol } else { - member(qual, name) + if (!inIDE) member(qual, name) + else verifyAndPrioritize(_ filter (alt => context.isAccessible(alt, qual.tpe, qual.isInstanceOf[Super])))(pt)(member(qual,name)) } if (sym == NoSymbol && name != nme.CONSTRUCTOR && (mode & EXPRmode) != 0) { val qual1 = adaptToName(qual, name) @@ -2510,6 +2561,7 @@ trait Typers { self: Analyzer => ((mode & PATTERNmode | FUNmode) != (PATTERNmode | FUNmode) || !sym.isSourceMethod || sym.isCaseFactory) + if (defSym == NoSymbol) { var defEntry: ScopeEntry = null // the scope entry of defSym, if defined in a local scope @@ -2520,22 +2572,23 @@ trait Typers { self: Analyzer => while (defSym == NoSymbol && cx != NoContext) { pre = cx.enclClass.prefix - defEntry = cx.scope.lookupEntry(name) - if (inIDE && (defEntry ne null) && defEntry.sym.exists) { - val sym = defEntry.sym - val namePos : Position = tree.pos - val symPos : Position = sym.pos - if (namePos.offset.get < symPos.offset.get) defEntry = null - } + defEntry = if (!inIDE) cx.scope.lookupEntry(name) + else verifyAndPrioritize(sym => sym)(pt)(cx.scope.lookupEntry(name)) if ((defEntry ne null) && qualifies(defEntry.sym)) { defSym = defEntry.sym - } else if (inIDE) { - if (cx.outer == cx.enclClass) { - cx = cx.enclClass - defSym = pre.member(name) filter ( - sym => sym.exists && context.isAccessible(sym, pre, false)) + } else if (inIDE) { // IDE: cannot rely on linked scopes. + if (cx.outer.owner eq cx.enclClass.owner) { + //cx = cx.outer + defSym = + verifyAndPrioritize{ // enables filtering of auto completion + _ filter (sym => qualifies(sym) && context.isAccessible(sym, pre, false)) + }(pt)(pre.member(name) filter ( + sym => qualifies(sym) && context.isAccessible(sym, pre, false))) } - if (defSym == NoSymbol) cx = cx.outer + val oldScope = cx.scope + cx = cx.outer + while (cx.scope == oldScope && !(cx.outer.owner eq cx.enclClass.owner)) // can't skip + cx = cx.outer } else { cx = cx.enclClass defSym = pre.member(name) filter ( @@ -2562,7 +2615,7 @@ trait Typers { self: Analyzer => // imported symbols take precedence over package-owned symbols in different // compilation units. Defined symbols take precedence over errenous imports. if (defSym.owner.isPackageClass && - (!currentRun.compiles(defSym) || + ((!inIDE && !currentRun.compiles(defSym)) || (context.unit ne null) && defSym.sourceFile != context.unit.source.file)) defSym = NoSymbol else if (impSym.isError) @@ -2614,9 +2667,14 @@ trait Typers { self: Analyzer => } } if (defSym.owner.isPackageClass) pre = defSym.owner.thisType - if (defSym.isThisSym) typed1(This(defSym.owner) setPos tree.pos, mode, pt) + if (defSym.isThisSym) { + val tree1 = typed1(This(defSym.owner) setPos tree.pos, mode, pt) + if (inIDE) { + Ident(defSym.name) setType tree1.tpe setSymbol defSym setPos tree.pos + } else tree1 + } else { - val tree1 = if (qual == EmptyTree) tree + var tree1 = if (qual == EmptyTree) tree else atPos(tree.pos)(Select(qual, name)) // atPos necessary because qualifier might come from startContext stabilize(checkAccessible(tree1, defSym, pre, qual), pre, mode, pt) @@ -2627,7 +2685,7 @@ trait Typers { self: Analyzer => val parents1 = List.mapConserve(templ.parents)(typedType) if (parents1 exists (_.tpe.isError)) tree setType ErrorType else { - val decls = newDecls(tree.asInstanceOf[CompoundTypeTree]) + val decls = scopeFor(tree) val self = refinedType(parents1 map (_.tpe), context.enclClass.owner, decls) newTyper(context.make(templ, self.typeSymbol, decls)).typedRefinement(templ.body) tree setType self @@ -2636,6 +2694,8 @@ trait Typers { self: Analyzer => def typedAppliedTypeTree(tpt: Tree, args: List[Tree]) = { val tpt1 = typed1(tpt, mode | FUNmode | TAPPmode, WildcardType) + // @S: shouldn't be necessary now, fixed a problem with SimpleTypeProxy not relaying typeParams calls. + // if (inIDE) tpt1.symbol.info // @S: seems like typeParams call doesn't force completion of symbol type in IDE. val tparams = tpt1.symbol.typeParams if (tpt1.tpe.isError) { @@ -2654,7 +2714,7 @@ trait Typers { self: Analyzer => // note: can't use args1 in selector, because Bind's got replaced case Bind(_, _) => if (arg.symbol.isAbstractType) - arg.symbol setInfo + arg.symbol setInfo // XXX, feedback. don't trackSymInfo here! TypeBounds(lub(List(arg.symbol.info.bounds.lo, tparam.info.bounds.lo)), glb(List(arg.symbol.info.bounds.hi, tparam.info.bounds.hi))) case _ => @@ -2675,24 +2735,25 @@ trait Typers { self: Analyzer => //if (settings.debug.value && tree.isDef) log("typing definition of "+sym);//DEBUG tree match { case PackageDef(name, stats) => + assert(sym.moduleClass ne NoSymbol) val stats1 = newTyper(context.make(tree, sym.moduleClass, sym.info.decls)) .typedStats(stats, NoSymbol) copy.PackageDef(tree, name, stats1) setType NoType case tree @ ClassDef(_, _, _, _) => - newTyper(makeNewScope(context, tree, sym)).typedClassDef(tree) + newTyper(context.makeNewScope(tree, sym)).typedClassDef(tree) case tree @ ModuleDef(_, _, _) => - newTyper(makeNewScope(context, tree, sym.moduleClass)).typedModuleDef(tree) + newTyper(context.makeNewScope(tree, sym.moduleClass)).typedModuleDef(tree) case vdef @ ValDef(_, _, _, _) => typedValDef(vdef) case ddef @ DefDef(_, _, _, _, _, _) => - newTyper(makeNewScope(context, tree, sym)).typedDefDef(ddef) + newTyper(context.makeNewScope(tree, sym)).typedDefDef(ddef) case tdef @ TypeDef(_, _, _, _) => - newTyper(makeNewScope(context, tree, sym)).typedTypeDef(tdef) + newTyper(context.makeNewScope(tree, sym)).typedTypeDef(tdef) case ldef @ LabelDef(_, _, _) => labelTyper(ldef).typedLabelDef(ldef) @@ -2712,7 +2773,7 @@ trait Typers { self: Analyzer => typedAnnotated(annot, typed(arg, mode, pt)) case tree @ Block(_, _) => - newTyper(makeNewScope(context, tree, context.owner)) + newTyper(context.makeNewScope(tree, context.owner)) .typedBlock(tree, mode, pt) case Sequence(elems) => @@ -2753,9 +2814,9 @@ trait Typers { self: Analyzer => case tree @ Function(_, _) => if (tree.symbol == NoSymbol) - tree.symbol = context.owner.newValue(tree.pos, nme.ANON_FUN_NAME) - .setFlag(SYNTHETIC).setInfo(NoType) - newTyper(makeNewScope(context, tree, tree.symbol)).typedFunction(tree, mode, pt) + tree.symbol = recycle(context.owner.newValue(tree.pos, nme.ANON_FUN_NAME) + .setFlag(SYNTHETIC).setInfo(NoType)) + newTyper(context.makeNewScope(tree, tree.symbol)).typedFunction(tree, mode, pt) case Assign(lhs, rhs) => typedAssign(lhs, rhs) @@ -2763,11 +2824,12 @@ trait Typers { self: Analyzer => case If(cond, thenp, elsep) => typedIf(cond, thenp, elsep) - case Match(selector, cases) => + case tree @ Match(selector, cases) => if (selector == EmptyTree) { val arity = if (isFunctionType(pt)) pt.normalize.typeArgs.length - 1 else 1 val params = for (i <- List.range(0, arity)) yield - ValDef(Modifiers(PARAM | SYNTHETIC), unit.fresh.newName("x$"), TypeTree(), EmptyTree) + ValDef(Modifiers(PARAM | SYNTHETIC), + unit.fresh.newName(tree.pos, "x" + i + "$"), TypeTree(), EmptyTree) val ids = for (p <- params) yield Ident(p.name) val selector1 = atPos(tree.pos) { if (arity == 1) ids.head else gen.mkTuple(ids) } val body = copy.Match(tree, selector1, cases) @@ -2920,14 +2982,14 @@ trait Typers { self: Analyzer => copy.TypeBoundsTree(tree, lo1, hi1) setType mkTypeBounds(lo1.tpe, hi1.tpe) case etpt @ ExistentialTypeTree(_, _) => - newTyper(makeNewScope(context, tree, context.owner)).typedExistentialTypeTree(etpt) + newTyper(context.makeNewScope(tree, context.owner)).typedExistentialTypeTree(etpt) case TypeTree() => // we should get here only when something before failed // and we try again (@see tryTypedApply). In that case we can assign // whatever type to tree; we just have to survive until a real error message is issued. tree setType AnyClass.tpe - + case EmptyTree if inIDE => EmptyTree // just tolerate it in the IDE. case _ => throw new Error("unexpected tree: " + tree.getClass + "\n" + tree)//debug } diff --git a/src/compiler/scala/tools/nsc/util/CharArrayReader.scala b/src/compiler/scala/tools/nsc/util/CharArrayReader.scala index ba67c6e3ea..4f99ecc221 100644 --- a/src/compiler/scala/tools/nsc/util/CharArrayReader.scala +++ b/src/compiler/scala/tools/nsc/util/CharArrayReader.scala @@ -8,10 +8,10 @@ package scala.tools.nsc.util import scala.tools.nsc.util.SourceFile.{LF, FF, CR, SU} -class CharArrayReader(buf: Array[Char], start: Int, /* startline: Int, startcol: Int, */ - decodeUni: Boolean, error: String => Unit) extends Iterator[Char] { +class CharArrayReader(buf: RandomAccessSeq[Char], start: Int, /* startline: int, startcol: int, */ + decodeUni: Boolean, error: String => unit) extends Iterator[Char] { - def this(buf: Array[Char], decodeUni: Boolean, error: String => Unit) = + def this(buf: RandomAccessSeq[Char], decodeUni: Boolean, error: String => unit) = this(buf, 0, /* 1, 1, */ decodeUni, error) /** layout constant @@ -46,17 +46,21 @@ class CharArrayReader(buf: Array[Char], start: Int, /* startline: Int, startcol: //nextcol = 1 } - def hasNext: Boolean = bp < buf.length + def hasNext: Boolean = if (bp < buf.length) true + else { + assert(true) + false + } def last: Char = if (bp > start + 2) buf(bp - 2) else ' ' // XML literals def next: Char = { //cline = nextline //ccol = nextcol + val buf = this.buf.asInstanceOf[runtime.BoxedCharArray].value if(!hasNext) { - // there is an endless stream of SU's at the end ch = SU - return SU + return SU // there is an endless stream of SU's at the end } oldBp = bp oldCh = ch diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index 6ac66ae968..cb67f55c60 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -81,7 +81,9 @@ class ClassPath(onlyPresentation: Boolean) { // assert(location != null, "cannot find classpath location") // assert(location.getFile() != null, "cannot find classpath location " + " " + location + " " + location.getClass()) def source: Source - override def toString() = location.toString() + override def toString() = + (if (location == null) "<none>" else location.toString) + + (if (source == null) "" else " source=" + source) } class Output(location0: AbstractFile, val sourceFile: AbstractFile) extends Entry(location0) { @@ -100,7 +102,7 @@ class ClassPath(onlyPresentation: Boolean) { if (entries.isEmpty) new Context(Nil) else { val ret = find0(entries.tail) - val head = entries.head + val head = entries.head; val name0 = name + (if (!isDir) ".class" else "") val clazz = if (head.location eq null) null else head.location.lookupPath(name0, isDir) @@ -124,7 +126,9 @@ class ClassPath(onlyPresentation: Boolean) { } try { //Console.err.println("this=" + this + "\nclazz=" + clazz + "\nsource0=" + source0 + "\n") - new Context(entry :: ret.entries) + + if (!isDir) new Context(entry :: Nil) + else new Context(entry :: ret.entries) } catch { case e: Error => throw e @@ -192,7 +196,7 @@ class ClassPath(onlyPresentation: Boolean) { val sourcePath0 = sourcePath if (sourcePath0 ne null) { if (!sourcePath0.isDirectory) { - Console.err.println(""+sourcePath0 + " cannot be a directory") + Console.err.println(""+sourcePath0 + " should be a directory") assert(false) } } @@ -248,15 +252,35 @@ class ClassPath(onlyPresentation: Boolean) { } /** - * @param classes ... - * @param sources ... + * @param classes where the class files come from and are written to + * @param sources where the source files come from + */ + def output(classes : String, sources : String) = { + assert(classes ne null) + assert(sources ne null) + val location = AbstractFile.getDirectory(classes) + val sources0 = AbstractFile.getDirectory(sources) + class Output0 extends Output(location, sources0) + entries += new Output0() + } + /** + * @param classes where the class files come from + * @param sources optional source file attachment, otherwise null */ def library(classes: String, sources: String) { assert(classes ne null) val location = AbstractFile.getDirectory(classes) - val sourceFile0 = + var sourceFile0 = if (sources ne null) AbstractFile.getDirectory(sources) else null + if (sourceFile0 ne null) { + val file00 = sourceFile0.lookupPath("src", true) + if ((file00 ne null) && file00.isDirectory) { + assert(true) + sourceFile0 = file00 + } + } + class Library0 extends Library(location) { override def sourceFile = sourceFile0 } diff --git a/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala b/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala index d3e79969af..a4c257a996 100644 --- a/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala +++ b/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala @@ -8,7 +8,13 @@ package scala.tools.nsc.util import scala.collection.mutable.HashMap -class FreshNameCreator { +trait FreshNameCreator { + def newName(prefix : String) : String + def newName() : String + def newName(pos : util.Position, prefix : String) : String +} +object FreshNameCreator { + class Default extends FreshNameCreator { protected var counter = 0 protected val counters = new HashMap[String, Int] @@ -26,9 +32,11 @@ class FreshNameCreator { counters.update(prefix, count) prefix + count } + def newName(pos : util.Position, prefix : String) = newName(prefix) def newName(): String = { counter = counter + 1 "$" + counter + "$" } } +}
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/util/NewCharArrayReader.scala b/src/compiler/scala/tools/nsc/util/NewCharArrayReader.scala new file mode 100644 index 0000000000..3f889587ed --- /dev/null +++ b/src/compiler/scala/tools/nsc/util/NewCharArrayReader.scala @@ -0,0 +1,74 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2006 LAMP/EPFL + * @author Martin Odersky + */ +// $Id: CharArrayReader.scala 11142 2007-05-22 10:23:00Z mcdirmid $ + +package scala.tools.nsc.util + +import scala.tools.nsc.util.SourceFile.{LF, FF, CR, SU} + +class NewCharArrayReader(val buf: RandomAccessSeq[Char], // should not change + decodeUni: Boolean, error: (Int,String) => unit) extends Iterator[Char] { + private var idx : Int = 0 + private var isUnicode0 = false + def isUnicode = isUnicode0 + + private val bufLength = buf.length + def seek(offset : Int) = { + assert(offset <= bufLength) + idx = offset + } + def offset = idx + def withOffset = new Iterator[(Int,Char)] { + def hasNext = NewCharArrayReader.this.hasNext + def next = (offset, NewCharArrayReader.this.next) + } + override def hasNext = { // could be padded + if (idx == bufLength - 1) buf(idx) != SU + else idx < bufLength + } + override def next : Char = { + isUnicode0 = false + if (!hasNext) return SU + var ch = buf(idx) + idx = idx + 1 + ch match { + case CR if buf.safeIs(idx + 1, LF) => + idx += 1; ch = LF + case LF | FF => + case '\\' => + def evenSlashPrefix: Boolean = { + var p = idx - 2 + while (p >= 0 && buf(p) == '\\') p = p - 1; + (idx - p) % 2 == 0 + } + def udigit: Int = { + val d = digit2int(buf(idx), 16) + if (d >= 0) { idx = idx + 1 } + else if (error != null) error(idx, "error in unicode escape"); + d + } + if (idx < bufLength && buf(idx) == 'u' && decodeUni && evenSlashPrefix) { + do { + idx = idx + 1; // nextcol = nextcol + 1; + } while (idx < bufLength && buf(idx) == 'u'); + val code = udigit << 12 | udigit << 8 | udigit << 4 | udigit + isUnicode0 = true + ch = code.asInstanceOf[Char] + } + case _ => + } + ch + } + def digit2int(ch: Char, base: Int): Int = { + if ('0' <= ch && ch <= '9' && ch < '0' + base) + ch - '0' + else if ('A' <= ch && ch < 'A' + base - 10) + ch - 'A' + 10 + else if ('a' <= ch && ch < 'a' + base - 10) + ch - 'a' + 10 + else + -1 + } +} diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala index 144809ff6a..ae4cd55086 100644 --- a/src/compiler/scala/tools/nsc/util/Position.scala +++ b/src/compiler/scala/tools/nsc/util/Position.scala @@ -8,14 +8,19 @@ // $Id$ package scala.tools.nsc.util - +object Position { + // a static field + private val tabInc = 8 +} trait Position { + import Position.tabInc def offset : Option[Int] = None - private val tabInc = 8 + def source : Option[SourceFile] = None + def line : Option[Int] = - if (source.isEmpty || offset.isEmpty) None else Some(source.get.offsetToLine(offset.get) + 1) + if (offset.isEmpty || source.isEmpty) None else Some(source.get.offsetToLine(offset.get) + 1) def column : Option[Int] = { - if (source.isEmpty || offset.isEmpty) return None + if (offset.isEmpty || source.isEmpty) return None var column = 1 // find beginning offset for line val line = source.get.offsetToLine(offset.get) @@ -23,33 +28,39 @@ trait Position { var continue = true while (continue) { if (coffset == offset.get(-1)) continue = false - else if (source.get.content(coffset) == '\t') column = ((column - 1) / tabInc * tabInc) + tabInc + 1 + else if (source.get.asInstanceOf[BatchSourceFile].content(coffset) == '\t') + column = ((column - 1) / tabInc * tabInc) + tabInc + 1 else column = column + 1 coffset = coffset + 1 } Some(column) } - def source : Option[SourceFile] = None - def lineContent: String = - if (!line.isEmpty && !source.isEmpty) source.get.lineToString(line.get - 1) + def lineContent: String = { + val line = this.line + if (!line.isEmpty) source.get.lineToString(line.get - 1) else "NO_LINE" + } + + /** Map this position to a position in an original source * file. If the SourceFile is a normal SourceFile, simply * return this. */ - def inUltimateSource = if (!source.isEmpty) source.get.positionInUltimateSource(this) - else this + def inUltimateSource(source : SourceFile) = + if (source == null) this else source.positionInUltimateSource(this) def dbgString = { (if (source.isEmpty) "" else "source-" + source.get.path) + (if (line.isEmpty) "" else "line-" + line.get) + - (if (offset.isEmpty || source.isEmpty) "" - else if (offset.get >= source.get.content.length) "out-of-bounds-" + offset.get + (if (offset.isEmpty) "" + else if (offset.get >= source.get.length) "out-of-bounds-" + offset.get else { val ret = "offset=" + offset.get; var add = ""; - while (offset.get + add.length < source.get.content.length && + /* + while (offset.get + add.length < source.get.length && add.length < 10) add = add + source.get.content(offset.get + add.length()); + */ ret + " c[0..9]=\"" + add + "\""; }) } @@ -59,14 +70,14 @@ trait Position { object NoPosition extends Position; case class FakePos(msg : String) extends Position; -case class LinePosition(line0 : Int, override val source : Option[SourceFile]) extends Position { - def this(line0 : Int) = this(line0, None) +case class LinePosition(source0 : SourceFile, line0 : Int) extends Position { assert(line0 >= 1) override def offset = None override def column = None override def line = Some(line0) + override def source = Some(source0) } case class OffsetPosition(source0 : SourceFile, offset0 : Int) extends Position { override def source = Some(source0) override def offset = Some(offset0) -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/util/SourceFile.scala b/src/compiler/scala/tools/nsc/util/SourceFile.scala index f810fe96f0..4f4694b6b7 100644 --- a/src/compiler/scala/tools/nsc/util/SourceFile.scala +++ b/src/compiler/scala/tools/nsc/util/SourceFile.scala @@ -6,72 +6,115 @@ // $Id$ package scala.tools.nsc.util - import scala.tools.nsc.io.{AbstractFile, VirtualFile} -/** Uses positions that are offsets rather than line/column pairs. - * - */ object SourceFile { val LF: Char = 0x0A val FF: Char = 0x0C val CR: Char = 0x0D val SU: Char = 0x1A - def isLineBreak(c: Char) = c == LF || c == FF || c == CR || c == SU + def isLineBreak(c: Int) = c match { + case LF|FF|CR|SU => true + case _ => false + } } - -/** Uses positions that are offsets rather than line/column pairs. - * - * @author Sean McDirmid - * @version 1.0 - */ -class SourceFile(val file: AbstractFile, _content: Array[Char]) { +/** abstract base class of a source file used in the compiler */ +abstract class SourceFile { import SourceFile._ + //def content : Seq[Char] // normalized, must end in SU + def file : AbstractFile + def isLineBreak(idx : Int) : Boolean + def length : Int + def position(offset: Int) : Position = { + assert(offset < length) + new OffsetPosition(this, offset) + } + def position(line: Int, column: Int) : Position = new OffsetPosition(this, lineToOffset(line) + column) + def offsetToLine(offset: Int): Int + def lineToOffset(index : Int): Int + /** Map a position to a position in the underlying source file. + * For regular source files, simply return the argument. + */ + def positionInUltimateSource(position: Position) = position + override def toString(): String = file.name /* + ":" + content.length */ + def dbg(offset: Int) = (new OffsetPosition(this, offset)).dbgString + def path = file.path - def this(_file: AbstractFile) = this(_file, _file.toCharArray) + def beginsWith(offset: Int, text: String): Boolean + def skipWhitespace(offset: Int): Int + def lineToString(index: Int): String + + def identifier(pos : Position, compiler : scala.tools.nsc.Global) : Option[String] = None +} +/** a file whose contents do not change over time */ +class BatchSourceFile(val file : AbstractFile, _content : Array[Char]) extends SourceFile { + import SourceFile._ + def this(_file: AbstractFile) = this(_file, _file.toCharArray) def this(sourceName: String, content: Array[Char]) = this(new VirtualFile(sourceName), content) + override def equals(that : Any) = that match { + case that : BatchSourceFile => file == that.file + case _ => false + } + override def hashCode = file.hashCode + + val content = _content // don't sweat it... + override val length = content.length + override def identifier(pos : Position, compiler : scala.tools.nsc.Global) = pos match { + case OffsetPosition(source,offset) if source == this => + import java.lang.Character + var i = offset + 1 + while (i < content.length && + (compiler.syntaxAnalyzer.isOperatorPart(content(i)) || + compiler.syntaxAnalyzer.isIdentifierPart(content(i)))) i = i + 1 + + assert(i > offset) + Some(new String(content, offset, i - offset)) + case _ => super.identifier(pos, compiler) + } - val content = normalize(_content) - - def getContent() = content - def getFile() = file def isLineBreak(idx: Int) = - if (!SourceFile.isLineBreak(content(idx))) false - else if (content(idx) == CR && idx + 1 < content.length && content(idx + 1) == LF) false + if (idx >= content.length) false + else if (!SourceFile.isLineBreak(content(idx))) false + else if (content(idx) == CR && content(idx + 1) == LF) false else true - def position(offset: Int) = new OffsetPosition(this, offset) - def position(line: Int, column: Int) = new OffsetPosition(this, lineToOffset(line) + column) - - /** Map a position to a position in the underlying source file. - * For regular source files, simply return the argument. - */ - def positionInUltimateSource(position: Position) = position - - // constants - - // NOTE: all indexes are based on zero!!!! - override def toString(): String = file.name /* + ":" + content.length */ - - def dbg(offset: Int) = (new OffsetPosition(this, offset)).dbgString + def beginsWith(offset: Int, text: String): Boolean = { + var idx = 0 + while (idx < text.length()) { + if (offset + idx >= content.length) return false + if (content(offset + idx) != text.charAt(idx)) return false + idx += 1 + } + return true + } + def skipWhitespace(offset: Int): Int = + if (content(offset).isWhitespace) skipWhitespace(offset + 1) + else offset + def lineToString(index: Int): String = { + var offset = lineToOffset(index) + val buf = new StringBuilder() + while (!isLineBreak(offset) && offset < content.length) { + buf.append(content(offset)) + offset += 1 + } + buf.toString() + } object line { var index = 0 var offset = 0 def find(toFind: Int, isIndex: Boolean): Int = { if (toFind == 0) return 0 - - //if (!isIndex) assert(toFind != -1) - //if ( isIndex) assert(toFind > 0) - - if (!isIndex && (toFind >= content.length)) + if (!isIndex && (toFind >= content.length)) { + assert(true) throw new Error(toFind + " not valid offset in " + file.name + ":" + content.length) + } def get(isIndex : Boolean) = if (isIndex) index else offset @@ -79,11 +122,7 @@ class SourceFile(val file: AbstractFile, _content: Array[Char]) { val increment = if (isBackward) -1 else + 1 val oneIfBackward = if (isBackward) +1 else 0 - // System.err.println("FIND-0: " + toFind + " " + isIndex); - while (true) { - // System.err.println("FIND-1: " + offset + " " + index); - if (!isIndex && offset == toFind) return index; if (isBackward && offset <= 0) throw new Error(offset + " " + index + " " + toFind + " " + isIndex); @@ -102,52 +141,19 @@ class SourceFile(val file: AbstractFile, _content: Array[Char]) { def offsetToLine(offset: Int): Int = line.find(offset, false) def lineToOffset(index : Int): Int = line.find(index , true) - def beginsWith(offset: Int, text: String): Boolean = { - var idx = 0 - while (idx < text.length()) { - if (offset + idx >= content.length) return false - if (content(offset + idx) != text.charAt(idx)) return false - idx += 1 - } - return true - } - def path = getFile().path +} - def skipWhitespace(offset: Int): Int = - if (content(offset).isWhitespace) skipWhitespace(offset + 1) - else offset - def lineToString(index: Int): String = { - var offset = lineToOffset(index) - val buf = new StringBuilder() - while (!isLineBreak(offset) && offset < content.length) { - buf.append(content(offset)) - offset += 1 - } - buf.toString() - } - - private def normalize(input : Array[Char]): Array[Char] = - if (input.length > 0 && input(input.length - 1) == SU) - input - else { - val content = new Array[Char](input.length + 1) - Array.copy(input, 0, content, 0, input.length) - content(input.length) = SU - content - } -} /** A source file composed of multiple other source files. * - * @author Sean McDirmid * @version 1.0 */ class CompoundSourceFile( name: String, - components: List[SourceFile], + components: List[BatchSourceFile], contents: Array[Char]) -extends SourceFile(name, contents) +extends BatchSourceFile(name, contents) { /** The usual constructor. Specify a name for the compound file and * a list of component sources. @@ -155,18 +161,18 @@ extends SourceFile(name, contents) * @param name ... * @param components ... */ - def this(name: String, components: SourceFile*) = { + def this(name: String, components: BatchSourceFile*) = { /* Note that the contents leaves off the final SU character * of all components */ this( name, components.toList, Array.concat(components.toList.map(comp => - comp.content.subArray(0, comp.content.length-1)):_*)) + comp.content.slice(0, comp.content.length-1).toArray):_*)) } /** Create an instance with the specified components and a generic name. */ - def this(components: SourceFile*) = + def this(components: BatchSourceFile*) = this("(virtual file)", components.toList:_*) override def positionInUltimateSource(position: Position) = { @@ -178,7 +184,7 @@ extends SourceFile(name, contents) off = off - compsLeft.head.content.length + 1 compsLeft = compsLeft.tail } - compsLeft.head.positionInUltimateSource(new OffsetPosition(compsLeft.head, off)) + compsLeft.head.positionInUltimateSource(new OffsetPosition(this, off)) } } } @@ -190,21 +196,20 @@ extends SourceFile(name, contents) */ class SourceFileFragment( name: String, - underlyingFile: SourceFile, + underlyingFile: BatchSourceFile, start: Int, stop: Int, contents: Array[Char]) -extends SourceFile(name, contents) -{ - def this(name: String, underlyingFile: SourceFile, start: Int, stop: Int) = +extends BatchSourceFile(name, contents) { + def this(name: String, underlyingFile: BatchSourceFile, start: Int, stop: Int) = this( name, underlyingFile, start, stop, - underlyingFile.content.subArray(start, stop)) + underlyingFile.content.slice(start, stop).toArray) - def this(underlyingFile: SourceFile, start: Int, stop: Int) = + def this(underlyingFile: BatchSourceFile, start: Int, stop: Int) = this( "(fragment of " + underlyingFile.file.name + ")", underlyingFile, @@ -214,7 +219,7 @@ extends SourceFile(name, contents) override def positionInUltimateSource(position: Position) = { if (position.offset.isEmpty) super.positionInUltimateSource(position) - else underlyingFile.positionInUltimateSource( - new OffsetPosition(underlyingFile, position.offset.get + start)) + else positionInUltimateSource( + new OffsetPosition(this, position.offset.get + start)) } } diff --git a/src/library/scala/collection/jcl/BufferWrapper.scala b/src/library/scala/collection/jcl/BufferWrapper.scala index 1a3e9a35e6..b1b388ed19 100644 --- a/src/library/scala/collection/jcl/BufferWrapper.scala +++ b/src/library/scala/collection/jcl/BufferWrapper.scala @@ -40,7 +40,7 @@ trait BufferWrapper[A] extends Buffer[A] with CollectionWrapper[A] { } override def elements = super[BufferWrapper].elements; } - class IteratorWrapper(underlying : java.util.ListIterator) extends super.IteratorWrapper(underlying) with BufferIterator[Int,A] { + class IteratorWrapper(underlying : java.util.ListIterator) extends MutableIterator.Wrapper[A](underlying) with BufferIterator[Int,A] { def add(a : A) = underlying.add(a); def set(a : A) = underlying.set(a); def hasPrevious = underlying.hasPrevious; diff --git a/src/library/scala/collection/jcl/IterableWrapper.scala b/src/library/scala/collection/jcl/IterableWrapper.scala index c89d7bf748..a0c1c1d51a 100644 --- a/src/library/scala/collection/jcl/IterableWrapper.scala +++ b/src/library/scala/collection/jcl/IterableWrapper.scala @@ -28,12 +28,14 @@ trait IterableWrapper[A] extends MutableIterable[A] { override def size = underlying.size; override def isEmpty = underlying.isEmpty; override def clear = underlying.clear; - override def elements : MutableIterator[A] = new IteratorWrapper(underlying.iterator); + override def elements : MutableIterator[A] = new MutableIterator.Wrapper[A](underlying.iterator); +/* moved to MutableIterator class IteratorWrapper(underlying : java.util.Iterator) extends MutableIterator[A] { // val underlying = IterableWrapper.this.underlying.iterator; def hasNext = underlying.hasNext; def next = underlying.next.asInstanceOf[A]; def remove = underlying.remove; } +*/ } diff --git a/src/library/scala/collection/jcl/Map.scala b/src/library/scala/collection/jcl/Map.scala index 40b2bcaf9c..a702fb15f1 100644 --- a/src/library/scala/collection/jcl/Map.scala +++ b/src/library/scala/collection/jcl/Map.scala @@ -23,10 +23,13 @@ trait Map[K,E] extends MutableIterable[Tuple2[K,E]] with scala.collection.mutabl removals from the returned collection will remove the element from this map. @returns a projection of this map's elements. */ def valueSet : MutableIterable.Projection[E] = projection.map(_._2); - def put(key : K, elem : E) : Option[E]; - def putAll(that : Iterable[Tuple2[K,E]]) : Unit = + + override def put(key : K, elem : E) : Option[E] = throw new java.lang.AbstractMethodError + + override def ++=(that : Iterable[(K,E)]) : Unit = that.foreach(p => put(p._1, p._2)); - def removeKey(key : K) : Option[E] = { + + override def removeKey(key : K) : Option[E] = { val i = elements; while (!i.hasNext) { val result = i.next; diff --git a/src/library/scala/collection/jcl/MapWrapper.scala b/src/library/scala/collection/jcl/MapWrapper.scala index 48e4b47003..7e6c491289 100644 --- a/src/library/scala/collection/jcl/MapWrapper.scala +++ b/src/library/scala/collection/jcl/MapWrapper.scala @@ -29,9 +29,9 @@ trait MapWrapper[K,E] extends jcl.Map[K,E] { if (ret == null) None else Some(ret.asInstanceOf[E]); } - override def putAll(that : Iterable[Tuple2[K,E]]) : Unit = that match { + override def ++=(that : Iterable[Tuple2[K,E]]) : Unit = that match { case that : MapWrapper[_,_] => underlying.putAll(that.underlying); - case _ => super.putAll(that); + case _ => super.++=(that); } override def removeKey(key : K) = { val ret = underlying.remove(key); diff --git a/src/library/scala/collection/jcl/MutableIterator.scala b/src/library/scala/collection/jcl/MutableIterator.scala index d82368698e..d90545c7a2 100644 --- a/src/library/scala/collection/jcl/MutableIterator.scala +++ b/src/library/scala/collection/jcl/MutableIterator.scala @@ -10,6 +10,14 @@ package scala.collection.jcl; +object MutableIterator { + class Wrapper[A](val underlying : java.util.Iterator) extends MutableIterator[A] { + def hasNext = underlying.hasNext; + def next = underlying.next.asInstanceOf[A]; + def remove = underlying.remove; + } +} + /** An iterator that supports the remove operation. * These iterators wrap Java iterators, and so have the same fail fast * behavior when dealing with concurrent modifications. @@ -26,7 +34,7 @@ trait MutableIterator[A] extends Iterator[A] { override def map[B](f: A => B) : MutableIterator[B] = new Map(f); /** A type-safe version of contains. -b **/ + **/ def has(a: A) = exists(b => a == a); /** Finds and removes the first instance of "a" through the iterator. diff --git a/src/library/scala/collection/mutable/Map.scala b/src/library/scala/collection/mutable/Map.scala index ca1dd9d62e..1f065cb6eb 100644 --- a/src/library/scala/collection/mutable/Map.scala +++ b/src/library/scala/collection/mutable/Map.scala @@ -133,6 +133,25 @@ trait Map[A, B] extends AnyRef */ def - (key: A): Map[A, B] = { this -= key; this } + /** Remove <code>key</code> from this map and return the element + * that the key was previously mapped to (if any). + */ + def removeKey(key : A) : Option[B] = { + val ret = get(key) + this -= key + ret + } + + /** Map <code>key</code> to <code>elem</code> in this map and return the element + * that the key was previously mapped to (if any). + */ + def put(key : A, elem : B) : Option[B] = { + val ret = get(key) + this(key) = elem + ret + } + + /** Remove two or more keys from this map * @param key1 the first key to be removed * @param key2 the second key to be removed diff --git a/src/library/scala/runtime/RichString.scala b/src/library/scala/runtime/RichString.scala index c109b9c9cb..a16c550786 100644 --- a/src/library/scala/runtime/RichString.scala +++ b/src/library/scala/runtime/RichString.scala @@ -15,6 +15,7 @@ package scala.runtime import Predef._ final class RichString(val self: String) extends Proxy with RandomAccessSeq[Char] with Ordered[String] { + import RichString._ override def apply(n: Int) = self charAt n override def length = self.length override def toString = self @@ -59,10 +60,6 @@ final class RichString(val self: String) extends Proxy with RandomAccessSeq[Char override def compare(other: String) = self compareTo other - private final val LF: Char = 0x0A - private final val FF: Char = 0x0C - private final val CR: Char = 0x0D - private final val SU: Char = 0x1A private def isLineBreak(c: Char) = c == LF || c == FF @@ -182,5 +179,12 @@ final class RichString(val self: String) extends Proxy with RandomAccessSeq[Char def toLong: Long = java.lang.Long.parseLong(self) def toFloat: Float = java.lang.Float.parseFloat(self) def toDouble: Double = java.lang.Double.parseDouble(self) - } +object RichString { + // just statics for rich string. + private final val LF: Char = 0x0A + private final val FF: Char = 0x0C + private final val CR: Char = 0x0D + private final val SU: Char = 0x1A +} + diff --git a/test/files/neg/abstract.check b/test/files/neg/abstract.check index f67cc2bbbd..c33011bb55 100644 --- a/test/files/neg/abstract.check +++ b/test/files/neg/abstract.check @@ -1,19 +1,19 @@ abstract.scala:5: error: method bar cannot be accessed in A.this.T because its instance type ()A.this.T#T contains a malformed type: A.this.T#T def foo1: A = bar().bar(); - ^ + ^ abstract.scala:6: error: type mismatch; found : A required: A.this.T def foo2: T = bar().baz(); - ^ + ^ abstract.scala:8: error: method bar cannot be accessed in A because its instance type ()A#T contains a malformed type: A#T def foo4: A = baz().bar(); - ^ + ^ abstract.scala:9: error: type mismatch; found : A required: A.this.T def foo5: T = baz().baz(); - ^ + ^ four errors found diff --git a/test/files/neg/accesses.check b/test/files/neg/accesses.check index 2fa78ffc50..11d313e534 100644 --- a/test/files/neg/accesses.check +++ b/test/files/neg/accesses.check @@ -1,17 +1,17 @@ accesses.scala:23: error: error overriding method f2 in class A of type => unit; method f2 has weaker access privileges; it should not be private private def f2: unit = () - ^ + ^ accesses.scala:24: error: error overriding method f3 in class A of type => unit; method f3 has weaker access privileges; it should be at least protected private[p2] def f3: unit = () - ^ + ^ accesses.scala:25: error: error overriding method f4 in class A of type => unit; method f4 has weaker access privileges; it should be at least private[p1] private[p2] def f4: unit - ^ + ^ accesses.scala:26: error: error overriding method f5 in class A of type => unit; method f5 has weaker access privileges; it should be at least protected[p1] protected[p2] def f5: unit - ^ + ^ four errors found diff --git a/test/files/neg/badtok-1.check b/test/files/neg/badtok-1.check index 6523358c79..27c7587828 100644 --- a/test/files/neg/badtok-1.check +++ b/test/files/neg/badtok-1.check @@ -1,7 +1,4 @@ -badtok-1.scala:2: error: expected class or object definition +badtok-1.scala:2: error: unexpected quote after symbol '42' ^ -badtok-1.scala:2: error: unclosed character literal -'42' - ^ -two errors found +one error found diff --git a/test/files/neg/badtok-2.check b/test/files/neg/badtok-2.check index 4b142c37a1..6364b857a1 100644 --- a/test/files/neg/badtok-2.check +++ b/test/files/neg/badtok-2.check @@ -1,10 +1,7 @@ -badtok-2.scala:3: error: unclosed quoted identifier -`x - ^ -badtok-2.scala:3: error: illegal start of definition +badtok-2.scala:3: error: unterminated quoted identifier `x ^ badtok-2.scala:3: error: '}' expected but eof found. `x - ^ -three errors found + ^ +two errors found diff --git a/test/files/neg/bug1112.check b/test/files/neg/bug1112.check index 3be45a87fe..9aedff2de9 100644 --- a/test/files/neg/bug1112.check +++ b/test/files/neg/bug1112.check @@ -1,4 +1,4 @@ bug1112.scala:12: error: wrong number of arguments for method call: (int)(=> () => unit)unit call(0,() => System.out.println("here we are")) - ^ + ^ one error found diff --git a/test/files/neg/bug1183.check b/test/files/neg/bug1183.check index 50b236187e..ebbf8aca23 100644 --- a/test/files/neg/bug1183.check +++ b/test/files/neg/bug1183.check @@ -1,17 +1,17 @@ bug1183.scala:10: error: name clash: class Foo defines object Baz and its companion object Foo also defines class Baz object Baz - ^ + ^ bug1183.scala:11: error: name clash: class Foo defines class Bam and its companion object Foo also defines object Bam class Bam - ^ + ^ bug1183.scala:12: error: name clash: class Foo defines object Bar and its companion object Foo also defines class Bar object Bar - ^ + ^ bug1183.scala:13: error: name clash: class Foo defines class Bar and its companion object Foo also defines class Bar case class Bar(i:Int) - ^ + ^ four errors found diff --git a/test/files/neg/bug200.check b/test/files/neg/bug200.check index bfce301807..d3670060cd 100644 --- a/test/files/neg/bug200.check +++ b/test/files/neg/bug200.check @@ -1,4 +1,4 @@ bug200.scala:7: error: method foo is defined twice def foo: Int; - ^ + ^ one error found diff --git a/test/files/neg/bug391.check b/test/files/neg/bug391.check index 4db19a39c4..18f36a5757 100644 --- a/test/files/neg/bug391.check +++ b/test/files/neg/bug391.check @@ -1,13 +1,13 @@ bug391.scala:2: error: identifier expected but 'def' found. def fun1(def x: Int): Int = x; // the "def x" is illegal ^ -bug391.scala:3: error: ':' expected but '}' found. - def fun2(val x: Int): Int = x; // the "val x" is illegal - ^ +bug391.scala:4: error: ':' expected but '}' found. +} +^ bug391.scala:6: error: identifier expected but 'def' found. class E(def x: Int); // the "def x" is illegal ^ bug391.scala:6: error: ':' expected but eof found. class E(def x: Int); // the "def x" is illegal - ^ + ^ four errors found diff --git a/test/files/neg/bug415.check b/test/files/neg/bug415.check index c834a328eb..a1c68954cb 100644 --- a/test/files/neg/bug415.check +++ b/test/files/neg/bug415.check @@ -1,5 +1,5 @@ bug415.scala:8: error: method x cannot be accessed in A because its instance type => A#T contains a malformed type: A#T val y: String = a.x; - ^ + ^ one error found diff --git a/test/files/neg/bug515.check b/test/files/neg/bug515.check index 28cdd48927..fff96a563d 100644 --- a/test/files/neg/bug515.check +++ b/test/files/neg/bug515.check @@ -2,5 +2,5 @@ bug515.scala:7: error: type mismatch; found : java.lang.String required: Test.this.Truc val parent: Truc = file.getMachin - ^ + ^ one error found diff --git a/test/files/neg/bug520.check b/test/files/neg/bug520.check index 258f8112e3..6768ebb5fc 100644 --- a/test/files/neg/bug520.check +++ b/test/files/neg/bug520.check @@ -1,4 +1,4 @@ bug520.scala:8: error: overloaded method verifyKeyword needs result type verifyKeyword("", source, pos); - ^ + ^ one error found diff --git a/test/files/neg/bug521.check b/test/files/neg/bug521.check index 80a1931231..1b05acae18 100644 --- a/test/files/neg/bug521.check +++ b/test/files/neg/bug521.check @@ -1,15 +1,15 @@ bug521.scala:10: error: class PlainFile needs to be abstract, since method path in class AbstractFile of type => String is not defined class PlainFile(val file : File) extends AbstractFile {} -^ + ^ bug521.scala:13: error: error overriding value file in class PlainFile of type java.io.File; value file needs `override' modifier final class ZipArchive(val file : File, archive : ZipFile) extends PlainFile(file) { - ^ + ^ bug521.scala:13: error: class ZipArchive needs to be abstract, since method path in class AbstractFile of type => String is not defined final class ZipArchive(val file : File, archive : ZipFile) extends PlainFile(file) { - ^ + ^ bug521.scala:15: error: error overriding value path in class VirtualFile of type String; method path needs to be an immutable value override def path = ""; - ^ + ^ four errors found diff --git a/test/files/neg/bug545.check b/test/files/neg/bug545.check index f349c084fc..892a66dfc6 100644 --- a/test/files/neg/bug545.check +++ b/test/files/neg/bug545.check @@ -1,6 +1,6 @@ bug545.scala:4: error: value blah is not a member of Test.this.Foo val x = foo.blah match { - ^ + ^ bug545.scala:5: error: recursive value x needs type case List(x) => x ^ diff --git a/test/files/neg/bug550.check b/test/files/neg/bug550.check index 6c8580091c..8f1a5c0e5a 100644 --- a/test/files/neg/bug550.check +++ b/test/files/neg/bug550.check @@ -3,5 +3,5 @@ bug550.scala:6: error: class List takes type parameters ^ bug550.scala:8: error: no implicit argument matching parameter type Monoid[Nothing] was found. sum(List(1,2,3)) - ^ + ^ two errors found diff --git a/test/files/neg/bug558.check b/test/files/neg/bug558.check index a51856f0e6..061f64f7bb 100644 --- a/test/files/neg/bug558.check +++ b/test/files/neg/bug558.check @@ -1,4 +1,4 @@ bug558.scala:13: error: value file is not a member of NewModel.this.RootURL final val source = top.file; - ^ + ^ one error found diff --git a/test/files/neg/bug576.check b/test/files/neg/bug576.check index b496ccafd4..72d5d258d2 100644 --- a/test/files/neg/bug576.check +++ b/test/files/neg/bug576.check @@ -1,4 +1,4 @@ bug576.scala:14: error: overloaded method insert needs result type if (true) sibling.insert(node); - ^ + ^ one error found diff --git a/test/files/neg/bug585.check b/test/files/neg/bug585.check index 4e2f72a941..af66898383 100644 --- a/test/files/neg/bug585.check +++ b/test/files/neg/bug585.check @@ -1,4 +1,4 @@ -bug585.scala:1: error: unclosed comment +bug585.scala:1: error: unterminated comment /* - ^ +^ one error found diff --git a/test/files/neg/bug588.check b/test/files/neg/bug588.check index b1e5340c91..59e4229192 100644 --- a/test/files/neg/bug588.check +++ b/test/files/neg/bug588.check @@ -3,11 +3,11 @@ method visit:((int) => String)boolean and method visit:((int) => unit)boolean at line 2 have same type after erasure: (Function1)Boolean def visit(f: int => String): boolean - ^ + ^ bug588.scala:10: error: double definition: method f:(Test.this.TypeB)Unit and method f:(Test.this.TypeA)Unit at line 9 have same type after erasure: (Test#TraitA)Unit def f(brac : TypeB) : Unit; - ^ + ^ two errors found diff --git a/test/files/neg/bug591.check b/test/files/neg/bug591.check index 7a1a38f52b..2c2e08da99 100644 --- a/test/files/neg/bug591.check +++ b/test/files/neg/bug591.check @@ -1,4 +1,4 @@ bug591.scala:38: error: method input_= is defined twice def input_=(in : Input) = {} - ^ + ^ one error found diff --git a/test/files/neg/bug630.check b/test/files/neg/bug630.check index 600a999d20..f1ac0da57f 100644 --- a/test/files/neg/bug630.check +++ b/test/files/neg/bug630.check @@ -1,5 +1,5 @@ bug630.scala:20: error: error overriding value foo in trait Bar of type Req2; object foo has incompatible type object Test.this.foo object foo extends Req1 - ^ + ^ one error found diff --git a/test/files/neg/bug631.check b/test/files/neg/bug631.check index cb18e1d397..0650c701d9 100644 --- a/test/files/neg/bug631.check +++ b/test/files/neg/bug631.check @@ -1,4 +1,4 @@ bug631.scala:1: error: `implicit' modifier cannot be used for top-level objects implicit object Test { - ^ + ^ one error found diff --git a/test/files/neg/bug649.check b/test/files/neg/bug649.check index 80220e1af2..a5b97b72d1 100644 --- a/test/files/neg/bug649.check +++ b/test/files/neg/bug649.check @@ -1,4 +1,4 @@ bug649.scala:3: error: illegal cyclic reference involving method foo def foo[A] = foo[A] - ^ + ^ one error found diff --git a/test/files/neg/bug663.check b/test/files/neg/bug663.check index 55b0b8f7bb..d1ef2ae09d 100644 --- a/test/files/neg/bug663.check +++ b/test/files/neg/bug663.check @@ -3,5 +3,5 @@ method asMatch:(Test.this.Node)Any and method asMatch:(Test.this.Matchable)Any in trait MatchableImpl have same type after erasure: (test.Test#NodeImpl)java.lang.Object def asMatch(m : Node) : Any = { - ^ + ^ one error found diff --git a/test/files/neg/bug664.check b/test/files/neg/bug664.check index 176058d962..c29f9b6c7c 100644 --- a/test/files/neg/bug664.check +++ b/test/files/neg/bug664.check @@ -1,7 +1,7 @@ bug664.scala:4: error: type Foo is not a member of test.Test with ScalaObject trait Foo extends super.Foo { - ^ + ^ bug664.scala:5: error: type Bar is not a member of AnyRef with ScalaObject trait Bar extends super.Bar; - ^ + ^ two errors found diff --git a/test/files/neg/bug691.check b/test/files/neg/bug691.check index 47ac8c3888..f811fc3559 100644 --- a/test/files/neg/bug691.check +++ b/test/files/neg/bug691.check @@ -1,4 +1,4 @@ bug691.scala:27: error: ambiguous parent class qualifier trait TiC extends super[Arrow].Ti2 with super[AssignArrow].Ti1; - ^ + ^ one error found diff --git a/test/files/neg/bug696.check b/test/files/neg/bug696.check index a2f31702b7..28ce342cf1 100644 --- a/test/files/neg/bug696.check +++ b/test/files/neg/bug696.check @@ -2,8 +2,8 @@ bug696.scala:3: error: implicit method WithType is not contractive, because the implicit parameter type TypeUtil0.this.Type[S] is not strictly contained in the signature TypeUtil0.this.Type[S with T] implicit def WithType[S,T](implicit tpeS : Type[S], tpeT : Type[T]) : Type[S with T] = null - ^ + ^ bug696.scala:4: error: no implicit argument matching parameter type TypeUtil0.this.Type[Any] was found. as[Any](null); - ^ + ^ two errors found diff --git a/test/files/neg/bug700.check b/test/files/neg/bug700.check index 149a1564a9..33a67e5094 100644 --- a/test/files/neg/bug700.check +++ b/test/files/neg/bug700.check @@ -1,4 +1,4 @@ bug700.scala:6: error: method foobar in trait Foo is accessed from super. It may not be abstract unless it is overridden by a member declared `abstract' and `override' def foobar: unit = super.foobar - ^ + ^ one error found diff --git a/test/files/neg/bug712.check b/test/files/neg/bug712.check index 59620d59cf..532eb4aec0 100644 --- a/test/files/neg/bug712.check +++ b/test/files/neg/bug712.check @@ -1,4 +1,4 @@ bug712.scala:10: error: value self is not a member of B.this.ParentImpl implicit def coerce(p : ParentImpl) = p.self; - ^ + ^ one error found diff --git a/test/files/neg/bug715.check b/test/files/neg/bug715.check index 7029220258..8ea1ddb0eb 100644 --- a/test/files/neg/bug715.check +++ b/test/files/neg/bug715.check @@ -1,4 +1,4 @@ bug715.scala:12: error: method chilren in trait NodeImpl is accessed from super. It may not be abstract unless it is overridden by a member declared `abstract' and `override' override def children = super.chilren; - ^ + ^ one error found diff --git a/test/files/neg/bug729.check b/test/files/neg/bug729.check index ae00d309b1..0b38b9bc1d 100644 --- a/test/files/neg/bug729.check +++ b/test/files/neg/bug729.check @@ -2,5 +2,5 @@ bug729.scala:20: error: type mismatch; found : ScalaParserAutoEdit.this.NodeImpl(in trait Parser) required: ScalaParserAutoEdit.this.NodeImpl(in trait ScalaParserAutoEdit) val yyy : NodeImpl = link.from; - ^ + ^ one error found diff --git a/test/files/neg/bug779.check b/test/files/neg/bug779.check index 180fa3824e..941951900e 100644 --- a/test/files/neg/bug779.check +++ b/test/files/neg/bug779.check @@ -1,4 +1,4 @@ -bug779.scala:6: error: method method ast has return statement; needs result type +bug779.scala:6: error: method ast has return statement; needs result type override def ast = return null ^ one error found diff --git a/test/files/neg/bug836.check b/test/files/neg/bug836.check index 10a707ec93..1fcae2ecb3 100644 --- a/test/files/neg/bug836.check +++ b/test/files/neg/bug836.check @@ -1,5 +1,5 @@ bug836.scala:6: error: type S cannot be accessed in A.this.MyObj because its instance type A.this.MyObj#S is malformed type S = MyObj#S - ^ + ^ one error found diff --git a/test/files/neg/bug839.check b/test/files/neg/bug839.check index fa161de5a5..2f22e26d44 100644 --- a/test/files/neg/bug839.check +++ b/test/files/neg/bug839.check @@ -1,5 +1,5 @@ bug839.scala:25: error: method set cannot be accessed in object Test.this.FileImpl#treeBuilder because its instance type (Test.this.Global#Tree)Unit contains a malformed type: Test.this.Global#Tree file.treeBuilder.set(nsc.get); - ^ + ^ one error found diff --git a/test/files/neg/bug856.check b/test/files/neg/bug856.check index 80c4deeea2..3ab4ce6c70 100644 --- a/test/files/neg/bug856.check +++ b/test/files/neg/bug856.check @@ -1,4 +1,4 @@ bug856.scala:3: error: class ComplexRect needs to be abstract, since method _2 in trait Product2 of type => double is not defined class ComplexRect(val _1:double, _2:double) extends Complex { -^ + ^ one error found diff --git a/test/files/neg/bug876.check b/test/files/neg/bug876.check index e7d5d5d78f..c08d4c7de8 100644 --- a/test/files/neg/bug876.check +++ b/test/files/neg/bug876.check @@ -1,4 +1,4 @@ bug876.scala:25: error: wrong number of arguments for method apply: (AssertionError.this.A)manager.B in trait Map assert(manager.map(A2) == List(manager.map(A2, A1))) - ^ + ^ one error found diff --git a/test/files/neg/bug877.check b/test/files/neg/bug877.check index 6c262cdcb9..e71041348c 100644 --- a/test/files/neg/bug877.check +++ b/test/files/neg/bug877.check @@ -1,4 +1,7 @@ bug877.scala:3: error: parents of traits may not have parameters trait Foo extends A(22A, Bug!) {} ^ -one error found +bug877.scala:3: error: Invalid literal number +trait Foo extends A(22A, Bug!) {} + ^ +two errors found diff --git a/test/files/neg/bug960.check b/test/files/neg/bug960.check index fc944bf879..c947223aa3 100644 --- a/test/files/neg/bug960.check +++ b/test/files/neg/bug960.check @@ -3,5 +3,5 @@ bug960.scala:18: error: cannot resolve overloaded unapply ^ bug960.scala:12: error: method unapply is defined twice def unapply[a](xs: List[a]): Option[Null] = xs match { - ^ + ^ two errors found diff --git a/test/files/neg/bug961.check b/test/files/neg/bug961.check index 559dd93d6f..ef7e54d712 100644 --- a/test/files/neg/bug961.check +++ b/test/files/neg/bug961.check @@ -1,4 +1,4 @@ bug961.scala:11: error: Temp.this.B of type object Temp.this.B does not take parameters B() match { - ^ + ^ one error found diff --git a/test/files/neg/bug987.check b/test/files/neg/bug987.check index d850f39fd9..5da1e1cbe3 100644 --- a/test/files/neg/bug987.check +++ b/test/files/neg/bug987.check @@ -2,17 +2,17 @@ bug987.scala:15: error: illegal inheritance; class E inherits different type instances of trait B: B[C] and B[D] class E extends D -^ + ^ bug987.scala:20: error: illegal inheritance; class F inherits different type instances of trait B: B[C] and B[D] class F extends D -^ + ^ bug987.scala:25: error: illegal inheritance; class D inherits different type instances of trait B: B[C] and B[D] abstract class D extends C with B[D] {} - ^ + ^ bug987.scala:25: error: type arguments [D] do not conform to trait B's type parameter bounds [T <: B[T]] abstract class D extends C with B[D] {} ^ diff --git a/test/files/neg/bug997.check b/test/files/neg/bug997.check index 44e383228d..e3c86c96a4 100644 --- a/test/files/neg/bug997.check +++ b/test/files/neg/bug997.check @@ -1,12 +1,12 @@ bug997.scala:7: error: wrong number of arguments for object Foo "x" match { case Foo(a) => Console.println(a) } - ^ + ^ bug997.scala:7: error: not found: value a "x" match { case Foo(a) => Console.println(a) } ^ bug997.scala:13: error: wrong number of arguments for object Foo "x" match { case Foo(a, b, c) => Console.println((a,b,c)) } - ^ + ^ bug997.scala:13: error: not found: value a "x" match { case Foo(a, b, c) => Console.println((a,b,c)) } ^ diff --git a/test/files/neg/checksensible.check b/test/files/neg/checksensible.check index 7c0c71c803..47abfe3589 100644 --- a/test/files/neg/checksensible.check +++ b/test/files/neg/checksensible.check @@ -1,6 +1,6 @@ checksensible.scala:1: error: class Test needs to be abstract, since method isabstract is not defined class Test { -^ + ^ checksensible.scala:3: warning: comparing values of types Ordered[Unit] and Unit using `>' will always yield false println((c = 1) > 0) ^ diff --git a/test/files/neg/constrs.check b/test/files/neg/constrs.check index 3680f292b2..606565d42e 100644 --- a/test/files/neg/constrs.check +++ b/test/files/neg/constrs.check @@ -1,9 +1,9 @@ constrs.scala:6: error: type T is not a member of object test def this(y: int)(z: int)(t: this.T) = { this(this.u + y + z); Console.println(x) } - ^ + ^ constrs.scala:6: error: value u is not a member of object test def this(y: int)(z: int)(t: this.T) = { this(this.u + y + z); Console.println(x) } - ^ + ^ constrs.scala:10: error: called constructor's definition must precede calling constructor's definition def this() = this("abc") ^ diff --git a/test/files/neg/gadts1.check b/test/files/neg/gadts1.check index 151cfad712..b16cbaf11d 100644 --- a/test/files/neg/gadts1.check +++ b/test/files/neg/gadts1.check @@ -2,5 +2,5 @@ gadts1.scala:15: error: type mismatch; found : Test.this.Double required: a case NumTerm(n) => c.x = Double(1.0) - ^ + ^ one error found diff --git a/test/files/neg/overload.check b/test/files/neg/overload.check index f3d3454116..5f7644eda7 100644 --- a/test/files/neg/overload.check +++ b/test/files/neg/overload.check @@ -3,5 +3,5 @@ most specific definition is: method f in class C of type (int)Unit, yet alternative definition method f in class D of type (Any)Unit is defined in a subclass (new D).f(1) - ^ + ^ one error found diff --git a/test/files/neg/sabin2.check b/test/files/neg/sabin2.check index e127cc67a2..cd45905df2 100644 --- a/test/files/neg/sabin2.check +++ b/test/files/neg/sabin2.check @@ -1,5 +1,5 @@ sabin2.scala:22: error: method set cannot be accessed in Test.this.Base#Inner because its instance type (Test.this.Base#T)Unit contains a malformed type: Test.this.Base#T a.set(b.get()) // Error - ^ + ^ one error found diff --git a/test/files/neg/scopes.check b/test/files/neg/scopes.check index b312893044..13f728b01c 100644 --- a/test/files/neg/scopes.check +++ b/test/files/neg/scopes.check @@ -18,7 +18,7 @@ scopes.scala:14: error: y is already defined as value y ^ scopes.scala:15: error: x is already defined as value x val closure = (x: int, x: float) => x - ^ + ^ scopes.scala:17: error: x is already defined as value x case x::x => x ^ diff --git a/test/files/neg/tcpoly_variance.check b/test/files/neg/tcpoly_variance.check index 61d7094437..146240ac9b 100644 --- a/test/files/neg/tcpoly_variance.check +++ b/test/files/neg/tcpoly_variance.check @@ -1,5 +1,5 @@ tcpoly_variance.scala:6: error: error overriding method str in class A of type => m[java.lang.Object]; method str has incompatible type => m[String] override def str: m[String] = error("foo") // since x in m[x] is invariant, ! m[String] <: m[Object] - ^ + ^ one error found diff --git a/test/files/neg/typeerror.check b/test/files/neg/typeerror.check index c087ba594b..3e21a79ad5 100644 --- a/test/files/neg/typeerror.check +++ b/test/files/neg/typeerror.check @@ -2,5 +2,5 @@ typeerror.scala:6: error: type mismatch; found : Long(in method add) required: Long(in package scala) else add2(x.head, y.head) :: add(x.tail, y.tail) - ^ + ^ one error found diff --git a/test/files/neg/variances.check b/test/files/neg/variances.check index 4934053706..f335035b5b 100644 --- a/test/files/neg/variances.check +++ b/test/files/neg/variances.check @@ -15,6 +15,6 @@ variances.scala:14: error: covariant type A occurs in contravariant position in ^ variances.scala:16: error: covariant type A occurs in invariant position in type test.C[A] with ScalaObject{def this(): object Foo.this.Baz} of object Baz object Baz extends C[A] - ^ + ^ three warnings found three errors found diff --git a/test/files/neg/xmlcorner.check b/test/files/neg/xmlcorner.check index 8791829e50..5d3e9288d5 100644 --- a/test/files/neg/xmlcorner.check +++ b/test/files/neg/xmlcorner.check @@ -3,5 +3,5 @@ xmlcorner.scala:2: error: illegal start of simple expression ^ xmlcorner.scala:5: error: in XML literal: name cannot end in ':' val wrong = <bla: /> - ^ + ^ two errors found diff --git a/test/files/neg/xmltruncated1.check b/test/files/neg/xmltruncated1.check index 0014ef4011..36daa342e5 100644 --- a/test/files/neg/xmltruncated1.check +++ b/test/files/neg/xmltruncated1.check @@ -1,4 +1,4 @@ -xmltruncated1.scala:3: error: input ended while parsing XML - -^ +xmltruncated1.scala:2: error: input ended while parsing XML + val stuff = <a> + ^ one error found diff --git a/test/files/neg/xmltruncated2.check b/test/files/neg/xmltruncated2.check index cb7949d25f..f1de059f84 100644 --- a/test/files/neg/xmltruncated2.check +++ b/test/files/neg/xmltruncated2.check @@ -1,4 +1,4 @@ -xmltruncated2.scala:3: error: input ended while parsing XML - -^ +xmltruncated2.scala:2: error: input ended while parsing XML + val stuff = <![CDATA[aoeu + ^ one error found diff --git a/test/files/neg/xmltruncated3.check b/test/files/neg/xmltruncated3.check index 3c7e31912f..76851bd365 100644 --- a/test/files/neg/xmltruncated3.check +++ b/test/files/neg/xmltruncated3.check @@ -1,4 +1,4 @@ -xmltruncated3.scala:3: error: input ended while parsing XML - -^ +xmltruncated3.scala:2: error: input ended while parsing XML + val stuff = <a unclosedattr="aaaa + ^ one error found diff --git a/test/files/neg/xmltruncated4.check b/test/files/neg/xmltruncated4.check index c78c222ca7..4a3265d273 100644 --- a/test/files/neg/xmltruncated4.check +++ b/test/files/neg/xmltruncated4.check @@ -1,4 +1,4 @@ -xmltruncated4.scala:3: error: input ended while parsing XML - -^ +xmltruncated4.scala:2: error: input ended while parsing XML + val stuff = <!-- comment starts but never ends... + ^ one error found diff --git a/test/files/neg/xmltruncated5.check b/test/files/neg/xmltruncated5.check index d6f5742eab..cd13200b86 100644 --- a/test/files/neg/xmltruncated5.check +++ b/test/files/neg/xmltruncated5.check @@ -1,4 +1,4 @@ -xmltruncated5.scala:4: error: input ended while parsing XML - -^ +xmltruncated5.scala:3: error: input ended while parsing XML + case <a> + ^ one error found diff --git a/test/files/neg/xmltruncated6.check b/test/files/neg/xmltruncated6.check index 82d62cae5a..f638f2f090 100644 --- a/test/files/neg/xmltruncated6.check +++ b/test/files/neg/xmltruncated6.check @@ -1,7 +1,4 @@ -xmltruncated6.scala:2: error: ';' expected but eof found. +xmltruncated6.scala:2: error: in XML literal: expected end of Scala block val stuff = <a>{ "no closing brace" ^ -xmltruncated6.scala:3: error: input ended while parsing XML - -^ -two errors found +one error found diff --git a/test/files/res/bug687.check b/test/files/res/bug687.check index 803edbbf4f..92e5e4e75d 100644 --- a/test/files/res/bug687.check +++ b/test/files/res/bug687.check @@ -5,7 +5,7 @@ method equals:(java.lang.Object)Boolean and method equals:(Any)Boolean in class Any have same type after erasure: (java.lang.Object)Boolean override def equals(o : Object) = false; - ^ + ^ nsc> nsc>
\ No newline at end of file |