@@ -7,29 +7,29 @@ package scala
77package tools
88package nsc
99
10- import java .io .{ File , IOException , FileNotFoundException }
10+ import java .io .{File , FileNotFoundException , IOException }
1111import java .net .URL
12- import java .nio .charset .{ Charset , CharsetDecoder , IllegalCharsetNameException , UnsupportedCharsetException }
13- import scala .collection .{ mutable , immutable }
14- import io .{ SourceReader , AbstractFile , Path }
12+ import java .nio .charset .{Charset , CharsetDecoder , IllegalCharsetNameException , UnsupportedCharsetException }
13+ import scala .collection .{immutable , mutable }
14+ import io .{AbstractFile , Path , SourceReader }
1515import reporters .Reporter
16- import util .{ ClassFileLookup , ClassPath , MergedClassPath , StatisticsInfo , returning }
16+ import util .{ClassFileLookup , ClassPath , StatisticsInfo , returning }
1717import scala .reflect .ClassTag
18- import scala .reflect .internal .util .{ ScalaClassLoader , SourceFile , NoSourceFile , BatchSourceFile , ScriptSourceFile }
18+ import scala .reflect .internal .util .{BatchSourceFile , NoSourceFile , ScalaClassLoader , ScriptSourceFile , SourceFile }
1919import scala .reflect .internal .pickling .PickleBuffer
20- import symtab .{ Flags , SymbolTable , SymbolTrackers }
20+ import symtab .{Flags , SymbolTable , SymbolTrackers }
2121import symtab .classfile .Pickler
2222import plugins .Plugins
2323import ast ._
2424import ast .parser ._
2525import typechecker ._
2626import transform .patmat .PatternMatching
2727import transform ._
28- import backend .{ ScalaPrimitives , JavaPlatform }
28+ import backend .{JavaPlatform , ScalaPrimitives }
2929import backend .jvm .GenBCode
3030import scala .language .postfixOps
3131import scala .tools .nsc .ast .{TreeGen => AstTreeGen }
32- import scala .tools .nsc .classpath .FlatClassPath
32+ import scala .tools .nsc .classpath ._
3333import scala .tools .nsc .settings .ClassPathRepresentationType
3434
3535class Global (var currentSettings : Settings , var reporter : Reporter )
@@ -102,9 +102,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
102102 type ThisPlatform = JavaPlatform { val global : Global .this .type }
103103 lazy val platform : ThisPlatform = new GlobalPlatform
104104
105- type PlatformClassPath = ClassPath [AbstractFile ]
106- type OptClassPath = Option [PlatformClassPath ]
107-
108105 def classPath : ClassFileLookup [AbstractFile ] = settings.YclasspathImpl .value match {
109106 case ClassPathRepresentationType .Flat => flatClassPath
110107 case ClassPathRepresentationType .Recursive => recursiveClassPath
@@ -771,13 +768,17 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
771768
772769 /** Extend classpath of `platform` and rescan updated packages. */
773770 def extendCompilerClassPath (urls : URL * ): Unit = {
774- if (settings.YclasspathImpl .value == ClassPathRepresentationType .Flat )
775- throw new UnsupportedOperationException (" Flat classpath doesn't support extending the compiler classpath" )
776-
777- val newClassPath = platform.classPath.mergeUrlsIntoClassPath(urls : _* )
778- platform.currentClassPath = Some (newClassPath)
779- // Reload all specified jars into this compiler instance
780- invalidateClassPathEntries(urls.map(_.getPath): _* )
771+ if (settings.YclasspathImpl .value == ClassPathRepresentationType .Flat ) {
772+ val urlClasspaths = urls.map(u => FlatClassPathFactory .newClassPath(AbstractFile .getURL(u), settings))
773+ val newClassPath = AggregateFlatClassPath .createAggregate(platform.flatClassPath +: urlClasspaths : _* )
774+ platform.currentFlatClassPath = Some (newClassPath)
775+ invalidateClassPathEntries(urls.map(_.getPath): _* )
776+ } else {
777+ val newClassPath = platform.classPath.mergeUrlsIntoClassPath(urls : _* )
778+ platform.currentClassPath = Some (newClassPath)
779+ // Reload all specified jars into this compiler instance
780+ invalidateClassPathEntries(urls.map(_.getPath): _* )
781+ }
781782 }
782783
783784 // ------------ Invalidations ---------------------------------
@@ -809,43 +810,60 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
809810 * entries on the classpath.
810811 */
811812 def invalidateClassPathEntries (paths : String * ): Unit = {
812- if (settings.YclasspathImpl .value == ClassPathRepresentationType .Flat )
813- throw new UnsupportedOperationException (" Flat classpath doesn't support the classpath invalidation" )
814-
815- implicit object ClassPathOrdering extends Ordering [PlatformClassPath ] {
816- def compare (a: PlatformClassPath , b: PlatformClassPath ) = a.asClassPathString compare b.asClassPathString
813+ implicit object ClassPathOrdering extends Ordering [ClassFileLookup [AbstractFile ]] {
814+ def compare (a: ClassFileLookup [AbstractFile ], b: ClassFileLookup [AbstractFile ]) = a.asClassPathString compare b.asClassPathString
817815 }
818816 val invalidated, failed = new mutable.ListBuffer [ClassSymbol ]
819- classPath match {
820- case cp : MergedClassPath [_] =>
821- def assoc (path : String ): List [(PlatformClassPath , PlatformClassPath )] = {
822- val dir = AbstractFile .getDirectory(path)
823- val canonical = dir.canonicalPath
824- def matchesCanonical (e : ClassPath [_]) = e.origin match {
825- case Some (opath) =>
826- AbstractFile .getDirectory(opath).canonicalPath == canonical
827- case None =>
828- false
829- }
830- cp.entries find matchesCanonical match {
831- case Some (oldEntry) =>
832- List (oldEntry -> cp.context.newClassPath(dir))
833- case None =>
834- error(s " Error adding entry to classpath. During invalidation, no entry named $path in classpath $classPath" )
835- List ()
836- }
837- }
838- val subst = immutable.TreeMap (paths flatMap assoc : _* )
839- if (subst.nonEmpty) {
840- platform updateClassPath subst
841- informProgress(s " classpath updated on entries [ ${subst.keys mkString " ," }] " )
842- def mkClassPath (elems : Iterable [PlatformClassPath ]): PlatformClassPath =
843- if (elems.size == 1 ) elems.head
844- else new MergedClassPath (elems, recursiveClassPath.context)
845- val oldEntries = mkClassPath(subst.keys)
846- val newEntries = mkClassPath(subst.values)
847- mergeNewEntries(newEntries, RootClass , Some (recursiveClassPath), Some (oldEntries), invalidated, failed)
848- }
817+
818+ def assoc (path : String ): Option [(ClassFileLookup [AbstractFile ], ClassFileLookup [AbstractFile ])] = {
819+ def origin (lookup : ClassFileLookup [AbstractFile ]): Option [String ] = lookup match {
820+ case cp : ClassPath [_] => cp.origin
821+ case cp : JFileDirectoryLookup [_] => Some (cp.dir.getPath)
822+ case cp : ZipArchiveFileLookup [_] => Some (cp.zipFile.getPath)
823+ case _ => None
824+ }
825+
826+ def entries (lookup : ClassFileLookup [AbstractFile ]): Seq [ClassFileLookup [AbstractFile ]] = lookup match {
827+ case cp : ClassPath [_] => cp.entries
828+ case cp : AggregateFlatClassPath => cp.aggregates
829+ case cp : FlatClassPath => Seq (cp)
830+ }
831+
832+ val dir = AbstractFile .getDirectory(path) // if path is a `jar`, this is a FileZipArchive (isDirectory is true)
833+ val canonical = dir.canonicalPath // this is the canonical path of the .jar
834+ def matchesCanonical (e : ClassFileLookup [AbstractFile ]) = origin(e) match {
835+ case Some (opath) =>
836+ AbstractFile .getDirectory(opath).canonicalPath == canonical
837+ case None =>
838+ false
839+ }
840+ entries(classPath) find matchesCanonical match {
841+ case Some (oldEntry) =>
842+ Some (oldEntry -> ClassFileLookup .createForFile(dir, classPath, settings))
843+ case None =>
844+ error(s " Error adding entry to classpath. During invalidation, no entry named $path in classpath $classPath" )
845+ None
846+ }
847+ }
848+ val subst = immutable.TreeMap (paths flatMap assoc : _* )
849+ if (subst.nonEmpty) {
850+ platform updateClassPath subst
851+ informProgress(s " classpath updated on entries [ ${subst.keys mkString " ," }] " )
852+ def mkClassPath (elems : Iterable [ClassFileLookup [AbstractFile ]]): ClassFileLookup [AbstractFile ] =
853+ if (elems.size == 1 ) elems.head
854+ else ClassFileLookup .createAggregate(elems, classPath)
855+ val oldEntries = mkClassPath(subst.keys)
856+ val newEntries = mkClassPath(subst.values)
857+ classPath match {
858+ case rcp : ClassPath [_] => mergeNewEntriesRecursive(
859+ newEntries.asInstanceOf [ClassPath [AbstractFile ]], RootClass , Some (rcp), Some (oldEntries.asInstanceOf [ClassPath [AbstractFile ]]),
860+ invalidated, failed)
861+
862+ case fcp : FlatClassPath => mergeNewEntriesFlat(
863+ RootClass , " " ,
864+ oldEntries.asInstanceOf [FlatClassPath ], newEntries.asInstanceOf [FlatClassPath ], fcp,
865+ invalidated, failed)
866+ }
849867 }
850868 def show (msg : String , syms : scala.collection.Traversable [Symbol ]) =
851869 if (syms.nonEmpty)
@@ -876,22 +894,22 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
876894 *
877895 * Here, old means classpath, and sym means symboltable. + is presence of an entry in its column, - is absence.
878896 */
879- private def mergeNewEntries (newEntries : PlatformClassPath , root : ClassSymbol ,
880- allEntries : OptClassPath , oldEntries : OptClassPath ,
897+ private def mergeNewEntriesRecursive (newEntries : ClassPath [ AbstractFile ] , root : ClassSymbol ,
898+ allEntries : Option [ ClassPath [ AbstractFile ]] , oldEntries : Option [ ClassPath [ AbstractFile ]] ,
881899 invalidated : mutable.ListBuffer [ClassSymbol ], failed : mutable.ListBuffer [ClassSymbol ]) {
882900 ifDebug(informProgress(s " syncing $root, $oldEntries -> $newEntries" ))
883901
884- val getName : ClassPath [AbstractFile ] => String = ( _.name)
885- def hasClasses (cp : OptClassPath ) = cp.isDefined && cp.get.classes.nonEmpty
902+ val getPackageName : ClassPath [AbstractFile ] => String = _.name
903+ def hasClasses (cp : Option [ ClassPath [ AbstractFile ]] ) = cp.isDefined && cp.get.classes.nonEmpty
886904 def invalidateOrRemove (root : ClassSymbol ) = {
887905 allEntries match {
888906 case Some (cp) => root setInfo new loaders.PackageLoader (cp)
889907 case None => root.owner.info.decls unlink root.sourceModule
890908 }
891909 invalidated += root
892910 }
893- def subPackage (cp : PlatformClassPath , name : String ): OptClassPath =
894- cp.packages find (cp1 => getName (cp1) == name)
911+ def subPackage (cp : ClassPath [ AbstractFile ] , name : String ): Option [ ClassPath [ AbstractFile ]] =
912+ cp.packages find (cp1 => getPackageName (cp1) == name)
895913
896914 val classesFound = hasClasses(oldEntries) || newEntries.classes.nonEmpty
897915 if (classesFound && ! isSystemPackageClass(root)) {
@@ -901,22 +919,81 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
901919 if (root.isRoot) invalidateOrRemove(EmptyPackageClass )
902920 else failed += root
903921 }
904- if (! oldEntries.isDefined ) invalidateOrRemove(root)
922+ if (oldEntries.isEmpty ) invalidateOrRemove(root)
905923 else
906- for (pstr <- newEntries.packages.map(getName )) {
924+ for (pstr <- newEntries.packages.map(getPackageName )) {
907925 val pname = newTermName(pstr)
908926 val pkg = (root.info decl pname) orElse {
909927 // package does not exist in symbol table, create symbol to track it
910- assert(! subPackage(oldEntries.get, pstr).isDefined )
928+ assert(subPackage(oldEntries.get, pstr).isEmpty )
911929 loaders.enterPackage(root, pstr, new loaders.PackageLoader (allEntries.get))
912930 }
913- mergeNewEntries (subPackage(newEntries, pstr).get, pkg.moduleClass.asClass,
931+ mergeNewEntriesRecursive (subPackage(newEntries, pstr).get, pkg.moduleClass.asClass,
914932 subPackage(allEntries.get, pstr), subPackage(oldEntries.get, pstr),
915933 invalidated, failed)
916934 }
917935 }
918936 }
919937
938+ /**
939+ * Merges new classpath entries into the symbol table
940+ *
941+ * @param packageClass The ClassSymbol for the package being updated
942+ * @param fullPackageName The full name of the package being updated
943+ * @param oldEntries The classpath that was removed, it is no longer part of fullClasspath
944+ * @param newEntries The classpath that was added, it is already part of fullClasspath
945+ * @param fullClasspath The full classpath, equivalent to global.classPath
946+ * @param invalidated A ListBuffer collecting the invalidated package classes
947+ * @param failed A ListBuffer collecting system package classes which could not be invalidated
948+ *
949+ * If either oldEntries or newEntries contains classes in the current package, the package symbol
950+ * is re-initialized to a fresh package loader, provided that a corresponding package exists in
951+ * fullClasspath. Otherwise it is removed.
952+ *
953+ * Otherwise, sub-packages in newEntries are looked up in the symbol table (created if
954+ * non-existent) and the merge function is called recursively.
955+ */
956+ private def mergeNewEntriesFlat (
957+ packageClass : ClassSymbol , fullPackageName : String ,
958+ oldEntries : FlatClassPath , newEntries : FlatClassPath , fullClasspath : FlatClassPath ,
959+ invalidated : mutable.ListBuffer [ClassSymbol ], failed : mutable.ListBuffer [ClassSymbol ]): Unit = {
960+ ifDebug(informProgress(s " syncing $packageClass, $oldEntries -> $newEntries" ))
961+
962+ def packageExists (cp : FlatClassPath ): Boolean = {
963+ val (parent, _) = PackageNameUtils .separatePkgAndClassNames(fullPackageName)
964+ cp.packages(parent).exists(_.name == fullPackageName)
965+ }
966+
967+ def invalidateOrRemove (pkg : ClassSymbol ) = {
968+ if (packageExists(fullClasspath))
969+ pkg setInfo new loaders.PackageLoaderUsingFlatClassPath (fullPackageName, fullClasspath)
970+ else
971+ pkg.owner.info.decls unlink pkg.sourceModule
972+ invalidated += pkg
973+ }
974+
975+ val classesFound = oldEntries.classes(fullPackageName).nonEmpty || newEntries.classes(fullPackageName).nonEmpty
976+ if (classesFound) {
977+ // if the package contains classes either in oldEntries or newEntries, the package is invalidated (or removed if there are no more classes in it)
978+ if (! isSystemPackageClass(packageClass)) invalidateOrRemove(packageClass)
979+ else if (packageClass.isRoot) invalidateOrRemove(EmptyPackageClass )
980+ else failed += packageClass
981+ } else {
982+ // no new or removed classes in the current package
983+ for (p <- newEntries.packages(fullPackageName)) {
984+ val (_, subPackageName) = PackageNameUtils .separatePkgAndClassNames(p.name)
985+ val subPackage = packageClass.info.decl(newTermName(subPackageName)) orElse {
986+ // package does not exist in symbol table, create a new symbol
987+ loaders.enterPackage(packageClass, subPackageName, new loaders.PackageLoaderUsingFlatClassPath (p.name, fullClasspath))
988+ }
989+ mergeNewEntriesFlat(
990+ subPackage.moduleClass.asClass, p.name,
991+ oldEntries, newEntries, fullClasspath,
992+ invalidated, failed)
993+ }
994+ }
995+ }
996+
920997 // ----------- Runs ---------------------------------------
921998
922999 private var curRun : Run = null
0 commit comments