diff options
Diffstat (limited to 'src')
25 files changed, 493 insertions, 221 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/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 3e60ef37c4..c5a3d605b1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -977,7 +977,7 @@ trait Contexts { self: Analyzer => */ def isInPackageObject(sym: Symbol, pkg: Symbol): Boolean = { if (sym.isOverloaded) sym.alternatives.exists(alt => isInPackageObject(alt, pkg)) - else pkg.isPackage && sym.owner != pkg && requiresQualifier(sym) + else pkg.hasPackageFlag && sym.owner != pkg && requiresQualifier(sym) } def isNameInScope(name: Name) = lookupSymbol(name, _ => true).isSuccess diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 9446a45c06..16d3f5134b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -105,7 +105,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // that are turned private by typedBlock private final val SYNTHETIC_PRIVATE = TRANS_FLAG - private final val InterpolatorCodeRegex = """\$\{.*?\}""".r + private final val InterpolatorCodeRegex = """\$\{\s*(.*?)\s*\}""".r private final val InterpolatorIdentRegex = """\$[$\w]+""".r // note that \w doesn't include $ abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with Tag with PatternTyper with TyperContextErrors { @@ -5206,17 +5206,23 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case MethodType(p :: _, _) => p.isImplicit // implicit method requires no args case _ => true // catches all others including NullaryMethodType } - def isPlausible(m: Symbol) = m.alternatives exists (m => requiresNoArgs(m.info)) + def isPlausible(m: Symbol) = !m.isPackage && m.alternatives.exists(x => requiresNoArgs(x.info)) def maybeWarn(s: String): Unit = { def warn(message: String) = context.warning(lit.pos, s"possible missing interpolator: $message") def suspiciousSym(name: TermName) = context.lookupSymbol(name, _ => true).symbol - def suspiciousExpr = InterpolatorCodeRegex findFirstIn s + val suspiciousExprs = InterpolatorCodeRegex findAllMatchIn s def suspiciousIdents = InterpolatorIdentRegex findAllIn s map (s => suspiciousSym(TermName(s drop 1))) - - if (suspiciousExpr.nonEmpty) - warn("detected an interpolated expression") // "${...}" - else + def isCheapIdent(expr: String) = (Character.isJavaIdentifierStart(expr.charAt(0)) && + expr.tail.forall(Character.isJavaIdentifierPart)) + def warnableExpr(expr: String) = !expr.isEmpty && (!isCheapIdent(expr) || isPlausible(suspiciousSym(TermName(expr)))) + + if (suspiciousExprs.nonEmpty) { + val exprs = (suspiciousExprs map (_ group 1)).toList + // short-circuit on leading ${} + if (!exprs.head.isEmpty && exprs.exists(warnableExpr)) + warn("detected an interpolated expression") // "${...}" + } else suspiciousIdents find isPlausible foreach (sym => warn(s"detected interpolated identifier `$$${sym.name}`")) // "$id" } lit match { 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/library/scala/Predef.scala b/src/library/scala/Predef.scala index 9cd2a2b8de..2f6d6511b2 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -65,6 +65,49 @@ import scala.io.StdIn * are provided for the "widening" of numeric values, for instance, converting a * Short value to a Long value as required, and to add additional higher-order * functions to Array values. These are described in more detail in the documentation of [[scala.Array]]. + * + * @groupname utilities Utility Methods + * @groupprio utilities 10 + * + * @groupname assertions Assertions + * @groupprio assertions 20 + * @groupdesc assertions These methods support program verfication and runtime correctness. + * + * @groupname console-output Console Output + * @groupprio console-output 30 + * @groupdesc console-output These methods provide output via the console. + * + * @groupname type-constraints Type Constraints + * @groupprio type-constraints 40 + * @groupdesc type-constraints These entities allows constraints between types to be stipulated. + * + * @groupname aliases Aliases + * @groupprio aliases 50 + * @groupdesc aliases These aliases bring selected immutable types into scope without any imports. + * + * @groupname conversions-string String Conversions + * @groupprio conversions-string 60 + * @groupdesc conversions-string Conversions to and from String and StringOps. + * + * @groupname implicit-classes-any Implicit Classes + * @groupprio implicit-classes-any 70 + * @groupdesc implicit-classes-any These implicit classes add useful extension methods to every type. + * + * @groupname implicit-classes-char CharSequence Conversions + * @groupprio implicit-classes-char 80 + * @groupdesc implicit-classes-char These implicit classes add CharSequence methods to Array[Char] and IndexedSeq[Char] instances. + * + * @groupname conversions-java-to-anyval Java to Scala + * @groupprio conversions-java-to-anyval 90 + * @groupdesc conversions-java-to-anyval Implicit conversion from Java primitive wrapper types to Scala equivalents. + * + * @groupname conversions-anyval-to-java Scala to Java + * @groupprio conversions-anyval-to-java 100 + * @groupdesc conversions-anyval-to-java Implicit conversion from Scala AnyVals to Java primitive wrapper types equivalents. + * + * @groupname conversions-array-to-wrapped-array Array to WrappedArray + * @groupprio conversions-array-to-wrapped-array 110 + * @groupdesc conversions-array-to-wrapped-array Conversions from Arrays to WrappedArrays. */ object Predef extends LowPriorityImplicits with DeprecatedPredef { /** @@ -78,6 +121,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * val mapIntString = classOf[Map[Int,String]] * // mapIntString is java.lang.Class[Map[Int,String]] = interface scala.collection.immutable.Map * }}} + * @group utilities */ def classOf[T]: Class[T] = null // This is a stub method. The actual implementation is filled in by the compiler. @@ -85,19 +129,26 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * Java String (see the documentation corresponding to your Java version, for * example [[http://docs.oracle.com/javase/8/docs/api/java/lang/String.html]]) or * are added implicitly through [[scala.collection.immutable.StringOps]]. + * @group aliases */ type String = java.lang.String + /** @group aliases */ type Class[T] = java.lang.Class[T] // miscellaneous ----------------------------------------------------- scala.`package` // to force scala package object to be seen. scala.collection.immutable.List // to force Nil, :: to be seen. + /** @group aliases */ type Function[-A, +B] = Function1[A, B] + /** @group aliases */ type Map[A, +B] = immutable.Map[A, B] + /** @group aliases */ type Set[A] = immutable.Set[A] + /** @group aliases */ val Map = immutable.Map + /** @group aliases */ val Set = immutable.Set // Manifest types, companions, and incantations for summoning @@ -130,8 +181,11 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { def optManifest[T](implicit m: OptManifest[T]) = m // Minor variations on identity functions + /** @group utilities */ @inline def identity[A](x: A): A = x // @see `conforms` for the implicit version + /** @group utilities */ @inline def implicitly[T](implicit e: T) = e // for summoning implicit values from the nether world -- TODO: when dependent method types are on by default, give this result type `e.type`, so that inliner has better chance of knowing which method to inline in calls like `implicitly[MatchingStrategy[Option]].zero` + /** @group utilities */ @inline def locally[T](x: T): T = x // to communicate intent and avoid unmoored statements // errors and asserts ------------------------------------------------- @@ -148,6 +202,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * * @see [[scala.annotation.elidable elidable]] * @param assertion the expression to test + * @group assertions */ @elidable(ASSERTION) def assert(assertion: Boolean) { @@ -162,6 +217,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * @see [[scala.annotation.elidable elidable]] * @param assertion the expression to test * @param message a String to include in the failure message + * @group assertions */ @elidable(ASSERTION) @inline final def assert(assertion: Boolean, message: => Any) { @@ -177,6 +233,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * * @see [[scala.annotation.elidable elidable]] * @param assumption the expression to test + * @group assertions */ @elidable(ASSERTION) def assume(assumption: Boolean) { @@ -193,6 +250,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * @see [[scala.annotation.elidable elidable]] * @param assumption the expression to test * @param message a String to include in the failure message + * @group assertions */ @elidable(ASSERTION) @inline final def assume(assumption: Boolean, message: => Any) { @@ -205,6 +263,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * for violating the condition. * * @param requirement the expression to test + * @group assertions */ def require(requirement: Boolean) { if (!requirement) @@ -217,6 +276,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * * @param requirement the expression to test * @param message a String to include in the failure message + * @group assertions */ @inline final def require(requirement: Boolean, message: => Any) { if (!requirement) @@ -225,6 +285,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { /** `???` can be used for marking methods that remain to be implemented. * @throws NotImplementedError + * @group utilities */ def ??? : Nothing = throw new NotImplementedError @@ -248,11 +309,13 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { // implicit classes ----------------------------------------------------- + /** @group implicit-classes-any */ implicit final class ArrowAssoc[A](private val self: A) extends AnyVal { @inline def -> [B](y: B): Tuple2[A, B] = Tuple2(self, y) def →[B](y: B): Tuple2[A, B] = ->(y) } + /** @group implicit-classes-any */ implicit final class Ensuring[A](private val self: A) extends AnyVal { def ensuring(cond: Boolean): A = { assert(cond); self } def ensuring(cond: Boolean, msg: => Any): A = { assert(cond, msg); self } @@ -260,6 +323,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { def ensuring(cond: A => Boolean, msg: => Any): A = { assert(cond(self), msg); self } } + /** @group implicit-classes-any */ implicit final class StringFormat[A](private val self: A) extends AnyVal { /** Returns string formatted according to given `format` string. * Format strings are as for `String.format` @@ -269,6 +333,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { } // SI-8229 retaining the pre 2.11 name for source compatibility in shadowing this implicit + /** @group implicit-classes-any */ implicit final class any2stringadd[A](private val self: A) extends AnyVal { def +(other: String): String = String.valueOf(self) + other } @@ -278,6 +343,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { @deprecated("Use Throwable#getStackTrace", "2.11.0") def getStackTraceString = self.getStackTrace().mkString("", EOL, EOL) } + /** @group implicit-classes-char */ implicit final class SeqCharSequence(val __sequenceOfChars: scala.collection.IndexedSeq[Char]) extends CharSequence { def length: Int = __sequenceOfChars.length def charAt(index: Int): Char = __sequenceOfChars(index) @@ -285,6 +351,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { override def toString = __sequenceOfChars mkString "" } + /** @group implicit-classes-char */ implicit final class ArrayCharSequence(val __arrayOfChars: Array[Char]) extends CharSequence { def length: Int = __arrayOfChars.length def charAt(index: Int): Char = __arrayOfChars(index) @@ -297,7 +364,9 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { def apply() = mutable.StringBuilder.newBuilder } + /** @group conversions-string */ @inline implicit def augmentString(x: String): StringOps = new StringOps(x) + /** @group conversions-string */ @inline implicit def unaugmentString(x: StringOps): String = x.repr // printing ----------------------------------------------------------- @@ -305,16 +374,19 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { /** Prints an object to `out` using its `toString` method. * * @param x the object to print; may be null. + * @group console-output */ def print(x: Any) = Console.print(x) /** Prints a newline character on the default output. + * @group console-output */ def println() = Console.println() /** Prints out an object to the default output, followed by a newline character. * * @param x the object to print. + * @group console-output */ def println(x: Any) = Console.println(x) @@ -332,6 +404,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * @throws java.lang.IllegalArgumentException if there was a problem with the format string or arguments * * @see [[scala.StringContext.f StringContext.f]] + * @group console-output */ def printf(text: String, xs: Any*) = Console.print(text.format(xs: _*)) @@ -379,22 +452,38 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { // "Autoboxing" and "Autounboxing" --------------------------------------------------- + /** @group conversions-anyval-to-java */ implicit def byte2Byte(x: Byte): java.lang.Byte = x.asInstanceOf[java.lang.Byte] + /** @group conversions-anyval-to-java */ implicit def short2Short(x: Short): java.lang.Short = x.asInstanceOf[java.lang.Short] + /** @group conversions-anyval-to-java */ implicit def char2Character(x: Char): java.lang.Character = x.asInstanceOf[java.lang.Character] + /** @group conversions-anyval-to-java */ implicit def int2Integer(x: Int): java.lang.Integer = x.asInstanceOf[java.lang.Integer] + /** @group conversions-anyval-to-java */ implicit def long2Long(x: Long): java.lang.Long = x.asInstanceOf[java.lang.Long] + /** @group conversions-anyval-to-java */ implicit def float2Float(x: Float): java.lang.Float = x.asInstanceOf[java.lang.Float] + /** @group conversions-anyval-to-java */ implicit def double2Double(x: Double): java.lang.Double = x.asInstanceOf[java.lang.Double] + /** @group conversions-anyval-to-java */ implicit def boolean2Boolean(x: Boolean): java.lang.Boolean = x.asInstanceOf[java.lang.Boolean] + /** @group conversions-java-to-anyval */ implicit def Byte2byte(x: java.lang.Byte): Byte = x.asInstanceOf[Byte] + /** @group conversions-java-to-anyval */ implicit def Short2short(x: java.lang.Short): Short = x.asInstanceOf[Short] + /** @group conversions-java-to-anyval */ implicit def Character2char(x: java.lang.Character): Char = x.asInstanceOf[Char] + /** @group conversions-java-to-anyval */ implicit def Integer2int(x: java.lang.Integer): Int = x.asInstanceOf[Int] + /** @group conversions-java-to-anyval */ implicit def Long2long(x: java.lang.Long): Long = x.asInstanceOf[Long] + /** @group conversions-java-to-anyval */ implicit def Float2float(x: java.lang.Float): Float = x.asInstanceOf[Float] + /** @group conversions-java-to-anyval */ implicit def Double2double(x: java.lang.Double): Double = x.asInstanceOf[Double] + /** @group conversions-java-to-anyval */ implicit def Boolean2boolean(x: java.lang.Boolean): Boolean = x.asInstanceOf[Boolean] // Type Constraints -------------------------------------------------------------- @@ -415,6 +504,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * required lower bound. * * In part contributed by Jason Zaugg. + * @group type-constraints */ @implicitNotFound(msg = "Cannot prove that ${From} <:< ${To}.") sealed abstract class <:<[-From, +To] extends (From => To) with Serializable @@ -422,6 +512,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { // The dollar prefix is to dodge accidental shadowing of this method // by a user-defined method of the same name (SI-7788). // The collections rely on this method. + /** @group type-constraints */ implicit def $conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A] @deprecated("Use `implicitly[T <:< U]` or `identity` instead.", "2.11.0") @@ -430,10 +521,12 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { /** An instance of `A =:= B` witnesses that the types `A` and `B` are equal. * * @see `<:<` for expressing subtyping constraints + * @group type-constraints */ @implicitNotFound(msg = "Cannot prove that ${From} =:= ${To}.") sealed abstract class =:=[From, To] extends (From => To) with Serializable private[this] final val singleton_=:= = new =:=[Any,Any] { def apply(x: Any): Any = x } + /** @group type-constraints */ object =:= { implicit def tpEquals[A]: A =:= A = singleton_=:=.asInstanceOf[A =:= A] } @@ -513,6 +606,7 @@ private[scala] abstract class LowPriorityImplicits { @inline implicit def doubleWrapper(x: Double) = new runtime.RichDouble(x) @inline implicit def booleanWrapper(x: Boolean) = new runtime.RichBoolean(x) + /** @group conversions-array-to-wrapped-array */ implicit def genericWrapArray[T](xs: Array[T]): WrappedArray[T] = if (xs eq null) null else WrappedArray.make(xs) @@ -520,23 +614,35 @@ private[scala] abstract class LowPriorityImplicits { // Since the JVM thinks arrays are covariant, one 0-length Array[AnyRef] // is as good as another for all T <: AnyRef. Instead of creating 100,000,000 // unique ones by way of this implicit, let's share one. + /** @group conversions-array-to-wrapped-array */ implicit def wrapRefArray[T <: AnyRef](xs: Array[T]): WrappedArray[T] = { if (xs eq null) null else if (xs.length == 0) WrappedArray.empty[T] else new WrappedArray.ofRef[T](xs) } + /** @group conversions-array-to-wrapped-array */ implicit def wrapIntArray(xs: Array[Int]): WrappedArray[Int] = if (xs ne null) new WrappedArray.ofInt(xs) else null + /** @group conversions-array-to-wrapped-array */ implicit def wrapDoubleArray(xs: Array[Double]): WrappedArray[Double] = if (xs ne null) new WrappedArray.ofDouble(xs) else null + /** @group conversions-array-to-wrapped-array */ implicit def wrapLongArray(xs: Array[Long]): WrappedArray[Long] = if (xs ne null) new WrappedArray.ofLong(xs) else null + /** @group conversions-array-to-wrapped-array */ implicit def wrapFloatArray(xs: Array[Float]): WrappedArray[Float] = if (xs ne null) new WrappedArray.ofFloat(xs) else null + /** @group conversions-array-to-wrapped-array */ implicit def wrapCharArray(xs: Array[Char]): WrappedArray[Char] = if (xs ne null) new WrappedArray.ofChar(xs) else null + /** @group conversions-array-to-wrapped-array */ implicit def wrapByteArray(xs: Array[Byte]): WrappedArray[Byte] = if (xs ne null) new WrappedArray.ofByte(xs) else null + /** @group conversions-array-to-wrapped-array */ implicit def wrapShortArray(xs: Array[Short]): WrappedArray[Short] = if (xs ne null) new WrappedArray.ofShort(xs) else null + /** @group conversions-array-to-wrapped-array */ implicit def wrapBooleanArray(xs: Array[Boolean]): WrappedArray[Boolean] = if (xs ne null) new WrappedArray.ofBoolean(xs) else null + /** @group conversions-array-to-wrapped-array */ implicit def wrapUnitArray(xs: Array[Unit]): WrappedArray[Unit] = if (xs ne null) new WrappedArray.ofUnit(xs) else null + /** @group conversions-string */ implicit def wrapString(s: String): WrappedString = if (s ne null) new WrappedString(s) else null + /** @group conversions-string */ implicit def unwrapString(ws: WrappedString): String = if (ws ne null) ws.self else null implicit def fallbackStringCanBuildFrom[T]: CanBuildFrom[String, T, immutable.IndexedSeq[T]] = diff --git a/src/library/scala/collection/GenSeqLike.scala b/src/library/scala/collection/GenSeqLike.scala index be1da1660a..405d8d7e57 100644 --- a/src/library/scala/collection/GenSeqLike.scala +++ b/src/library/scala/collection/GenSeqLike.scala @@ -58,6 +58,7 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal * Note: `xs.length` and `xs.size` yield the same result. * * @return the number of elements in this $coll. + * @throws IllegalArgumentException if the length of the sequence cannot be represented in an `Int`, for example, `(-1 to Int.MaxValue).length`. */ def length: Int diff --git a/src/library/scala/concurrent/SyncChannel.scala b/src/library/scala/concurrent/SyncChannel.scala index ec584b3eb0..735598935c 100644 --- a/src/library/scala/concurrent/SyncChannel.scala +++ b/src/library/scala/concurrent/SyncChannel.scala @@ -31,10 +31,10 @@ class SyncChannel[A] { pendingReads = pendingReads.tail // let reader continue - readReq set data + readReq put data // resolve write request - writeReq set true + writeReq put true } else { // enqueue write request @@ -57,10 +57,10 @@ class SyncChannel[A] { pendingWrites = pendingWrites.tail // let writer continue - writeReq set true + writeReq.put(true) // resolve read request - readReq set data + readReq.put (data) } else { // enqueue read request diff --git a/src/library/scala/sys/process/ProcessBuilderImpl.scala b/src/library/scala/sys/process/ProcessBuilderImpl.scala index 236baaf038..eef140c16a 100644 --- a/src/library/scala/sys/process/ProcessBuilderImpl.scala +++ b/src/library/scala/sys/process/ProcessBuilderImpl.scala @@ -56,7 +56,7 @@ private[process] trait ProcessBuilderImpl { success put false val t = Spawn({ runImpl(io) - success set true + success.put(true) }, io.daemonizeThreads) new ThreadProcess(t, success) diff --git a/src/library/scala/sys/process/ProcessImpl.scala b/src/library/scala/sys/process/ProcessImpl.scala index 559c0ee525..6da0dee056 100644 --- a/src/library/scala/sys/process/ProcessImpl.scala +++ b/src/library/scala/sys/process/ProcessImpl.scala @@ -30,8 +30,8 @@ private[process] trait ProcessImpl { def apply[T](f: => T): (Thread, () => T) = { val result = new SyncVar[Either[Throwable, T]] def run(): Unit = - try result set Right(f) - catch { case e: Exception => result set Left(e) } + try result.put(Right(f)) + catch { case e: Exception => result.put(Left(e)) } val t = Spawn(run()) @@ -91,8 +91,8 @@ private[process] trait ProcessImpl { protected lazy val (processThread, getExitValue, destroyer) = { val code = new SyncVar[Option[Int]]() - code set None - val thread = Spawn(code set runAndExitValue()) + code.put(None) + val thread = Spawn(code.put(runAndExitValue())) ( thread, diff --git a/src/partest-extras/scala/tools/partest/Util.scala b/src/partest-extras/scala/tools/partest/Util.scala index 60e9dbb0f9..511997ea35 100644 --- a/src/partest-extras/scala/tools/partest/Util.scala +++ b/src/partest-extras/scala/tools/partest/Util.scala @@ -14,7 +14,7 @@ object Util { * An alternative to [[scala.tools.partest.ReplTest]] that avoids the inconvenience of embedding * test code in a string. */ - def trace[A](a: A) = macro traceImpl[A] + def trace[A](a: A): A = macro traceImpl[A] import scala.reflect.macros.blackbox.Context def traceImpl[A: c.WeakTypeTag](c: Context)(a: c.Expr[A]): c.Expr[A] = { diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index f75381691f..34f9417e57 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -835,7 +835,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** The package object symbol corresponding to this package or package class symbol, or NoSymbol otherwise */ def packageObject: Symbol = if (isPackageClass) tpe.packageObject - else if (isPackage) moduleClass.packageObject + else if (hasPackageFlag) moduleClass.packageObject else NoSymbol /** If this is a constructor, its owner: otherwise this. 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() |