summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@typesafe.com>2016-03-23 08:46:32 +0100
committerLukas Rytz <lukas.rytz@typesafe.com>2016-03-23 08:46:32 +0100
commit952da60a5be15ef972b521bdaf5e650f7e0a5245 (patch)
tree41a5f0589f1cc2fa1caba7ca0265782fa0e151fd /src
parent6dbdb09711140c8022a8721c520dd08661bb1fb2 (diff)
parentf8950c1457955835f4411beb8dcb3672f7cd39bd (diff)
downloadscala-952da60a5be15ef972b521bdaf5e650f7e0a5245.tar.gz
scala-952da60a5be15ef972b521bdaf5e650f7e0a5245.tar.bz2
scala-952da60a5be15ef972b521bdaf5e650f7e0a5245.zip
Merge pull request #5057 from lrytz/flatClasspath
Enable -YclasspathImpl:flat by default
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala205
-rw-r--r--src/compiler/scala/tools/nsc/backend/JavaPlatform.scala25
-rw-r--r--src/compiler/scala/tools/nsc/backend/Platform.scala4
-rw-r--r--src/compiler/scala/tools/nsc/classpath/AggregateFlatClassPath.scala22
-rw-r--r--src/compiler/scala/tools/nsc/classpath/DirectoryFlatClassPath.scala148
-rw-r--r--src/compiler/scala/tools/nsc/classpath/FileUtils.scala6
-rw-r--r--src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala9
-rw-r--r--src/compiler/scala/tools/nsc/classpath/FlatClassPathFactory.scala25
-rw-r--r--src/compiler/scala/tools/nsc/classpath/VirtualDirectoryFlatClassPath.scala39
-rw-r--r--src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala8
-rw-r--r--src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala2
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/util/ClassFileLookup.scala21
-rw-r--r--src/compiler/scala/tools/nsc/util/ClassPath.scala9
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ILoop.scala4
-rw-r--r--src/repl/scala/tools/nsc/interpreter/PresentationCompilation.scala34
16 files changed, 361 insertions, 202 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index c1d7176d0c..1a794f7554 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.{ClassFileLookup, 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,11 +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.classpath._
import scala.tools.nsc.settings.ClassPathRepresentationType
class Global(var currentSettings: Settings, var reporter: Reporter)
@@ -102,9 +102,6 @@ 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
@@ -771,13 +768,17 @@ 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: _*)
- platform.currentClassPath = Some(newClassPath)
- // Reload all specified jars into this compiler instance
- invalidateClassPathEntries(urls.map(_.getPath): _*)
+ if (settings.YclasspathImpl.value == ClassPathRepresentationType.Flat) {
+ val urlClasspaths = urls.map(u => FlatClassPathFactory.newClassPath(AbstractFile.getURL(u), settings))
+ val newClassPath = AggregateFlatClassPath.createAggregate(platform.flatClassPath +: urlClasspaths : _*)
+ platform.currentFlatClassPath = Some(newClassPath)
+ invalidateClassPathEntries(urls.map(_.getPath): _*)
+ } else {
+ val newClassPath = platform.classPath.mergeUrlsIntoClassPath(urls: _*)
+ platform.currentClassPath = Some(newClassPath)
+ // Reload all specified jars into this compiler instance
+ invalidateClassPathEntries(urls.map(_.getPath): _*)
+ }
}
// ------------ Invalidations ---------------------------------
@@ -809,43 +810,60 @@ 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[ClassFileLookup[AbstractFile]] {
+ def compare(a:ClassFileLookup[AbstractFile], b:ClassFileLookup[AbstractFile]) = a.asClassPathString compare 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[(ClassFileLookup[AbstractFile], ClassFileLookup[AbstractFile])] = {
+ def origin(lookup: ClassFileLookup[AbstractFile]): Option[String] = lookup match {
+ case cp: ClassPath[_] => cp.origin
+ case cp: JFileDirectoryLookup[_] => Some(cp.dir.getPath)
+ case cp: ZipArchiveFileLookup[_] => Some(cp.zipFile.getPath)
+ case _ => None
+ }
+
+ def entries(lookup: ClassFileLookup[AbstractFile]): Seq[ClassFileLookup[AbstractFile]] = lookup match {
+ case cp: ClassPath[_] => cp.entries
+ case cp: AggregateFlatClassPath => cp.aggregates
+ case cp: FlatClassPath => 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: ClassFileLookup[AbstractFile]) = origin(e) match {
+ case Some(opath) =>
+ AbstractFile.getDirectory(opath).canonicalPath == canonical
+ case None =>
+ false
+ }
+ entries(classPath) find matchesCanonical match {
+ case Some(oldEntry) =>
+ Some(oldEntry -> ClassFileLookup.createForFile(dir, classPath, 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[ClassFileLookup[AbstractFile]]): ClassFileLookup[AbstractFile] =
+ if (elems.size == 1) elems.head
+ else ClassFileLookup.createAggregate(elems, classPath)
+ val oldEntries = mkClassPath(subst.keys)
+ val newEntries = mkClassPath(subst.values)
+ classPath match {
+ case rcp: ClassPath[_] => mergeNewEntriesRecursive(
+ newEntries.asInstanceOf[ClassPath[AbstractFile]], RootClass, Some(rcp), Some(oldEntries.asInstanceOf[ClassPath[AbstractFile]]),
+ invalidated, failed)
+
+ case fcp: FlatClassPath => mergeNewEntriesFlat(
+ RootClass, "",
+ oldEntries.asInstanceOf[FlatClassPath], newEntries.asInstanceOf[FlatClassPath], fcp,
+ invalidated, failed)
+ }
}
def show(msg: String, syms: scala.collection.Traversable[Symbol]) =
if (syms.nonEmpty)
@@ -876,13 +894,13 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
*
* Here, old means classpath, and sym means symboltable. + is presence of an entry in its column, - is absence.
*/
- private def mergeNewEntries(newEntries: PlatformClassPath, root: ClassSymbol,
- allEntries: OptClassPath, oldEntries: OptClassPath,
+ private def mergeNewEntriesRecursive(newEntries: ClassPath[AbstractFile], root: ClassSymbol,
+ allEntries: Option[ClassPath[AbstractFile]], oldEntries: Option[ClassPath[AbstractFile]],
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
+ val getPackageName: ClassPath[AbstractFile] => String = _.name
+ def hasClasses(cp: Option[ClassPath[AbstractFile]]) = cp.isDefined && cp.get.classes.nonEmpty
def invalidateOrRemove(root: ClassSymbol) = {
allEntries match {
case Some(cp) => root setInfo new loaders.PackageLoader(cp)
@@ -890,8 +908,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
}
invalidated += root
}
- def subPackage(cp: PlatformClassPath, name: String): OptClassPath =
- cp.packages find (cp1 => getName(cp1) == name)
+ def subPackage(cp: ClassPath[AbstractFile], name: String): Option[ClassPath[AbstractFile]] =
+ cp.packages find (cp1 => getPackageName(cp1) == name)
val classesFound = hasClasses(oldEntries) || newEntries.classes.nonEmpty
if (classesFound && !isSystemPackageClass(root)) {
@@ -901,22 +919,81 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
if (root.isRoot) invalidateOrRemove(EmptyPackageClass)
else failed += root
}
- if (!oldEntries.isDefined) invalidateOrRemove(root)
+ if (oldEntries.isEmpty) invalidateOrRemove(root)
else
- for (pstr <- newEntries.packages.map(getName)) {
+ for (pstr <- newEntries.packages.map(getPackageName)) {
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)
+ assert(subPackage(oldEntries.get, pstr).isEmpty)
loaders.enterPackage(root, pstr, new loaders.PackageLoader(allEntries.get))
}
- mergeNewEntries(subPackage(newEntries, pstr).get, pkg.moduleClass.asClass,
+ mergeNewEntriesRecursive(subPackage(newEntries, pstr).get, pkg.moduleClass.asClass,
subPackage(allEntries.get, pstr), subPackage(oldEntries.get, pstr),
invalidated, failed)
}
}
}
+ /**
+ * Merges new classpath entries into the symbol table
+ *
+ * @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
+ *
+ * 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.
+ *
+ * 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 mergeNewEntriesFlat(
+ packageClass: ClassSymbol, fullPackageName: String,
+ oldEntries: FlatClassPath, newEntries: FlatClassPath, fullClasspath: FlatClassPath,
+ invalidated: mutable.ListBuffer[ClassSymbol], failed: mutable.ListBuffer[ClassSymbol]): Unit = {
+ ifDebug(informProgress(s"syncing $packageClass, $oldEntries -> $newEntries"))
+
+ def packageExists(cp: FlatClassPath): Boolean = {
+ val (parent, _) = PackageNameUtils.separatePkgAndClassNames(fullPackageName)
+ cp.packages(parent).exists(_.name == fullPackageName)
+ }
+
+ def invalidateOrRemove(pkg: ClassSymbol) = {
+ if (packageExists(fullClasspath))
+ pkg setInfo new loaders.PackageLoaderUsingFlatClassPath(fullPackageName, fullClasspath)
+ else
+ 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.PackageLoaderUsingFlatClassPath(p.name, fullClasspath))
+ }
+ mergeNewEntriesFlat(
+ subPackage.moduleClass.asClass, p.name,
+ oldEntries, newEntries, fullClasspath,
+ invalidated, failed)
+ }
+ }
+ }
+
// ----------- Runs ---------------------------------------
private var curRun: Run = null
diff --git a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
index 16f086e9e7..0e2f059a36 100644
--- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
+++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
@@ -7,9 +7,9 @@ package scala.tools.nsc
package backend
import io.AbstractFile
-import scala.tools.nsc.classpath.FlatClassPath
+import scala.tools.nsc.classpath.{AggregateFlatClassPath, FlatClassPath}
import scala.tools.nsc.settings.ClassPathRepresentationType
-import scala.tools.nsc.util.{ ClassPath, DeltaClassPath, MergedClassPath }
+import scala.tools.nsc.util.{ClassFileLookup, ClassPath, MergedClassPath}
import scala.tools.util.FlatClassPathResolver
import scala.tools.util.PathResolver
@@ -29,16 +29,29 @@ trait JavaPlatform extends Platform {
currentClassPath.get
}
- private[nsc] lazy val flatClassPath: FlatClassPath = {
+ private[nsc] var currentFlatClassPath: Option[FlatClassPath] = None
+
+ private[nsc] def flatClassPath: FlatClassPath = {
assert(settings.YclasspathImpl.value == ClassPathRepresentationType.Flat,
"To use flat classpath representation you must enable it with -YclasspathImpl:flat compiler option.")
- new FlatClassPathResolver(settings).result
+ if (currentFlatClassPath.isEmpty) currentFlatClassPath = Some(new FlatClassPathResolver(settings).result)
+ currentFlatClassPath.get
}
/** Update classpath with a substituted subentry */
- def updateClassPath(subst: Map[ClassPath[AbstractFile], ClassPath[AbstractFile]]) =
- currentClassPath = Some(new DeltaClassPath(currentClassPath.get, subst))
+ def updateClassPath(subst: Map[ClassFileLookup[AbstractFile], ClassFileLookup[AbstractFile]]) = global.classPath match {
+ case cp: ClassPath[AbstractFile] =>
+ val s = subst.asInstanceOf[Map[ClassPath[AbstractFile], ClassPath[AbstractFile]]]
+ currentClassPath = Some(new MergedClassPath(cp.entries map (e => s.getOrElse(e, e)), cp.context))
+
+ case AggregateFlatClassPath(entries) =>
+ val s = subst.asInstanceOf[Map[FlatClassPath, FlatClassPath]]
+ currentFlatClassPath = Some(AggregateFlatClassPath(entries map (e => s.getOrElse(e, e))))
+
+ case cp: FlatClassPath =>
+ currentFlatClassPath = Some(subst.getOrElse(cp, cp).asInstanceOf[FlatClassPath])
+ }
def platformPhases = List(
flatten, // get rid of inner classes
diff --git a/src/compiler/scala/tools/nsc/backend/Platform.scala b/src/compiler/scala/tools/nsc/backend/Platform.scala
index c3bc213be1..369bcc44ed 100644
--- a/src/compiler/scala/tools/nsc/backend/Platform.scala
+++ b/src/compiler/scala/tools/nsc/backend/Platform.scala
@@ -6,7 +6,7 @@
package scala.tools.nsc
package backend
-import util.ClassPath
+import util.{ClassFileLookup, ClassPath}
import io.AbstractFile
import scala.tools.nsc.classpath.FlatClassPath
@@ -23,7 +23,7 @@ trait Platform {
private[nsc] def flatClassPath: FlatClassPath
/** Update classpath with a substitution that maps entries to entries */
- def updateClassPath(subst: Map[ClassPath[AbstractFile], ClassPath[AbstractFile]])
+ def updateClassPath(subst: Map[ClassFileLookup[AbstractFile], ClassFileLookup[AbstractFile]])
/** Any platform-specific phases. */
def platformPhases: List[SubComponent]
diff --git a/src/compiler/scala/tools/nsc/classpath/AggregateFlatClassPath.scala b/src/compiler/scala/tools/nsc/classpath/AggregateFlatClassPath.scala
index 3f06264e3c..f97d97548e 100644
--- a/src/compiler/scala/tools/nsc/classpath/AggregateFlatClassPath.scala
+++ b/src/compiler/scala/tools/nsc/classpath/AggregateFlatClassPath.scala
@@ -18,7 +18,6 @@ import scala.tools.nsc.util.ClassRepresentation
* @param aggregates classpath instances containing entries which this class processes
*/
case class AggregateFlatClassPath(aggregates: Seq[FlatClassPath]) extends FlatClassPath {
-
override def findClassFile(className: String): Option[AbstractFile] = {
@tailrec
def find(aggregates: Seq[FlatClassPath]): Option[AbstractFile] =
@@ -37,8 +36,7 @@ case class AggregateFlatClassPath(aggregates: Seq[FlatClassPath]) extends FlatCl
@tailrec
def findEntry[T <: ClassRepClassPathEntry](aggregates: Seq[FlatClassPath], getEntries: FlatClassPath => Seq[T]): Option[T] =
if (aggregates.nonEmpty) {
- val entry = getEntries(aggregates.head)
- .find(_.name == simpleClassName)
+ val entry = getEntries(aggregates.head).find(_.name == simpleClassName)
if (entry.isDefined) entry
else findEntry(aggregates.tail, getEntries)
} else None
@@ -46,7 +44,11 @@ case class AggregateFlatClassPath(aggregates: Seq[FlatClassPath]) extends FlatCl
val classEntry = findEntry(aggregates, classesGetter(pkg))
val sourceEntry = findEntry(aggregates, sourcesGetter(pkg))
- mergeClassesAndSources(classEntry.toList, sourceEntry.toList).headOption
+ (classEntry, sourceEntry) match {
+ case (Some(c), Some(s)) => Some(ClassAndSourceFilesEntry(c.file, s.file))
+ case (c @ Some(_), _) => c
+ case (_, s) => s
+ }
}
override def asURLs: Seq[URL] = aggregates.flatMap(_.asURLs)
@@ -123,3 +125,15 @@ case class AggregateFlatClassPath(aggregates: Seq[FlatClassPath]) extends FlatCl
private def classesGetter(pkg: String) = (cp: FlatClassPath) => cp.classes(pkg)
private def sourcesGetter(pkg: String) = (cp: FlatClassPath) => cp.sources(pkg)
}
+
+object AggregateFlatClassPath {
+ def createAggregate(parts: FlatClassPath*): FlatClassPath = {
+ val elems = new ArrayBuffer[FlatClassPath]()
+ parts foreach {
+ case AggregateFlatClassPath(ps) => elems ++= ps
+ case p => elems += p
+ }
+ if (elems.size == 1) elems.head
+ else AggregateFlatClassPath(elems.toIndexedSeq)
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/classpath/DirectoryFlatClassPath.scala b/src/compiler/scala/tools/nsc/classpath/DirectoryFlatClassPath.scala
index 81d2f7320f..e3964dfa78 100644
--- a/src/compiler/scala/tools/nsc/classpath/DirectoryFlatClassPath.scala
+++ b/src/compiler/scala/tools/nsc/classpath/DirectoryFlatClassPath.scala
@@ -4,7 +4,6 @@
package scala.tools.nsc.classpath
import java.io.File
-import java.io.FileFilter
import java.net.URL
import scala.reflect.io.AbstractFile
import scala.reflect.io.PlainFile
@@ -12,97 +11,101 @@ import scala.tools.nsc.util.ClassRepresentation
import FileUtils._
/**
- * A trait allowing to look for classpath entries of given type in directories.
- * It provides common logic for classes handling class and source files.
+ * A trait allowing to look for classpath entries in directories. It provides common logic for
+ * classes handling class and source files.
* It makes use of the fact that in the case of nested directories it's easy to find a file
* when we have a name of a package.
+ * It abstracts over the file representation to work with both JFile and AbstractFile.
*/
-trait DirectoryFileLookup[FileEntryType <: ClassRepClassPathEntry] extends FlatClassPath {
- val dir: File
- assert(dir != null, "Directory file in DirectoryFileLookup cannot be null")
+trait DirectoryLookup[FileEntryType <: ClassRepClassPathEntry] extends FlatClassPath {
+ type F
+
+ val dir: F
+
+ protected def emptyFiles: Array[F] // avoids reifying ClassTag[F]
+ protected def getSubDir(dirName: String): Option[F]
+ protected def listChildren(dir: F, filter: Option[F => Boolean] = None): Array[F]
+ protected def getName(f: F): String
+ protected def toAbstractFile(f: F): AbstractFile
+ protected def isPackage(f: F): Boolean
- override def asURLs: Seq[URL] = Seq(dir.toURI.toURL)
- override def asClassPathStrings: Seq[String] = Seq(dir.getPath)
+ protected def createFileEntry(file: AbstractFile): FileEntryType
+ protected def isMatchingFile(f: F): Boolean
- import FlatClassPath.RootPackage
- private def getDirectory(forPackage: String): Option[File] = {
- if (forPackage == RootPackage) {
+ private def getDirectory(forPackage: String): Option[F] = {
+ if (forPackage == FlatClassPath.RootPackage) {
Some(dir)
} else {
val packageDirName = FileUtils.dirPath(forPackage)
- val packageDir = new File(dir, packageDirName)
- if (packageDir.exists && packageDir.isDirectory) {
- Some(packageDir)
- } else None
+ getSubDir(packageDirName)
}
}
- override private[nsc] def packages(inPackage: String): Seq[PackageEntry] = {
+ private[nsc] def packages(inPackage: String): Seq[PackageEntry] = {
val dirForPackage = getDirectory(inPackage)
- val nestedDirs: Array[File] = dirForPackage match {
- case None => Array.empty
- case Some(directory) => directory.listFiles(DirectoryFileLookup.packageDirectoryFileFilter)
+ val nestedDirs: Array[F] = dirForPackage match {
+ case None => emptyFiles
+ case Some(directory) => listChildren(directory, Some(isPackage))
}
val prefix = PackageNameUtils.packagePrefix(inPackage)
- val entries = nestedDirs map { file =>
- PackageEntryImpl(prefix + file.getName)
- }
- entries
+ nestedDirs.map(f => PackageEntryImpl(prefix + getName(f)))
}
protected def files(inPackage: String): Seq[FileEntryType] = {
val dirForPackage = getDirectory(inPackage)
- val files: Array[File] = dirForPackage match {
- case None => Array.empty
- case Some(directory) => directory.listFiles(fileFilter)
- }
- val entries = files map { file =>
- val wrappedFile = new scala.reflect.io.File(file)
- createFileEntry(new PlainFile(wrappedFile))
+ val files: Array[F] = dirForPackage match {
+ case None => emptyFiles
+ case Some(directory) => listChildren(directory, Some(isMatchingFile))
}
- entries
+ files.map(f => createFileEntry(toAbstractFile(f)))
}
- override private[nsc] def list(inPackage: String): FlatClassPathEntries = {
+ private[nsc] def list(inPackage: String): FlatClassPathEntries = {
val dirForPackage = getDirectory(inPackage)
- val files: Array[File] = dirForPackage match {
- case None => Array.empty
- case Some(directory) => directory.listFiles()
+ val files: Array[F] = dirForPackage match {
+ case None => emptyFiles
+ case Some(directory) => listChildren(directory)
}
val packagePrefix = PackageNameUtils.packagePrefix(inPackage)
val packageBuf = collection.mutable.ArrayBuffer.empty[PackageEntry]
val fileBuf = collection.mutable.ArrayBuffer.empty[FileEntryType]
for (file <- files) {
- if (file.isPackage) {
- val pkgEntry = PackageEntryImpl(packagePrefix + file.getName)
- packageBuf += pkgEntry
- } else if (fileFilter.accept(file)) {
- val wrappedFile = new scala.reflect.io.File(file)
- val abstractFile = new PlainFile(wrappedFile)
- fileBuf += createFileEntry(abstractFile)
- }
+ if (isPackage(file))
+ packageBuf += PackageEntryImpl(packagePrefix + getName(file))
+ else if (isMatchingFile(file))
+ fileBuf += createFileEntry(toAbstractFile(file))
}
FlatClassPathEntries(packageBuf, fileBuf)
}
-
- protected def createFileEntry(file: AbstractFile): FileEntryType
- protected def fileFilter: FileFilter
}
-object DirectoryFileLookup {
+trait JFileDirectoryLookup[FileEntryType <: ClassRepClassPathEntry] extends DirectoryLookup[FileEntryType] {
+ type F = File
- private[classpath] object packageDirectoryFileFilter extends FileFilter {
- override def accept(pathname: File): Boolean = pathname.isPackage
+ protected def emptyFiles: Array[File] = Array.empty
+ protected def getSubDir(packageDirName: String): Option[File] = {
+ val packageDir = new File(dir, packageDirName)
+ if (packageDir.exists && packageDir.isDirectory) Some(packageDir)
+ else None
}
-}
+ protected def listChildren(dir: File, filter: Option[File => Boolean]): Array[File] = filter match {
+ case Some(f) => dir.listFiles(mkFileFilter(f))
+ case None => dir.listFiles()
+ }
+ protected def getName(f: File): String = f.getName
+ protected def toAbstractFile(f: File): AbstractFile = new PlainFile(new scala.reflect.io.File(f))
+ protected def isPackage(f: File): Boolean = f.isPackage
-case class DirectoryFlatClassPath(dir: File)
- extends DirectoryFileLookup[ClassFileEntryImpl]
- with NoSourcePaths {
+ assert(dir != null, "Directory file in DirectoryFileLookup cannot be null")
+ def asURLs: Seq[URL] = Seq(dir.toURI.toURL)
+ def asClassPathStrings: Seq[String] = Seq(dir.getPath)
+}
+
+case class DirectoryFlatClassPath(dir: File) extends JFileDirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = findClassFile(className) map ClassFileEntryImpl
- override def findClassFile(className: String): Option[AbstractFile] = {
+ def findClassFile(className: String): Option[AbstractFile] = {
val relativePath = FileUtils.dirPath(className)
val classFile = new File(s"$dir/$relativePath.class")
if (classFile.exists) {
@@ -112,31 +115,19 @@ case class DirectoryFlatClassPath(dir: File)
} else None
}
- override protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file)
- override protected def fileFilter: FileFilter = DirectoryFlatClassPath.classFileFilter
-
- override private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage)
-}
-
-object DirectoryFlatClassPath {
+ protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file)
+ protected def isMatchingFile(f: File): Boolean = f.isClass
- private val classFileFilter = new FileFilter {
- override def accept(pathname: File): Boolean = pathname.isClass
- }
+ private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage)
}
-case class DirectoryFlatSourcePath(dir: File)
- extends DirectoryFileLookup[SourceFileEntryImpl]
- with NoClassPaths {
+case class DirectoryFlatSourcePath(dir: File) extends JFileDirectoryLookup[SourceFileEntryImpl] with NoClassPaths {
+ def asSourcePathString: String = asClassPathString
- override def asSourcePathString: String = asClassPathString
+ protected def createFileEntry(file: AbstractFile): SourceFileEntryImpl = SourceFileEntryImpl(file)
+ protected def isMatchingFile(f: File): Boolean = endsScalaOrJava(f.getName)
- override protected def createFileEntry(file: AbstractFile): SourceFileEntryImpl = SourceFileEntryImpl(file)
- override protected def fileFilter: FileFilter = DirectoryFlatSourcePath.sourceFileFilter
-
- override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = {
- findSourceFile(className) map SourceFileEntryImpl
- }
+ override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = findSourceFile(className) map SourceFileEntryImpl
private def findSourceFile(className: String): Option[AbstractFile] = {
val relativePath = FileUtils.dirPath(className)
@@ -151,12 +142,5 @@ case class DirectoryFlatSourcePath(dir: File)
}
}
- override private[nsc] def sources(inPackage: String): Seq[SourceFileEntry] = files(inPackage)
-}
-
-object DirectoryFlatSourcePath {
-
- private val sourceFileFilter = new FileFilter {
- override def accept(pathname: File): Boolean = endsScalaOrJava(pathname.getName)
- }
+ private[nsc] def sources(inPackage: String): Seq[SourceFileEntry] = files(inPackage)
}
diff --git a/src/compiler/scala/tools/nsc/classpath/FileUtils.scala b/src/compiler/scala/tools/nsc/classpath/FileUtils.scala
index ee2528e15c..bbcfcb24ca 100644
--- a/src/compiler/scala/tools/nsc/classpath/FileUtils.scala
+++ b/src/compiler/scala/tools/nsc/classpath/FileUtils.scala
@@ -3,7 +3,7 @@
*/
package scala.tools.nsc.classpath
-import java.io.{ File => JFile }
+import java.io.{File => JFile, FileFilter}
import java.net.URL
import scala.reflect.internal.FatalError
import scala.reflect.io.AbstractFile
@@ -65,4 +65,8 @@ object FileUtils {
// because then some tests in partest don't pass
private def mayBeValidPackage(dirName: String): Boolean =
(dirName != "META-INF") && (dirName != "") && (dirName.charAt(0) != '.')
+
+ def mkFileFilter(f: JFile => Boolean) = new FileFilter {
+ def accept(pathname: JFile): Boolean = f(pathname)
+ }
}
diff --git a/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala b/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala
index cb201617d2..e95ffe02e3 100644
--- a/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala
+++ b/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala
@@ -28,11 +28,8 @@ trait FlatClassPath extends ClassFileLookup[AbstractFile] {
override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = {
val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className)
- val foundClassFromClassFiles = classes(pkg)
- .find(_.name == simpleClassName)
-
- def findClassInSources = sources(pkg)
- .find(_.name == simpleClassName)
+ val foundClassFromClassFiles = classes(pkg).find(_.name == simpleClassName)
+ def findClassInSources = sources(pkg).find(_.name == simpleClassName)
foundClassFromClassFiles orElse findClassInSources
}
@@ -50,7 +47,7 @@ case class FlatClassPathEntries(packages: Seq[PackageEntry], classesAndSources:
object FlatClassPathEntries {
import scala.language.implicitConversions
// to have working unzip method
- implicit def entry2Tuple(entry: FlatClassPathEntries) = (entry.packages, entry.classesAndSources)
+ implicit def entry2Tuple(entry: FlatClassPathEntries): (Seq[PackageEntry], Seq[ClassRepClassPathEntry]) = (entry.packages, entry.classesAndSources)
}
sealed trait ClassRepClassPathEntry extends ClassRepresentation[AbstractFile]
diff --git a/src/compiler/scala/tools/nsc/classpath/FlatClassPathFactory.scala b/src/compiler/scala/tools/nsc/classpath/FlatClassPathFactory.scala
index d8ca325885..463301696e 100644
--- a/src/compiler/scala/tools/nsc/classpath/FlatClassPathFactory.scala
+++ b/src/compiler/scala/tools/nsc/classpath/FlatClassPathFactory.scala
@@ -3,6 +3,7 @@
*/
package scala.tools.nsc.classpath
+import scala.reflect.io.VirtualDirectory
import scala.tools.nsc.Settings
import scala.tools.nsc.io.AbstractFile
import FileUtils.AbstractFileOps
@@ -12,16 +13,9 @@ import FileUtils.AbstractFileOps
* it uses proper type of classpath depending on a types of particular files containing sources or classes.
*/
class FlatClassPathFactory(settings: Settings) extends ClassPathFactory[FlatClassPath] {
+ def newClassPath(file: AbstractFile): FlatClassPath = FlatClassPathFactory.newClassPath(file, settings)
- override def newClassPath(file: AbstractFile): FlatClassPath =
- if (file.isJarOrZip)
- ZipAndJarFlatClassPathFactory.create(file, settings)
- else if (file.isDirectory)
- new DirectoryFlatClassPath(file.file)
- else
- sys.error(s"Unsupported classpath element: $file")
-
- override def sourcesInPath(path: String): List[FlatClassPath] =
+ def sourcesInPath(path: String): List[FlatClassPath] =
for {
file <- expandPath(path, expandStar = false)
dir <- Option(AbstractFile getDirectory file)
@@ -35,3 +29,16 @@ class FlatClassPathFactory(settings: Settings) extends ClassPathFactory[FlatClas
else
sys.error(s"Unsupported sourcepath element: $file")
}
+
+object FlatClassPathFactory {
+ def newClassPath(file: AbstractFile, settings: Settings): FlatClassPath = file match {
+ case vd: VirtualDirectory => VirtualDirectoryFlatClassPath(vd)
+ case _ =>
+ if (file.isJarOrZip)
+ ZipAndJarFlatClassPathFactory.create(file, settings)
+ else if (file.isDirectory)
+ new DirectoryFlatClassPath(file.file)
+ else
+ sys.error(s"Unsupported classpath element: $file")
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/classpath/VirtualDirectoryFlatClassPath.scala b/src/compiler/scala/tools/nsc/classpath/VirtualDirectoryFlatClassPath.scala
new file mode 100644
index 0000000000..06cdab583c
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/classpath/VirtualDirectoryFlatClassPath.scala
@@ -0,0 +1,39 @@
+package scala.tools.nsc.classpath
+
+import scala.tools.nsc.util.ClassRepresentation
+import scala.reflect.io.{Path, PlainFile, VirtualDirectory, AbstractFile}
+import FileUtils._
+import java.net.URL
+
+case class VirtualDirectoryFlatClassPath(dir: VirtualDirectory) extends FlatClassPath with DirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
+ type F = AbstractFile
+
+ protected def emptyFiles: Array[AbstractFile] = Array.empty
+ protected def getSubDir(packageDirName: String): Option[AbstractFile] =
+ Option(dir.lookupName(packageDirName, directory = true))
+ protected def listChildren(dir: AbstractFile, filter: Option[AbstractFile => Boolean] = None): Array[F] = filter match {
+ case Some(f) => dir.iterator.filter(f).toArray
+ case _ => dir.toArray
+ }
+ def getName(f: AbstractFile): String = f.name
+ def toAbstractFile(f: AbstractFile): AbstractFile = f
+ def isPackage(f: AbstractFile): Boolean = f.isPackage
+
+ // mimic the behavior of the old nsc.util.DirectoryClassPath
+ def asURLs: Seq[URL] = Seq(new URL(dir.name))
+ def asClassPathStrings: Seq[String] = Seq(dir.path)
+
+ override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = findClassFile(className) map ClassFileEntryImpl
+
+ def findClassFile(className: String): Option[AbstractFile] = {
+ val relativePath = FileUtils.dirPath(className)
+ val classFile = new PlainFile(Path(s"$dir/$relativePath.class"))
+ if (classFile.exists) Some(classFile)
+ else None
+ }
+
+ private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage)
+
+ protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file)
+ protected def isMatchingFile(f: AbstractFile): Boolean = f.isClass
+}
diff --git a/src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala b/src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala
index 85c7c3c843..6ec3805d8b 100644
--- a/src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala
+++ b/src/compiler/scala/tools/nsc/classpath/ZipAndJarFileLookupFactory.scala
@@ -19,7 +19,6 @@ import FileUtils._
* when there are a lot of projects having a lot of common dependencies.
*/
sealed trait ZipAndJarFileLookupFactory {
-
private val cache = collection.mutable.Map.empty[AbstractFile, FlatClassPath]
def create(zipFile: AbstractFile, settings: Settings): FlatClassPath = {
@@ -44,7 +43,6 @@ sealed trait ZipAndJarFileLookupFactory {
* It should be the only way of creating them as it provides caching.
*/
object ZipAndJarFlatClassPathFactory extends ZipAndJarFileLookupFactory {
-
private case class ZipArchiveFlatClassPath(zipFile: File)
extends ZipArchiveFileLookup[ClassFileEntryImpl]
with NoSourcePaths {
@@ -67,10 +65,7 @@ object ZipAndJarFlatClassPathFactory extends ZipAndJarFileLookupFactory {
* with a particularly prepared scala-library.jar. It should have all classes listed in the manifest like e.g. this entry:
* Name: scala/Function2$mcFJD$sp.class
*/
- private case class ManifestResourcesFlatClassPath(file: ManifestResources)
- extends FlatClassPath
- with NoSourcePaths {
-
+ private case class ManifestResourcesFlatClassPath(file: ManifestResources) extends FlatClassPath with NoSourcePaths {
override def findClassFile(className: String): Option[AbstractFile] = {
val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className)
classes(pkg).find(_.name == simpleClassName).map(_.file)
@@ -163,7 +158,6 @@ object ZipAndJarFlatClassPathFactory extends ZipAndJarFileLookupFactory {
* It should be the only way of creating them as it provides caching.
*/
object ZipAndJarFlatSourcePathFactory extends ZipAndJarFileLookupFactory {
-
private case class ZipArchiveFlatSourcePath(zipFile: File)
extends ZipArchiveFileLookup[SourceFileEntryImpl]
with NoClassPaths {
diff --git a/src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala b/src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala
index 1d0de57779..a24d989306 100644
--- a/src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala
+++ b/src/compiler/scala/tools/nsc/classpath/ZipArchiveFileLookup.scala
@@ -57,7 +57,7 @@ trait ZipArchiveFileLookup[FileEntryType <: ClassRepClassPathEntry] extends Flat
} getOrElse FlatClassPathEntries(Seq.empty, Seq.empty)
}
- private def findDirEntry(pkg: String) = {
+ private def findDirEntry(pkg: String): Option[archive.DirEntry] = {
val dirName = s"${FileUtils.dirPath(pkg)}/"
archive.allDirs.get(dirName)
}
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index c524121646..982a6da41a 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -199,7 +199,7 @@ trait ScalaSettings extends AbsScalaSettings
val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overridden methods.")
val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.").withDeprecationMessage(removalIn212)
val inferByName = BooleanSetting ("-Yinfer-by-name", "Allow inference of by-name types. This is a temporary option to ease transition. See SI-7899.").withDeprecationMessage(removalIn212)
- val YclasspathImpl = ChoiceSetting ("-YclasspathImpl", "implementation", "Choose classpath scanning method.", List(ClassPathRepresentationType.Recursive, ClassPathRepresentationType.Flat), ClassPathRepresentationType.Recursive)
+ val YclasspathImpl = ChoiceSetting ("-YclasspathImpl", "implementation", "Choose classpath scanning method.", List(ClassPathRepresentationType.Recursive, ClassPathRepresentationType.Flat), ClassPathRepresentationType.Flat)
val YdisableFlatCpCaching = BooleanSetting ("-YdisableFlatCpCaching", "Do not cache flat classpath representation of classpath elements from jars across compiler instances.")
val exposeEmptyPackage = BooleanSetting ("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly()
diff --git a/src/compiler/scala/tools/nsc/util/ClassFileLookup.scala b/src/compiler/scala/tools/nsc/util/ClassFileLookup.scala
index 4451651229..5d8831a607 100644
--- a/src/compiler/scala/tools/nsc/util/ClassFileLookup.scala
+++ b/src/compiler/scala/tools/nsc/util/ClassFileLookup.scala
@@ -3,6 +3,8 @@
*/
package scala.tools.nsc.util
+import scala.tools.nsc.Settings
+import scala.tools.nsc.classpath.{AggregateFlatClassPath, FlatClassPath, FlatClassPathFactory}
import scala.tools.nsc.io.AbstractFile
import java.net.URL
@@ -39,6 +41,25 @@ trait ClassFileLookup[T] {
def asSourcePathString: String
}
+object ClassFileLookup {
+ def createForFile(f: AbstractFile, current: ClassFileLookup[AbstractFile], settings: Settings): ClassFileLookup[AbstractFile] = current match {
+ case cp: ClassPath[_] => cp.context.newClassPath(f)
+ case _: FlatClassPath => FlatClassPathFactory.newClassPath(f, settings)
+ }
+
+ def createAggregate(elems: Iterable[ClassFileLookup[AbstractFile]], current: ClassFileLookup[AbstractFile]): ClassFileLookup[AbstractFile] = {
+ assert(elems.nonEmpty)
+ if (elems.size == 1) elems.head
+ else current match {
+ case cp: ClassPath[_] =>
+ new MergedClassPath(elems.asInstanceOf[Iterable[ClassPath[AbstractFile]]], cp.context)
+
+ case _: FlatClassPath =>
+ AggregateFlatClassPath.createAggregate(elems.asInstanceOf[Iterable[FlatClassPath]].toSeq : _*)
+ }
+ }
+}
+
/**
* Represents classes which can be loaded with a ClassfileLoader and/or SourcefileLoader.
*/
diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala
index 2811520b67..6cdc3856cd 100644
--- a/src/compiler/scala/tools/nsc/util/ClassPath.scala
+++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala
@@ -278,7 +278,7 @@ class DirectoryClassPath(val dir: AbstractFile, val context: ClassPathContext[Ab
f =>
// Optimization: We assume the file was not changed since `dir` called
// `Path.apply` and categorized existent files as `Directory`
- // or `File`.
+ // or `File` (avoids IO operation JFile.isDirectory()).
val isDirectory = f match {
case pf: io.PlainFile => pf.givenPath match {
case _: io.Directory => true
@@ -300,13 +300,6 @@ class DirectoryClassPath(val dir: AbstractFile, val context: ClassPathContext[Ab
override def toString() = "directory classpath: "+ origin.getOrElse("?")
}
-class DeltaClassPath[T](original: MergedClassPath[T], subst: Map[ClassPath[T], ClassPath[T]])
-extends MergedClassPath[T](original.entries map (e => subst getOrElse (e, e)), original.context) {
- // not sure we should require that here. Commented out for now.
- // require(subst.keySet subsetOf original.entries.toSet)
- // We might add specialized operations for computing classes packages here. Not sure it's worth it.
-}
-
/**
* A classpath unifying multiple class- and sourcepath entries.
*/
diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
index 459450a94e..56d62f3efc 100644
--- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
@@ -633,10 +633,10 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
}
}
def alreadyDefined(clsName: String) = intp.classLoader.tryToLoadClass(clsName).isDefined
- val exists = entries.filter(_.hasExtension("class")).map(classNameOf).exists(alreadyDefined)
+ val existingClass = entries.filter(_.hasExtension("class")).map(classNameOf).find(alreadyDefined)
if (!f.exists) echo(s"The path '$f' doesn't seem to exist.")
- else if (exists) echo(s"The path '$f' cannot be loaded, because existing classpath entries conflict.") // TODO tell me which one
+ else if (existingClass.nonEmpty) echo(s"The path '$f' cannot be loaded, it contains a classfile that already exists on the classpath: ${existingClass.get}")
else {
addedClasspath = ClassPath.join(addedClasspath, f.path)
intp.addUrlsToClassPath(f.toURI.toURL)
diff --git a/src/repl/scala/tools/nsc/interpreter/PresentationCompilation.scala b/src/repl/scala/tools/nsc/interpreter/PresentationCompilation.scala
index c8cd201bf5..e3dc72b717 100644
--- a/src/repl/scala/tools/nsc/interpreter/PresentationCompilation.scala
+++ b/src/repl/scala/tools/nsc/interpreter/PresentationCompilation.scala
@@ -5,12 +5,14 @@
package scala.tools.nsc.interpreter
import scala.reflect.internal.util.RangePosition
+import scala.reflect.io.AbstractFile
import scala.tools.nsc.backend.JavaPlatform
+import scala.tools.nsc.settings.ClassPathRepresentationType
+import scala.tools.nsc.util.ClassPath.DefaultJavaContext
+import scala.tools.nsc.util.{ClassPath, MergedClassPath, DirectoryClassPath}
import scala.tools.nsc.{interactive, Settings}
-import scala.tools.nsc.io._
import scala.tools.nsc.reporters.StoreReporter
-import scala.tools.nsc.util.ClassPath.DefaultJavaContext
-import scala.tools.nsc.util.{DirectoryClassPath, MergedClassPath}
+import scala.tools.nsc.classpath._
trait PresentationCompilation {
self: IMain =>
@@ -55,8 +57,14 @@ trait PresentationCompilation {
* You may downcast the `reporter` to `StoreReporter` to access type errors.
*/
def newPresentationCompiler(): interactive.Global = {
- val replOutClasspath: DirectoryClassPath = new DirectoryClassPath(replOutput.dir, DefaultJavaContext)
- val mergedClasspath = new MergedClassPath[AbstractFile](replOutClasspath :: global.platform.classPath :: Nil, DefaultJavaContext)
+ def mergedFlatClasspath = {
+ val replOutClasspath = FlatClassPathFactory.newClassPath(replOutput.dir, settings)
+ AggregateFlatClassPath(replOutClasspath :: global.platform.flatClassPath :: Nil)
+ }
+ def mergedRecursiveClasspath = {
+ val replOutClasspath: DirectoryClassPath = new DirectoryClassPath(replOutput.dir, DefaultJavaContext)
+ new MergedClassPath[AbstractFile](replOutClasspath :: global.platform.classPath :: Nil, DefaultJavaContext)
+ }
def copySettings: Settings = {
val s = new Settings(_ => () /* ignores "bad option -nc" errors, etc */)
s.processArguments(global.settings.recreateArgs, processAll = false)
@@ -65,10 +73,18 @@ trait PresentationCompilation {
}
val storeReporter: StoreReporter = new StoreReporter
val interactiveGlobal = new interactive.Global(copySettings, storeReporter) { self =>
- override lazy val platform: ThisPlatform = new JavaPlatform {
- val global: self.type = self
-
- override def classPath: PlatformClassPath = mergedClasspath
+ override lazy val platform: ThisPlatform = {
+ if (settings.YclasspathImpl.value == ClassPathRepresentationType.Flat) {
+ new JavaPlatform {
+ val global: self.type = self
+ override private[nsc] lazy val flatClassPath: FlatClassPath = mergedFlatClasspath
+ }
+ } else {
+ new JavaPlatform {
+ val global: self.type = self
+ override def classPath: ClassPath[AbstractFile] = mergedRecursiveClasspath
+ }
+ }
}
}
new interactiveGlobal.TyperRun()