diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/Global.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 258 |
1 files changed, 16 insertions, 242 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 572e579aca..82ffb35c3f 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -45,7 +45,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter) with Printers with DocComments with Positions - with Reporting { self => + with Reporting + with Parsing { self => // the mirror -------------------------------------------------- @@ -218,6 +219,14 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** Called from parser, which signals hereby that a method definition has been parsed. */ def signalParseProgress(pos: Position) {} + /** Called by ScalaDocAnalyzer when a doc comment has been parsed. */ + def signalParsedDocComment(comment: String, pos: Position) = { + // TODO: this is all very borken (only works for scaladoc comments, not regular ones) + // --> add hooks to parser and refactor Interactive global to handle comments directly + // in any case don't use reporter for parser hooks + reporter.comment(pos, comment) + } + /** Register new context; called for every created context */ def registerContext(c: analyzer.Context) { @@ -395,7 +404,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) reporter.cancelled || unit.isJava && this.id > maxJavaPhase } - final def applyPhase(unit: CompilationUnit) { + final def withCurrentUnit(unit: CompilationUnit)(task: => Unit) { if ((unit ne null) && unit.exists) lastSeenSourceFile = unit.source @@ -407,7 +416,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) currentRun.currentUnit = unit if (!cancelled(unit)) { currentRun.informUnitStarting(this, unit) - apply(unit) + task } currentRun.advanceUnit() } finally { @@ -415,6 +424,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter) currentRun.currentUnit = unit0 } } + + final def applyPhase(unit: CompilationUnit) = withCurrentUnit(unit)(apply(unit)) } // phaseName = "parser" @@ -831,198 +842,11 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } reverse } - // ------------ Invalidations --------------------------------- - - /** Is given package class a system package class that cannot be invalidated? - */ - private def isSystemPackageClass(pkg: Symbol) = - pkg == RootClass || - pkg == definitions.ScalaPackageClass || { - val pkgname = pkg.fullName - (pkgname startsWith "scala.") && !(pkgname startsWith "scala.tools") - } - - /** Invalidates packages that contain classes defined in a classpath entry, and - * rescans that entry. - * @param paths Fully qualified names that refer to directories or jar files that are - * a entries on the classpath. - * First, causes the classpath entry referred to by `path` to be rescanned, so that - * any new files or deleted files or changes in subpackages are picked up. - * Second, invalidates any packages for which one of the following considitions is met: - - * - the classpath entry contained during the last compilation run classfiles - * that represent a member in the package - * - the classpath entry now contains classfiles - * that represent a member in the package - * - the set of subpackages has changed. - * - * The invalidated packages are reset in their entirety; all member classes and member packages - * are re-accessed using the new classpath. - * Not invalidated are system packages that the compiler needs to access as parts - * of standard definitions. The criterion what is a system package is currently: - * any package rooted in "scala", with the exception of packages rooted in "scala.tools". - * This can be refined later. - * @return A pair consisting of - * - a list of invalidated packages - * - a list of of packages that should have been invalidated but were not because - * they are system packages. - */ - def invalidateClassPathEntries(paths: String*): (List[ClassSymbol], List[ClassSymbol]) = { - val invalidated, failed = new mutable.ListBuffer[ClassSymbol] - classPath match { - case cp: MergedClassPath[_] => - def assoc(path: String): List[(PlatformClassPath, PlatformClassPath)] = { - val dir = AbstractFile getDirectory path - val canonical = dir.canonicalPath - def matchesCanonical(e: ClassPath[_]) = e.origin match { - case Some(opath) => - (AbstractFile getDirectory opath).canonicalPath == canonical - case None => - false - } - cp.entries find matchesCanonical match { - case Some(oldEntry) => - List(oldEntry -> cp.context.newClassPath(dir)) - case None => - println(s"canonical = $canonical, origins = ${cp.entries map (_.origin)}") - error(s"cannot invalidate: no entry named $path in classpath $classPath") - List() - } - } - val subst = Map(paths flatMap assoc: _*) - if (subst.nonEmpty) { - platform updateClassPath subst - informProgress(s"classpath updated on entries [${subst.keys mkString ","}]") - def mkClassPath(elems: Iterable[PlatformClassPath]): PlatformClassPath = - if (elems.size == 1) elems.head - else new MergedClassPath(elems, classPath.context) - val oldEntries = mkClassPath(subst.keys) - val newEntries = mkClassPath(subst.values) - reSync(RootClass, Some(classPath), Some(oldEntries), Some(newEntries), invalidated, failed) - } - } - def show(msg: String, syms: scala.collection.Traversable[Symbol]) = - if (syms.nonEmpty) - informProgress(s"$msg: ${syms map (_.fullName) mkString ","}") - show("invalidated packages", invalidated) - show("could not invalidate system packages", failed) - (invalidated.toList, failed.toList) - } - - /** Re-syncs symbol table with classpath - * @param root The root symbol to be resynced (a package class) - * @param allEntries Optionally, the corresponding package in the complete current classPath - * @param oldEntries Optionally, the corresponding package in the old classPath entries - * @param newEntries Optionally, the corresponding package in the new classPath entries - * @param invalidated A listbuffer collecting the invalidated package classes - * @param failed A listbuffer collecting system package classes which could not be invalidated - * The resyncing strategy is determined by the absence or presence of classes and packages. - * If either oldEntries or newEntries contains classes, root is invalidated, provided a corresponding package - * exists in allEntries, or otherwise is removed. - * Otherwise, the action is determined by the following matrix, with columns: - * - * old new all sym action - * + + + + recurse into all child packages of old ++ new - * + - + + invalidate root - * + - - + remove root from its scope - * - + + + invalidate root - * - + + - create and enter root - * - - * * no action - * - * Here, old, new, all mean classpaths and sym means symboltable. + is presence of an - * entry in its column, - is absence, * is don't care. - * - * Note that new <= all and old <= sym, so the matrix above covers all possibilities. - */ - private def reSync(root: ClassSymbol, - allEntries: OptClassPath, oldEntries: OptClassPath, newEntries: OptClassPath, - invalidated: mutable.ListBuffer[ClassSymbol], failed: mutable.ListBuffer[ClassSymbol]) { - ifDebug(informProgress(s"syncing $root, $oldEntries -> $newEntries")) - - val getName: ClassPath[AbstractFile] => String = (_.name) - def hasClasses(cp: OptClassPath) = cp.isDefined && cp.get.classes.nonEmpty - def invalidateOrRemove(root: ClassSymbol) = { - allEntries match { - case Some(cp) => root setInfo new loaders.PackageLoader(cp) - case None => root.owner.info.decls unlink root.sourceModule - } - invalidated += root - } - def packageNames(cp: PlatformClassPath): Set[String] = cp.packages.toSet map getName - def subPackage(cp: PlatformClassPath, name: String): OptClassPath = - cp.packages find (cp1 => getName(cp1) == name) - - val classesFound = hasClasses(oldEntries) || hasClasses(newEntries) - if (classesFound && !isSystemPackageClass(root)) { - invalidateOrRemove(root) - } else { - if (classesFound) { - if (root.isRoot) invalidateOrRemove(EmptyPackageClass) - else failed += root - } - (oldEntries, newEntries) match { - case (Some(oldcp) , Some(newcp)) => - for (pstr <- packageNames(oldcp) ++ packageNames(newcp)) { - val pname = newTermName(pstr) - val pkg = (root.info decl pname) orElse { - // package was created by external agent, create symbol to track it - assert(!subPackage(oldcp, pstr).isDefined) - loaders.enterPackage(root, pstr, new loaders.PackageLoader(allEntries.get)) - } - reSync( - pkg.moduleClass.asInstanceOf[ClassSymbol], - subPackage(allEntries.get, pstr), subPackage(oldcp, pstr), subPackage(newcp, pstr), - invalidated, failed) - } - case (Some(oldcp), None) => - invalidateOrRemove(root) - case (None, Some(newcp)) => - invalidateOrRemove(root) - case (None, None) => - } - } - } - - /** Invalidate contents of setting -Yinvalidate */ - def doInvalidation() = settings.Yinvalidate.value match { - case "" => - case entry => invalidateClassPathEntries(entry) - } - // ----------- Runs --------------------------------------- private var curRun: Run = null private var curRunId = 0 - /** A hook that lets subclasses of `Global` define whether a package or class should be kept loaded for the - * next compiler run. If the parameter `sym` is a class or object, and `clearOnNextRun(sym)` returns `true`, - * then the symbol is unloaded and reset to its state before the last compiler run. If the parameter `sym` is - * a package, and clearOnNextRun(sym)` returns `true`, the package is recursively searched for - * classes to drop. - * - * Example: Let's say I want a compiler that drops all classes corresponding to the current project - * between runs. Then `keepForNextRun` of a toplevel class or object should return `true` if the - * class or object does not form part of the current project, `false` otherwise. For a package, - * clearOnNextRun should return `true` if no class in that package forms part of the current project, - * `false` otherwise. - * - * @param sym A class symbol, object symbol, package, or package class. - */ - @deprecated("use invalidateClassPathEntries instead", "2.10.0") - def clearOnNextRun(sym: Symbol) = false - /* To try out clearOnNext run on the scala.tools.nsc project itself - * replace `false` above with the following code - - settings.Xexperimental.value && { sym.isRoot || { - sym.fullName match { - case "scala" | "scala.tools" | "scala.tools.nsc" => true - case _ => sym.owner.fullName.startsWith("scala.tools.nsc") - } - }} - - * Then, fsc -Xexperimental clears the nsc project between successive runs of `fsc`. - */ - object typeDeconstruct extends { val global: Global.this.type = Global.this } with typechecker.StructuredTypeStrings @@ -1155,7 +979,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** A Run is a single execution of the compiler on a set of units. */ - class Run extends RunContextApi with RunReporting { + class Run extends RunContextApi with RunReporting with RunParsing { /** Have been running into too many init order issues with Run * during erroneous conditions. Moved all these vals up to the * top of the file so at least they're not trivially null. @@ -1292,47 +1116,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) first } - /** Reset all classes contained in current project, as determined by - * the clearOnNextRun hook - */ - @deprecated("use invalidateClassPathEntries instead", "2.10.0") - def resetProjectClasses(root: Symbol): Unit = try { - def unlink(sym: Symbol) = - if (sym != NoSymbol) root.info.decls.unlink(sym) - if (settings.verbose) inform("[reset] recursing in "+root) - val toReload = mutable.Set[String]() - for (sym <- root.info.decls) { - if (sym.isInitialized && clearOnNextRun(sym)) - if (sym.hasPackageFlag) { - resetProjectClasses(sym.moduleClass) - openPackageModule(sym.moduleClass) - } else { - unlink(sym) - unlink(root.info.decls.lookup( - if (sym.isTerm) sym.name.toTypeName else sym.name.toTermName)) - toReload += sym.fullName - // note: toReload could be set twice with the same name - // but reinit must happen only once per name. That's why - // the following classPath.findClass { ... } code cannot be moved here. - } - } - for (fullname <- toReload) - classPath.findClass(fullname) match { - case Some(classRep) => - if (settings.verbose) inform("[reset] reinit "+fullname) - loaders.initializeFromClassPath(root, classRep) - case _ => - } - } catch { - case ex: Throwable => - // this handler should not be nessasary, but it seems that `fsc` - // eats exceptions if they appear here. Need to find out the cause for - // this and fix it. - inform("[reset] exception happened: "+ex) - ex.printStackTrace() - throw ex - } - // --------------- Miscellania ------------------------------- /** Progress tracking. Measured in "progress units" which are 1 per @@ -1397,7 +1180,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val erasurePhase = phaseNamed("erasure") val posterasurePhase = phaseNamed("posterasure") // val lazyvalsPhase = phaseNamed("lazyvals") - // val lambdaliftPhase = phaseNamed("lambdalift") + val lambdaliftPhase = phaseNamed("lambdalift") // val constructorsPhase = phaseNamed("constructors") val flattenPhase = phaseNamed("flatten") val mixinPhase = phaseNamed("mixin") @@ -1542,8 +1325,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) compileUnitsInternal(units, fromPhase) private def compileUnitsInternal(units: List[CompilationUnit], fromPhase: Phase) { - doInvalidation() - units foreach addUnit val startTime = currentTime @@ -1619,13 +1400,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) // Clear any sets or maps created via perRunCaches. perRunCaches.clearAll() - - // Reset project - if (!stopPhase("namer")) { - enteringPhase(namerPhase) { - resetProjectClasses(RootClass) - } - } } /** Compile list of abstract files. */ |