diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/Global.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 244 |
1 files changed, 117 insertions, 127 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index c1d7176d0c..7417d9c09d 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -7,17 +7,17 @@ package scala package tools package nsc -import java.io.{ File, IOException, FileNotFoundException } +import java.io.{File, FileNotFoundException, IOException} import java.net.URL -import java.nio.charset.{ Charset, CharsetDecoder, IllegalCharsetNameException, UnsupportedCharsetException } -import scala.collection.{ mutable, immutable } -import io.{ SourceReader, AbstractFile, Path } +import java.nio.charset.{Charset, CharsetDecoder, IllegalCharsetNameException, UnsupportedCharsetException} +import scala.collection.{immutable, mutable} +import io.{AbstractFile, Path, SourceReader} import reporters.Reporter -import util.{ ClassFileLookup, ClassPath, MergedClassPath, StatisticsInfo, returning } +import util.{ClassPath, StatisticsInfo, returning} import scala.reflect.ClassTag -import scala.reflect.internal.util.{ ScalaClassLoader, SourceFile, NoSourceFile, BatchSourceFile, ScriptSourceFile } +import scala.reflect.internal.util.{BatchSourceFile, NoSourceFile, ScalaClassLoader, ScriptSourceFile, SourceFile} import scala.reflect.internal.pickling.PickleBuffer -import symtab.{ Flags, SymbolTable, SymbolTrackers } +import symtab.{Flags, SymbolTable, SymbolTrackers} import symtab.classfile.Pickler import plugins.Plugins import ast._ @@ -25,12 +25,11 @@ import ast.parser._ import typechecker._ import transform.patmat.PatternMatching import transform._ -import backend.{ ScalaPrimitives, JavaPlatform } +import backend.{JavaPlatform, ScalaPrimitives} import backend.jvm.GenBCode import scala.language.postfixOps import scala.tools.nsc.ast.{TreeGen => AstTreeGen} -import scala.tools.nsc.classpath.FlatClassPath -import scala.tools.nsc.settings.ClassPathRepresentationType +import scala.tools.nsc.classpath._ class Global(var currentSettings: Settings, var reporter: Reporter) extends SymbolTable @@ -54,12 +53,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) class GlobalMirror extends Roots(NoSymbol) { val universe: self.type = self - def rootLoader: LazyType = { - settings.YclasspathImpl.value match { - case ClassPathRepresentationType.Flat => new loaders.PackageLoaderUsingFlatClassPath(FlatClassPath.RootPackage, flatClassPath) - case ClassPathRepresentationType.Recursive => new loaders.PackageLoader(recursiveClassPath) - } - } + def rootLoader: LazyType = new loaders.PackageLoader(ClassPath.RootPackage, classPath) override def toString = "compiler mirror" } implicit val MirrorTag: ClassTag[Mirror] = ClassTag[Mirror](classOf[GlobalMirror]) @@ -102,17 +96,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) type ThisPlatform = JavaPlatform { val global: Global.this.type } lazy val platform: ThisPlatform = new GlobalPlatform - type PlatformClassPath = ClassPath[AbstractFile] - type OptClassPath = Option[PlatformClassPath] - - def classPath: ClassFileLookup[AbstractFile] = settings.YclasspathImpl.value match { - case ClassPathRepresentationType.Flat => flatClassPath - case ClassPathRepresentationType.Recursive => recursiveClassPath - } - - private def recursiveClassPath: ClassPath[AbstractFile] = platform.classPath - - private def flatClassPath: FlatClassPath = platform.flatClassPath + def classPath: ClassPath = platform.classPath // sub-components -------------------------------------------------- @@ -286,7 +270,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) // Over 200 closure objects are eliminated by inlining this. @inline final def log(msg: => AnyRef) { if (shouldLogAtThisPhase) - inform("[log %s%s] %s".format(globalPhase, atPhaseStackMessage, msg)) + inform(s"[log $globalPhase$atPhaseStackMessage] $msg") } @inline final override def debuglog(msg: => String) { @@ -308,10 +292,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter) try Some(Charset.forName(name)) catch { case _: IllegalCharsetNameException => - globalError("illegal charset name '" + name + "'") + globalError(s"illegal charset name '$name'") None case _: UnsupportedCharsetException => - globalError("unsupported charset '" + name + "'") + globalError(s"unsupported charset '$name'") None } @@ -397,15 +381,18 @@ class Global(var currentSettings: Settings, var reporter: Reporter) if (settings.debug && (settings.verbose || currentRun.size < 5)) inform("[running phase " + name + " on " + unit + "]") + if (!cancelled(unit)) { + currentRun.informUnitStarting(this, unit) + try withCurrentUnitNoLog(unit)(task) + finally currentRun.advanceUnit() + } + } + final def withCurrentUnitNoLog(unit: CompilationUnit)(task: => Unit) { val unit0 = currentUnit try { currentRun.currentUnit = unit - if (!cancelled(unit)) { - currentRun.informUnitStarting(this, unit) - task - } - currentRun.advanceUnit() + task } finally { //assert(currentUnit == unit) currentRun.currentUnit = unit0 @@ -771,12 +758,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** Extend classpath of `platform` and rescan updated packages. */ def extendCompilerClassPath(urls: URL*): Unit = { - if (settings.YclasspathImpl.value == ClassPathRepresentationType.Flat) - throw new UnsupportedOperationException("Flat classpath doesn't support extending the compiler classpath") - - val newClassPath = platform.classPath.mergeUrlsIntoClassPath(urls: _*) + val urlClasspaths = urls.map(u => ClassPathFactory.newClassPath(AbstractFile.getURL(u), settings)) + val newClassPath = AggregateClassPath.createAggregate(platform.classPath +: urlClasspaths : _*) platform.currentClassPath = Some(newClassPath) - // Reload all specified jars into this compiler instance invalidateClassPathEntries(urls.map(_.getPath): _*) } @@ -809,43 +793,54 @@ class Global(var currentSettings: Settings, var reporter: Reporter) * entries on the classpath. */ def invalidateClassPathEntries(paths: String*): Unit = { - if (settings.YclasspathImpl.value == ClassPathRepresentationType.Flat) - throw new UnsupportedOperationException("Flat classpath doesn't support the classpath invalidation") - - implicit object ClassPathOrdering extends Ordering[PlatformClassPath] { - def compare(a:PlatformClassPath, b:PlatformClassPath) = a.asClassPathString compare b.asClassPathString + implicit object ClassPathOrdering extends Ordering[ClassPath] { + def compare(a: ClassPath, b: ClassPath): Int = a.asClassPathString compareTo b.asClassPathString } 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 => - error(s"Error adding entry to classpath. During invalidation, no entry named $path in classpath $classPath") - List() - } - } - val subst = immutable.TreeMap(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, recursiveClassPath.context) - val oldEntries = mkClassPath(subst.keys) - val newEntries = mkClassPath(subst.values) - mergeNewEntries(newEntries, RootClass, Some(recursiveClassPath), Some(oldEntries), invalidated, failed) - } + + def assoc(path: String): Option[(ClassPath, ClassPath)] = { + def origin(lookup: ClassPath): Option[String] = lookup match { + case cp: JFileDirectoryLookup[_] => Some(cp.dir.getPath) + case cp: ZipArchiveFileLookup[_] => Some(cp.zipFile.getPath) + case _ => None + } + + def entries(lookup: ClassPath): Seq[ClassPath] = lookup match { + case cp: AggregateClassPath => cp.aggregates + case cp: ClassPath => Seq(cp) + } + + val dir = AbstractFile.getDirectory(path) // if path is a `jar`, this is a FileZipArchive (isDirectory is true) + val canonical = dir.canonicalPath // this is the canonical path of the .jar + def matchesCanonical(e: ClassPath) = origin(e) match { + case Some(opath) => + AbstractFile.getDirectory(opath).canonicalPath == canonical + case None => + false + } + entries(classPath) find matchesCanonical match { + case Some(oldEntry) => + Some(oldEntry -> ClassPathFactory.newClassPath(dir, settings)) + case None => + error(s"Error adding entry to classpath. During invalidation, no entry named $path in classpath $classPath") + None + } + } + val subst = immutable.TreeMap(paths flatMap assoc: _*) + if (subst.nonEmpty) { + platform updateClassPath subst + informProgress(s"classpath updated on entries [${subst.keys mkString ","}]") + def mkClassPath(elems: Iterable[ClassPath]): ClassPath = + if (elems.size == 1) elems.head + else AggregateClassPath.createAggregate(elems.toSeq: _*) + val oldEntries = mkClassPath(subst.keys) + val newEntries = mkClassPath(subst.values) + classPath match { + case cp: ClassPath => mergeNewEntries( + RootClass, "", + oldEntries, newEntries, cp, + invalidated, failed) + } } def show(msg: String, syms: scala.collection.Traversable[Symbol]) = if (syms.nonEmpty) @@ -854,66 +849,61 @@ class Global(var currentSettings: Settings, var reporter: Reporter) show("could not invalidate system packages", failed) } - /** Merges new classpath entries into the symbol table - * - * @param newEntries The new classpath entries - * @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 invalidated A listbuffer collecting the invalidated package classes - * @param failed A listbuffer collecting system package classes which could not be invalidated - * - * The merging strategy is determined by the absence or presence of classes and packages. + /** + * Merges new classpath entries into the symbol table * - * If either oldEntries or newEntries contains classes, root is invalidated provided that a corresponding package - * exists in allEntries. Otherwise it is removed. - * Otherwise, the action is determined by the following matrix, with columns: + * @param packageClass The ClassSymbol for the package being updated + * @param fullPackageName The full name of the package being updated + * @param oldEntries The classpath that was removed, it is no longer part of fullClasspath + * @param newEntries The classpath that was added, it is already part of fullClasspath + * @param fullClasspath The full classpath, equivalent to global.classPath + * @param invalidated A ListBuffer collecting the invalidated package classes + * @param failed A ListBuffer collecting system package classes which could not be invalidated * - * old sym action - * + + recurse into all child packages of newEntries - * - + invalidate root - * - - create and enter root + * If either oldEntries or newEntries contains classes in the current package, the package symbol + * is re-initialized to a fresh package loader, provided that a corresponding package exists in + * fullClasspath. Otherwise it is removed. * - * Here, old means classpath, and sym means symboltable. + is presence of an entry in its column, - is absence. + * Otherwise, sub-packages in newEntries are looked up in the symbol table (created if + * non-existent) and the merge function is called recursively. */ - private def mergeNewEntries(newEntries: PlatformClassPath, root: ClassSymbol, - allEntries: OptClassPath, oldEntries: 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 + private def mergeNewEntries(packageClass: ClassSymbol, fullPackageName: String, + oldEntries: ClassPath, newEntries: ClassPath, fullClasspath: ClassPath, + invalidated: mutable.ListBuffer[ClassSymbol], failed: mutable.ListBuffer[ClassSymbol]): Unit = { + ifDebug(informProgress(s"syncing $packageClass, $oldEntries -> $newEntries")) + + def packageExists(cp: ClassPath): Boolean = { + val (parent, _) = PackageNameUtils.separatePkgAndClassNames(fullPackageName) + cp.packages(parent).exists(_.name == fullPackageName) } - def subPackage(cp: PlatformClassPath, name: String): OptClassPath = - cp.packages find (cp1 => getName(cp1) == name) - val classesFound = hasClasses(oldEntries) || newEntries.classes.nonEmpty - if (classesFound && !isSystemPackageClass(root)) { - invalidateOrRemove(root) - } else { - if (classesFound) { - if (root.isRoot) invalidateOrRemove(EmptyPackageClass) - else failed += root - } - if (!oldEntries.isDefined) invalidateOrRemove(root) + def invalidateOrRemove(pkg: ClassSymbol) = { + if (packageExists(fullClasspath)) + pkg setInfo new loaders.PackageLoader(fullPackageName, fullClasspath) else - for (pstr <- newEntries.packages.map(getName)) { - val pname = newTermName(pstr) - val pkg = (root.info decl pname) orElse { - // package does not exist in symbol table, create symbol to track it - assert(!subPackage(oldEntries.get, pstr).isDefined) - loaders.enterPackage(root, pstr, new loaders.PackageLoader(allEntries.get)) - } - mergeNewEntries(subPackage(newEntries, pstr).get, pkg.moduleClass.asClass, - subPackage(allEntries.get, pstr), subPackage(oldEntries.get, pstr), - invalidated, failed) + pkg.owner.info.decls unlink pkg.sourceModule + invalidated += pkg + } + + val classesFound = oldEntries.classes(fullPackageName).nonEmpty || newEntries.classes(fullPackageName).nonEmpty + if (classesFound) { + // if the package contains classes either in oldEntries or newEntries, the package is invalidated (or removed if there are no more classes in it) + if (!isSystemPackageClass(packageClass)) invalidateOrRemove(packageClass) + else if (packageClass.isRoot) invalidateOrRemove(EmptyPackageClass) + else failed += packageClass + } else { + // no new or removed classes in the current package + for (p <- newEntries.packages(fullPackageName)) { + val (_, subPackageName) = PackageNameUtils.separatePkgAndClassNames(p.name) + val subPackage = packageClass.info.decl(newTermName(subPackageName)) orElse { + // package does not exist in symbol table, create a new symbol + loaders.enterPackage(packageClass, subPackageName, new loaders.PackageLoader(p.name, fullClasspath)) } + mergeNewEntries( + subPackage.moduleClass.asClass, p.name, + oldEntries, newEntries, fullClasspath, + invalidated, failed) + } } } |