From 6b498c30038d92c5dd8970656258894e30566104 Mon Sep 17 00:00:00 2001 From: mpociecha Date: Fri, 28 Nov 2014 17:51:56 +0100 Subject: Use new asClassPathString method and create FileUtils for classpath The method asClasspathString is now deprecated. Moreover it's moved to ClassFileLookup in the case someone was using it in some project (an alternative classpath also will support it - just in the case). All its usages existing in Scala sources are changed to asClassPathString method. The only difference is the name. Some operations on files or their names are moved from ClassPath to the newly created FileUtils dedicated to classpath. It will be possible to reuse them when implementing an alternative classpath representation. Moreover such allocation-free extension methods like the one added in this commit will improve the readability. --- src/compiler/scala/tools/nsc/Global.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/compiler/scala/tools/nsc/Global.scala') diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 430424d0f8..2316fb7ce9 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -339,11 +339,11 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } } - if (settings.verbose || settings.Ylogcp) { + if (settings.verbose || settings.Ylogcp) reporter.echo( - s"[search path for source files: ${classPath.sourcepaths.mkString(",")}]\n"+ - s"[search path for class files: ${classPath.asClasspathString}") - } + s"[search path for source files: ${classPath.asSourcePathString}]\n" + + s"[search path for class files: ${classPath.asClassPathString}]" + ) // The current division between scala.reflect.* and scala.tools.nsc.* is pretty // clunky. It is often difficult to have a setting influence something without having @@ -882,7 +882,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) */ def invalidateClassPathEntries(paths: String*): Unit = { implicit object ClassPathOrdering extends Ordering[PlatformClassPath] { - def compare(a:PlatformClassPath, b:PlatformClassPath) = a.asClasspathString compare b.asClasspathString + def compare(a:PlatformClassPath, b:PlatformClassPath) = a.asClassPathString compare b.asClassPathString } val invalidated, failed = new mutable.ListBuffer[ClassSymbol] classPath match { -- cgit v1.2.3 From 04620a0e2a0cf64f2d33e32007d85afabad5e201 Mon Sep 17 00:00:00 2001 From: mpociecha Date: Sun, 30 Nov 2014 22:59:04 +0100 Subject: Integrate flat classpath with the compiler This commit integrates with the compiler the whole flat classpath representation build next to the recursive one as an alternative. From now flat classpath really works and can be turned on. There's added flag -YclasspathImpl with two options: recursive (the default one) and flat. It was needed to make the dynamic dispatch to the particular classpath representation according to the chosen type of a classpath representation. There's added PathResolverFactory which is used instead of a concrete implementation of a path resolver. It turned out that only a small subset of path resolvers methods is used outside this class in Scala sources. Therefore, PathResolverFactory returns an instance of a base interface PathResolverResult providing only these used methods. PathResolverFactory in combination with matches in some other places ensures that in all places using classpath we create/get the proper representation. Also the classPath method in Global is modified to use the dynamic dispatch. This is very important change as a return type changed to the base ClassFileLookup providing subset of old ClassPath public methods. It can be problematic if someone was using in his project the explicit ClassPath type or public methods which are not provided via ClassFileLookup. I tested flat classpath with sbt and Scala IDE and there were no problems. Also was looking at sources of some other projects like e.g. Scala plugin for IntelliJ and there shouldn't be problems, I think, but it would be better to check these changes using the community build. Scalap's Main.scala is changed to be able to use both implementations and also to use flags related to the classpath implementation. The classpath invalidation is modified to work properly with the old (recursive) classpath representation after changes made in a Global. In the case of the attempt to use the invalidation for the flat cp it just throws exception with a message that the flat one currently doesn't support the invalidation. And also that's why the partest's test for the invalidation has been changed to use (always) the old implementation. There's added an adequate comment with TODO to this file. There's added partest test generating various dependencies (directories, zips and jars with sources and class files) and testing whether the compilation and further running an application works correctly, when there are these various types of entries specified as -classpath and -sourcepath. It should be a good approximation of real use cases. --- .../scala/tools/nsc/GenericRunnerSettings.scala | 5 +- src/compiler/scala/tools/nsc/Global.scala | 35 +++- src/compiler/scala/tools/nsc/ObjectRunner.scala | 4 +- src/compiler/scala/tools/nsc/ScriptRunner.scala | 9 +- .../scala/tools/nsc/backend/JavaPlatform.scala | 15 +- .../scala/tools/nsc/backend/Platform.scala | 6 +- .../scala/tools/nsc/settings/ScalaSettings.scala | 7 + .../scala/tools/nsc/symtab/SymbolLoaders.scala | 12 +- .../scala/tools/nsc/transform/AddInterfaces.scala | 40 ++-- src/compiler/scala/tools/reflect/ReflectMain.scala | 6 +- src/compiler/scala/tools/util/PathResolver.scala | 44 +++-- src/repl/scala/tools/nsc/interpreter/IMain.scala | 4 +- src/scalap/scala/tools/scalap/Main.scala | 39 +++- test/files/run/t6502.scala | 27 ++- test/files/run/various-flat-classpath-types.check | 12 ++ test/files/run/various-flat-classpath-types.scala | 214 +++++++++++++++++++++ .../nsc/symtab/SymbolTableForUnitTesting.scala | 29 ++- 17 files changed, 440 insertions(+), 68 deletions(-) create mode 100644 test/files/run/various-flat-classpath-types.check create mode 100644 test/files/run/various-flat-classpath-types.scala (limited to 'src/compiler/scala/tools/nsc/Global.scala') diff --git a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala index ad75d02bff..1289d55c37 100644 --- a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala +++ b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala @@ -5,10 +5,11 @@ package scala.tools.nsc -import scala.tools.util.PathResolver +import java.net.URL +import scala.tools.util.PathResolverFactory class GenericRunnerSettings(error: String => Unit) extends Settings(error) { - def classpathURLs = new PathResolver(this).asURLs + def classpathURLs: Seq[URL] = PathResolverFactory.create(this).resultAsURLs val howtorun = ChoiceSetting( diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 2316fb7ce9..01e8829d6e 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -14,11 +14,10 @@ import scala.compat.Platform.currentTime import scala.collection.{ mutable, immutable } import io.{ SourceReader, AbstractFile, Path } import reporters.{ Reporter, ConsoleReporter } -import util.{ ClassPath, MergedClassPath, StatisticsInfo, returning, stackTraceString } +import util.{ ClassFileLookup, ClassPath, MergedClassPath, StatisticsInfo, returning } import scala.reflect.ClassTag -import scala.reflect.internal.util.{ OffsetPosition, SourceFile, NoSourceFile, BatchSourceFile, ScriptSourceFile } -import scala.reflect.internal.pickling.{ PickleBuffer, PickleFormat } -import scala.reflect.io.VirtualFile +import scala.reflect.internal.util.{ SourceFile, NoSourceFile, BatchSourceFile, ScriptSourceFile } +import scala.reflect.internal.pickling.PickleBuffer import symtab.{ Flags, SymbolTable, SymbolTrackers } import symtab.classfile.Pickler import plugins.Plugins @@ -35,6 +34,8 @@ import backend.opt.{ Inliners, InlineExceptionHandlers, ConstantOptimization, Cl import backend.icode.analysis._ import scala.language.postfixOps import scala.tools.nsc.ast.{TreeGen => AstTreeGen} +import scala.tools.nsc.classpath.FlatClassPath +import scala.tools.nsc.settings.ClassPathRepresentationType class Global(var currentSettings: Settings, var reporter: Reporter) extends SymbolTable @@ -58,7 +59,12 @@ class Global(var currentSettings: Settings, var reporter: Reporter) class GlobalMirror extends Roots(NoSymbol) { val universe: self.type = self - def rootLoader: LazyType = new loaders.PackageLoader(classPath) + def rootLoader: LazyType = { + settings.YclasspathImpl.value match { + case ClassPathRepresentationType.Flat => new loaders.PackageLoaderUsingFlatClassPath(FlatClassPath.RootPackage, flatClassPath) + case ClassPathRepresentationType.Recursive => new loaders.PackageLoader(recursiveClassPath) + } + } override def toString = "compiler mirror" } implicit val MirrorTag: ClassTag[Mirror] = ClassTag[Mirror](classOf[GlobalMirror]) @@ -104,7 +110,14 @@ class Global(var currentSettings: Settings, var reporter: Reporter) type PlatformClassPath = ClassPath[AbstractFile] type OptClassPath = Option[PlatformClassPath] - def classPath: PlatformClassPath = platform.classPath + def classPath: ClassFileLookup[AbstractFile] = settings.YclasspathImpl.value match { + case ClassPathRepresentationType.Flat => flatClassPath + case ClassPathRepresentationType.Recursive => recursiveClassPath + } + + private def recursiveClassPath: ClassPath[AbstractFile] = platform.classPath + + private def flatClassPath: FlatClassPath = platform.flatClassPath // sub-components -------------------------------------------------- @@ -846,6 +859,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** Extend classpath of `platform` and rescan updated packages. */ def extendCompilerClassPath(urls: URL*): Unit = { + if (settings.YclasspathImpl.value == ClassPathRepresentationType.Flat) + throw new UnsupportedOperationException("Flat classpath doesn't support extending the compiler classpath") + val newClassPath = platform.classPath.mergeUrlsIntoClassPath(urls: _*) platform.currentClassPath = Some(newClassPath) // Reload all specified jars into this compiler instance @@ -881,6 +897,9 @@ 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 } @@ -910,10 +929,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter) informProgress(s"classpath updated on entries [${subst.keys mkString ","}]") def mkClassPath(elems: Iterable[PlatformClassPath]): PlatformClassPath = if (elems.size == 1) elems.head - else new MergedClassPath(elems, classPath.context) + else new MergedClassPath(elems, recursiveClassPath.context) val oldEntries = mkClassPath(subst.keys) val newEntries = mkClassPath(subst.values) - mergeNewEntries(newEntries, RootClass, Some(classPath), Some(oldEntries), invalidated, failed) + mergeNewEntries(newEntries, RootClass, Some(recursiveClassPath), Some(oldEntries), invalidated, failed) } } def show(msg: String, syms: scala.collection.Traversable[Symbol]) = diff --git a/src/compiler/scala/tools/nsc/ObjectRunner.scala b/src/compiler/scala/tools/nsc/ObjectRunner.scala index 95264aeda6..7c14f4943f 100644 --- a/src/compiler/scala/tools/nsc/ObjectRunner.scala +++ b/src/compiler/scala/tools/nsc/ObjectRunner.scala @@ -18,14 +18,14 @@ trait CommonRunner { * @throws NoSuchMethodException * @throws InvocationTargetException */ - def run(urls: List[URL], objectName: String, arguments: Seq[String]) { + def run(urls: Seq[URL], objectName: String, arguments: Seq[String]) { (ScalaClassLoader fromURLs urls).run(objectName, arguments) } /** Catches exceptions enumerated by run (in the case of InvocationTargetException, * unwrapping it) and returns it any thrown in Left(x). */ - def runAndCatch(urls: List[URL], objectName: String, arguments: Seq[String]): Either[Throwable, Boolean] = { + def runAndCatch(urls: Seq[URL], objectName: String, arguments: Seq[String]): Either[Throwable, Boolean] = { try { run(urls, objectName, arguments) ; Right(true) } catch { case e: Throwable => Left(unwrap(e)) } } diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala index 7d5c6f6fff..6d24b31531 100644 --- a/src/compiler/scala/tools/nsc/ScriptRunner.scala +++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala @@ -8,7 +8,10 @@ package tools.nsc import io.{ AbstractFile, Directory, File, Path } import java.io.IOException +import scala.tools.nsc.classpath.DirectoryFlatClassPath import scala.tools.nsc.reporters.{Reporter,ConsoleReporter} +import scala.tools.nsc.settings.ClassPathRepresentationType +import scala.tools.nsc.util.ClassPath.DefaultJavaContext import util.Exceptional.unwrap /** An object that runs Scala code in script files. @@ -112,8 +115,10 @@ class ScriptRunner extends HasCompileSocket { } def hasClassToRun(d: Directory): Boolean = { - import util.ClassPath.{ DefaultJavaContext => ctx } - val cp = ctx.newClassPath(AbstractFile.getDirectory(d)) + val cp = settings.YclasspathImpl.value match { + case ClassPathRepresentationType.Recursive => DefaultJavaContext.newClassPath(AbstractFile.getDirectory(d)) + case ClassPathRepresentationType.Flat => DirectoryFlatClassPath(d.jfile) + } cp.findClass(mainClass).isDefined } diff --git a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala index 4877bd9b80..6bd123c51f 100644 --- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala +++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala @@ -7,7 +7,10 @@ package scala.tools.nsc package backend import io.AbstractFile -import util.{ClassPath,MergedClassPath,DeltaClassPath} +import scala.tools.nsc.classpath.FlatClassPath +import scala.tools.nsc.settings.ClassPathRepresentationType +import scala.tools.nsc.util.{ ClassPath, DeltaClassPath, MergedClassPath } +import scala.tools.util.FlatClassPathResolver import scala.tools.util.PathResolver trait JavaPlatform extends Platform { @@ -19,10 +22,20 @@ trait JavaPlatform extends Platform { private[nsc] var currentClassPath: Option[MergedClassPath[AbstractFile]] = None def classPath: ClassPath[AbstractFile] = { + assert(settings.YclasspathImpl.value == ClassPathRepresentationType.Recursive, + "To use recursive classpath representation you must enable it with -YclasspathImpl:recursive compiler option.") + if (currentClassPath.isEmpty) currentClassPath = Some(new PathResolver(settings).result) currentClassPath.get } + private[nsc] lazy val 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 + } + /** Update classpath with a substituted subentry */ def updateClassPath(subst: Map[ClassPath[AbstractFile], ClassPath[AbstractFile]]) = currentClassPath = Some(new DeltaClassPath(currentClassPath.get, subst)) diff --git a/src/compiler/scala/tools/nsc/backend/Platform.scala b/src/compiler/scala/tools/nsc/backend/Platform.scala index 439cc1efb8..c3bc213be1 100644 --- a/src/compiler/scala/tools/nsc/backend/Platform.scala +++ b/src/compiler/scala/tools/nsc/backend/Platform.scala @@ -8,6 +8,7 @@ package backend import util.ClassPath import io.AbstractFile +import scala.tools.nsc.classpath.FlatClassPath /** The platform dependent pieces of Global. */ @@ -15,9 +16,12 @@ trait Platform { val symbolTable: symtab.SymbolTable import symbolTable._ - /** The compiler classpath. */ + /** The old, recursive implementation of compiler classpath. */ def classPath: ClassPath[AbstractFile] + /** The new implementation of compiler classpath. */ + private[nsc] def flatClassPath: FlatClassPath + /** Update classpath with a substitution that maps entries to entries */ def updateClassPath(subst: Map[ClassPath[AbstractFile], ClassPath[AbstractFile]]) diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index d6650595eb..e259c543cf 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -202,6 +202,8 @@ trait ScalaSettings extends AbsScalaSettings val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overriden 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 YvirtClasses = false // too embryonic to even expose as a -Y //BooleanSetting ("-Yvirtual-classes", "Support virtual classes") val YdisableUnreachablePrevention = BooleanSetting("-Ydisable-unreachable-prevention", "Disable the prevention of unreachable blocks in code generation.") val YnoLoadImplClass = BooleanSetting ("-Yno-load-impl-class", "Do not load $class.class files.") @@ -329,3 +331,8 @@ trait ScalaSettings extends AbsScalaSettings val Discard = "discard" } } + +object ClassPathRepresentationType { + val Flat = "flat" + val Recursive = "recursive" +} diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 3b1ce2fd5c..6386da5725 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -6,14 +6,15 @@ package scala.tools.nsc package symtab +import classfile.ClassfileParser import java.io.IOException import scala.compat.Platform.currentTime -import scala.tools.nsc.util.{ ClassPath, ClassRepresentation } -import classfile.ClassfileParser import scala.reflect.internal.MissingRequirementError import scala.reflect.internal.util.Statistics import scala.reflect.io.{ AbstractFile, NoAbstractFile } import scala.tools.nsc.classpath.FlatClassPath +import scala.tools.nsc.settings.ClassPathRepresentationType +import scala.tools.nsc.util.{ ClassPath, ClassRepresentation } /** This class ... * @@ -327,8 +328,13 @@ abstract class SymbolLoaders { * */ private type SymbolLoadersRefined = SymbolLoaders { val symbolTable: classfileParser.symbolTable.type } + val loaders = SymbolLoaders.this.asInstanceOf[SymbolLoadersRefined] - override def classFileLookup: util.ClassFileLookup[AbstractFile] = platform.classPath + + override def classFileLookup: util.ClassFileLookup[AbstractFile] = settings.YclasspathImpl.value match { + case ClassPathRepresentationType.Recursive => platform.classPath + case ClassPathRepresentationType.Flat => platform.flatClassPath + } } protected def description = "class file "+ classfile.toString diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index 2b7c6cca2c..c5f46dc140 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -8,6 +8,7 @@ package transform import symtab._ import Flags._ +import scala.tools.nsc.util.ClassPath abstract class AddInterfaces extends InfoTransform { self: Erasure => import global._ // the global environment @@ -67,25 +68,30 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => val implName = tpnme.implClassName(iface.name) val implFlags = (iface.flags & ~(INTERFACE | lateINTERFACE)) | IMPLCLASS - val impl0 = ( + val impl0 = { if (!inClass) NoSymbol - else iface.owner.info.decl(implName) match { - case NoSymbol => NoSymbol - case implSym => - // Unlink a pre-existing symbol only if the implementation class is - // visible on the compilation classpath. In general this is true under - // -optimise and not otherwise, but the classpath can use arbitrary - // logic so the classpath must be queried. - if (classPath.context.isValidName(implName + ".class")) { - iface.owner.info.decls unlink implSym - NoSymbol - } - else { - log(s"not unlinking $iface's existing implClass ${implSym.name} because it is not on the classpath.") - implSym - } + else { + val typeInfo = iface.owner.info + typeInfo.decl(implName) match { + case NoSymbol => NoSymbol + case implSym => + // Unlink a pre-existing symbol only if the implementation class is + // visible on the compilation classpath. In general this is true under + // -optimise and not otherwise, but the classpath can use arbitrary + // logic so the classpath must be queried. + // TODO this is not taken into account by flat classpath yet + classPath match { + case cp: ClassPath[_] if !cp.context.isValidName(implName + ".class") => + log(s"not unlinking $iface's existing implClass ${implSym.name} because it is not on the classpath.") + implSym + case _ => + typeInfo.decls unlink implSym + NoSymbol + } + } } - ) + } + val impl = impl0 orElse { val impl = iface.owner.newImplClass(implName, iface.pos, implFlags) if (iface.thisSym != iface) { diff --git a/src/compiler/scala/tools/reflect/ReflectMain.scala b/src/compiler/scala/tools/reflect/ReflectMain.scala index 3ae21b6b98..a998a44643 100644 --- a/src/compiler/scala/tools/reflect/ReflectMain.scala +++ b/src/compiler/scala/tools/reflect/ReflectMain.scala @@ -5,13 +5,13 @@ import scala.tools.nsc.Driver import scala.tools.nsc.Global import scala.tools.nsc.Settings import scala.tools.nsc.util.ScalaClassLoader -import scala.tools.util.PathResolver +import scala.tools.util.PathResolverFactory object ReflectMain extends Driver { private def classloaderFromSettings(settings: Settings) = { - val classpath = new PathResolver(settings).result - ScalaClassLoader.fromURLs(classpath.asURLs, getClass.getClassLoader) + val classPathURLs = PathResolverFactory.create(settings).resultAsURLs + ScalaClassLoader.fromURLs(classPathURLs, getClass.getClassLoader) } override def newCompiler(): Global = new ReflectGlobal(settings, reporter, classloaderFromSettings(settings)) diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala index 797abc085c..315476953d 100644 --- a/src/compiler/scala/tools/util/PathResolver.scala +++ b/src/compiler/scala/tools/util/PathResolver.scala @@ -9,7 +9,7 @@ package util import java.net.URL import scala.tools.reflect.WrappedProperties.AccessControl -import scala.tools.nsc.{ Settings } +import scala.tools.nsc.Settings import scala.tools.nsc.util.{ ClassFileLookup, ClassPath, JavaClassPath } import scala.reflect.io.{ File, Directory, Path, AbstractFile } import scala.reflect.runtime.ReflectionUtils @@ -17,6 +17,7 @@ import ClassPath.{ JavaContext, DefaultJavaContext, join, split } import PartialFunction.condOpt import scala.language.postfixOps import scala.tools.nsc.classpath.{ AggregateFlatClassPath, ClassPathFactory, FlatClassPath, FlatClassPathFactory } +import scala.tools.nsc.settings.ClassPathRepresentationType // Loosely based on the draft specification at: // https://wiki.scala-lang.org/display/SIW/Classpath @@ -172,7 +173,7 @@ object PathResolver { !ReflectionUtils.scalacShouldntLoadClassfile(name) } - // called from scalap + @deprecated("This method is no longer used be scalap and will be deleted", "2.11.5") def fromPathString(path: String, context: JavaContext = DefaultJavaContext): JavaClassPath = { val s = new Settings() s.classpath.value = path @@ -183,24 +184,35 @@ object PathResolver { * If there are arguments, show those in Calculated as if those options had been * given to a scala runner. */ - def main(args: Array[String]): Unit = { + def main(args: Array[String]): Unit = if (args.isEmpty) { println(Environment) println(Defaults) - } - else { + } else { val settings = new Settings() val rest = settings.processArguments(args.toList, processAll = false)._2 - val pr = new PathResolver(settings) - println(" COMMAND: 'scala %s'".format(args.mkString(" "))) + val pr = PathResolverFactory.create(settings) + println("COMMAND: 'scala %s'".format(args.mkString(" "))) println("RESIDUAL: 'scala %s'\n".format(rest.mkString(" "))) - pr.result.show() + + pr.result match { + case cp: JavaClassPath => + cp.show() + case cp: AggregateFlatClassPath => + println(s"ClassPath has ${cp.aggregates.size} entries and results in:\n${cp.asClassPathStrings}") + } } - } +} + +trait PathResolverResult { + def result: ClassFileLookup[AbstractFile] + + def resultAsURLs: Seq[URL] = result.asURLs } abstract class PathResolverBase[BaseClassPathType <: ClassFileLookup[AbstractFile], ResultClassPathType <: BaseClassPathType] -(settings: Settings, classPathFactory: ClassPathFactory[BaseClassPathType]) { +(settings: Settings, classPathFactory: ClassPathFactory[BaseClassPathType]) + extends PathResolverResult { import PathResolver.{ AsLines, Defaults, ppcp } @@ -304,7 +316,8 @@ abstract class PathResolverBase[BaseClassPathType <: ClassFileLookup[AbstractFil cp } - def asURLs: List[URL] = result.asURLs.toList + @deprecated("Use resultAsURLs instead of this one", "2.11.5") + def asURLs: List[URL] = resultAsURLs.toList protected def computeResult(): ResultClassPathType } @@ -328,3 +341,12 @@ class FlatClassPathResolver(settings: Settings, flatClassPathFactory: ClassPathF override protected def computeResult(): AggregateFlatClassPath = AggregateFlatClassPath(containers.toIndexedSeq) } + +object PathResolverFactory { + + def create(settings: Settings): PathResolverResult = + settings.YclasspathImpl.value match { + case ClassPathRepresentationType.Flat => new FlatClassPathResolver(settings) + case ClassPathRepresentationType.Recursive => new PathResolver(settings) + } +} diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index b990e401ec..63d95b32b7 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -15,7 +15,7 @@ import scala.concurrent.{ Future, ExecutionContext } import scala.reflect.runtime.{ universe => ru } import scala.reflect.{ ClassTag, classTag } import scala.reflect.internal.util.{ BatchSourceFile, SourceFile } -import scala.tools.util.PathResolver +import scala.tools.util.PathResolverFactory import scala.tools.nsc.io.AbstractFile import scala.tools.nsc.typechecker.{ TypeStrings, StructuredTypeStrings } import scala.tools.nsc.util.{ ScalaClassLoader, stringFromReader, stringFromWriter, StackTraceOps, ClassPath, MergedClassPath } @@ -90,7 +90,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set def compilerClasspath: Seq[java.net.URL] = ( if (isInitializeComplete) global.classPath.asURLs - else new PathResolver(settings).result.asURLs // the compiler's classpath + else PathResolverFactory.create(settings).resultAsURLs // the compiler's classpath ) def settings = initialSettings // Run the code body with the given boolean settings flipped to true. diff --git a/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala index dc3bf64060..0e0970db1f 100644 --- a/src/scalap/scala/tools/scalap/Main.scala +++ b/src/scalap/scala/tools/scalap/Main.scala @@ -10,11 +10,15 @@ package tools.scalap import java.io.{ PrintStream, OutputStreamWriter, ByteArrayOutputStream } import scala.reflect.NameTransformer +import scala.tools.nsc.Settings +import scala.tools.nsc.classpath.AggregateFlatClassPath +import scala.tools.nsc.classpath.FlatClassPathFactory import scala.tools.nsc.io.AbstractFile +import scala.tools.nsc.settings.ClassPathRepresentationType import scala.tools.nsc.util.ClassFileLookup -import scala.tools.nsc.util.JavaClassPath import scala.tools.nsc.util.ClassPath.DefaultJavaContext -import scala.tools.util.PathResolver +import scala.tools.nsc.util.JavaClassPath +import scala.tools.util.PathResolverFactory import scalax.rules.scalasig._ /**The main object used to execute scalap on the command-line. @@ -139,6 +143,9 @@ object Main extends Main { val showPrivateDefs = "-private" val verbose = "-verbose" val version = "-version" + + val classPathImplType = "-YclasspathImpl" + val logClassPath = "-Ylog-classpath" } /** Prints usage information for scalap. */ @@ -170,11 +177,14 @@ object Main extends Main { verbose = arguments contains opts.verbose printPrivates = arguments contains opts.showPrivateDefs // construct a custom class path - val cpArg = List(opts.classpath, opts.cp) map (arguments getArgument _) reduceLeft (_ orElse _) - val path = cpArg match { - case Some(cp) => new JavaClassPath(DefaultJavaContext.classesInExpandedPath(cp), DefaultJavaContext) - case _ => PathResolver.fromPathString(".") // include '.' in the default classpath SI-6669 - } + val cpArg = List(opts.classpath, opts.cp) map (arguments getArgument) reduceLeft (_ orElse _) + + val settings = new Settings() + + arguments getArgument opts.classPathImplType foreach settings.YclasspathImpl.tryToSetFromPropertyValue + settings.Ylogcp.value = arguments contains opts.logClassPath + + val path = createClassPath(cpArg, settings) // print the classpath if output is verbose if (verbose) @@ -192,5 +202,20 @@ object Main extends Main { .withOption(opts.help) .withOptionalArg(opts.classpath) .withOptionalArg(opts.cp) + // TODO two temporary, hidden options to be able to test different classpath representations + .withOptionalArg(opts.classPathImplType) + .withOption(opts.logClassPath) .parse(args) + + private def createClassPath(cpArg: Option[String], settings: Settings) = cpArg match { + case Some(cp) => settings.YclasspathImpl.value match { + case ClassPathRepresentationType.Flat => + AggregateFlatClassPath(new FlatClassPathFactory(settings).classesInExpandedPath(cp)) + case ClassPathRepresentationType.Recursive => + new JavaClassPath(DefaultJavaContext.classesInExpandedPath(cp), DefaultJavaContext) + } + case _ => + settings.classpath.value = "." // include '.' in the default classpath SI-6669 + PathResolverFactory.create(settings).result + } } diff --git a/test/files/run/t6502.scala b/test/files/run/t6502.scala index ced1b5812d..4ce034a482 100644 --- a/test/files/run/t6502.scala +++ b/test/files/run/t6502.scala @@ -1,6 +1,7 @@ -import scala.tools.partest._ -import java.io.File +import scala.tools.nsc.Settings import scala.tools.nsc.interpreter.ILoop +import scala.tools.nsc.settings.ClassPathRepresentationType +import scala.tools.partest._ object Test extends StoreReporterDirectTest { def code = ??? @@ -10,6 +11,14 @@ object Test extends StoreReporterDirectTest { compileString(newCompiler("-cp", classpath, "-d", s"${testOutput.path}/$jarFileName"))(code) } + // TODO flat classpath doesn't support the classpath invalidation yet so we force using the recursive one + // it's the only test which needed such a workaround + override def settings = { + val settings = new Settings + settings.YclasspathImpl.value = ClassPathRepresentationType.Recursive + settings + } + def app1 = """ package test @@ -41,7 +50,8 @@ object Test extends StoreReporterDirectTest { val jar = "test1.jar" compileCode(app1, jar) - val output = ILoop.run(List(s":require ${testOutput.path}/$jar", "test.Test.test()")) + val codeToRun = toCodeInSeparateLines(s":require ${testOutput.path}/$jar", "test.Test.test()") + val output = ILoop.run(codeToRun, settings) val lines = output.split("\n") val res1 = lines(4).contains("Added") && lines(4).contains("test1.jar") val res2 = lines(lines.length-3).contains("testing...") @@ -56,7 +66,8 @@ object Test extends StoreReporterDirectTest { val jar2 = "test2.jar" compileCode(app2, jar2) - val output = ILoop.run(List(s":require ${testOutput.path}/$jar1", s":require ${testOutput.path}/$jar2")) + val codeToRun = toCodeInSeparateLines(s":require ${testOutput.path}/$jar1", s":require ${testOutput.path}/$jar2") + val output = ILoop.run(codeToRun, settings) val lines = output.split("\n") val res1 = lines(4).contains("Added") && lines(4).contains("test1.jar") val res2 = lines(lines.length-3).contains("test2.jar") && lines(lines.length-3).contains("existing classpath entries conflict") @@ -71,7 +82,8 @@ object Test extends StoreReporterDirectTest { val jar3 = "test3.jar" compileCode(app3, jar3) - val output = ILoop.run(List(s":require ${testOutput.path}/$jar1", s":require ${testOutput.path}/$jar3", "test.Test3.test()")) + val codeToRun = toCodeInSeparateLines(s":require ${testOutput.path}/$jar1", s":require ${testOutput.path}/$jar3", "test.Test3.test()") + val output = ILoop.run(codeToRun, settings) val lines = output.split("\n") val res1 = lines(4).contains("Added") && lines(4).contains("test1.jar") val res2 = lines(lines.length-3).contains("new object in existing package") @@ -83,7 +95,8 @@ object Test extends StoreReporterDirectTest { def test4(): Unit = { // twice the same jar should be rejected val jar1 = "test1.jar" - val output = ILoop.run(List(s":require ${testOutput.path}/$jar1", s":require ${testOutput.path}/$jar1")) + val codeToRun = toCodeInSeparateLines(s":require ${testOutput.path}/$jar1", s":require ${testOutput.path}/$jar1") + val output = ILoop.run(codeToRun, settings) val lines = output.split("\n") val res1 = lines(4).contains("Added") && lines(4).contains("test1.jar") val res2 = lines(lines.length-3).contains("test1.jar") && lines(lines.length-3).contains("existing classpath entries conflict") @@ -98,4 +111,6 @@ object Test extends StoreReporterDirectTest { test3() test4() } + + def toCodeInSeparateLines(lines: String*): String = lines.map(_ + "\n").mkString } diff --git a/test/files/run/various-flat-classpath-types.check b/test/files/run/various-flat-classpath-types.check new file mode 100644 index 0000000000..401f707d0e --- /dev/null +++ b/test/files/run/various-flat-classpath-types.check @@ -0,0 +1,12 @@ +ZipBin() +JarBin() +DirBin() +ZipSrc() +JarSrc() +DirSrc() +NestedZipBin() +NestedJarBin() +NestedDirBin() +NestedZipSrc() +NestedJarSrc() +NestedDirSrc() \ No newline at end of file diff --git a/test/files/run/various-flat-classpath-types.scala b/test/files/run/various-flat-classpath-types.scala new file mode 100644 index 0000000000..d39019e885 --- /dev/null +++ b/test/files/run/various-flat-classpath-types.scala @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2014 Contributor. All rights reserved. + */ + +import java.io.{File => JFile, FileInputStream, FileOutputStream} +import java.util.zip.{ZipEntry, ZipOutputStream} +import scala.reflect.io.{Directory, File} +import scala.tools.nsc.classpath.FlatClassPath.RootPackage +import scala.tools.nsc.classpath.PackageNameUtils +import scala.tools.nsc.io.Jar + +/** + * Generates directories, jars and zip files containing sources and classes + * (the result of a compilation which is executed here) + * and use them as a class- and sourcepath during compilation and running + * created application. At the end everything is cleaned up. + * + * It can test also current, recursive classpath. Just right now we force + * flat classpath to test it also when the recursive one would be set as a default. + */ +object Test { + + private implicit class JFileOps(file: JFile) { + + def createDir(newDirName: String) = { + val newDir = new JFile(file, newDirName) + newDir.mkdir() + newDir + } + + def createSrcFile(newFileName: String) = createFile(newFileName + ".scala") + + def createFile(fullFileName: String) = { + val newFile = new JFile(file, fullFileName) + newFile.createNewFile() + newFile + } + + def writeAll(text: String): Unit = File(file) writeAll text + + def moveContentToZip(zipName: String): Unit = { + val newZip = zipsDir createFile s"$zipName.zip" + val outputStream = new ZipOutputStream(new FileOutputStream(newZip)) + + def addFileToZip(dirPrefix: String = "")(fileToAdd: JFile): Unit = + if (fileToAdd.isDirectory) { + val dirEntryName = fileToAdd.getName + "/" + outputStream.putNextEntry(new ZipEntry(dirEntryName)) + fileToAdd.listFiles() foreach addFileToZip(dirEntryName) + } else { + val inputStream = new FileInputStream(fileToAdd) + outputStream.putNextEntry(new ZipEntry(dirPrefix + fileToAdd.getName)) + + val buffer = new Array[Byte](1024) + var count = inputStream.read(buffer) + while (count > 0) { + outputStream.write(buffer, 0, count) + count = inputStream.read(buffer) + } + + inputStream.close() + } + + file.listFiles() foreach addFileToZip() + outputStream.close() + + cleanDir(file) + } + + def moveContentToJar(jarName: String): Unit = { + val newJar = jarsDir createFile s"$jarName.jar" + Jar.create(file = File(newJar), sourceDir = Directory(file), mainClass = "won't be used") + cleanDir(file) + } + + def path: String = file.getAbsolutePath + } + + private case class DirRep(name: String, nestedDirs: Seq[DirRep] = Nil, sourceFiles: Seq[String] = Nil) + + private val compiler = new scala.tools.nsc.MainClass + private val appRunner = new scala.tools.nsc.MainGenericRunner + private val classPathImplFlag = "-YclasspathImpl:flat" + private val javaClassPath = sys.props("java.class.path") + + // creates a test dir in a temporary dir containing compiled files of this test + // root dir will be automatically deleted after the end of test + private val rootDir = new JFile(sys.props("partest.output")) + private val testDir = rootDir createDir s"cp-tests-${System.currentTimeMillis()}" + + private val jarsDir = testDir createDir "jars" + private val zipsDir = testDir createDir "zips" + private val srcDir = testDir createDir "src" + private val binDir = testDir createDir "bin" + private val outDir = testDir createDir "out" + + def main(args: Array[String]): Unit = { + createClassesZipInZipsDir() + createClassesJarInJarsDir() + createClassesInBinDir() + createSourcesZipInZipsDir() + createSourcesJarInJarsDir() + createSourcesInSrcDir() + compileFinalApp() + runApp() + // at the end all created files will be deleted automatically + } + + private def createClassesZipInZipsDir(): Unit = { + val baseFileName = "ZipBin" + createStandardSrcHierarchy(baseFileName) + compileSrc(baseFileName) + outDir moveContentToZip "Bin" + cleanDir(srcDir) + } + + private def createClassesJarInJarsDir(): Unit = { + val baseFileName = "JarBin" + createStandardSrcHierarchy(baseFileName) + compileSrc(baseFileName) + outDir moveContentToJar "Bin" + cleanDir(srcDir) + } + + private def createClassesInBinDir(): Unit = { + val baseFileName = "DirBin" + createStandardSrcHierarchy(baseFileName) + compileSrc(baseFileName, destination = binDir) + cleanDir(srcDir) + } + + private def createSourcesZipInZipsDir(): Unit = { + createStandardSrcHierarchy(baseFileName = "ZipSrc") + srcDir moveContentToZip "Src" + } + + private def createSourcesJarInJarsDir(): Unit = { + createStandardSrcHierarchy(baseFileName = "JarSrc") + srcDir moveContentToJar "Src" + } + + private def createSourcesInSrcDir(): Unit = { + createStandardSrcHierarchy(baseFileName = "DirSrc") + + val appFile = srcDir createSrcFile "Main" + appFile writeAll s"""import nested._ + | object Main extends App { + | println(new ZipBin) + | println(new JarBin) + | println(new DirBin) + | println(new ZipSrc) + | println(new JarSrc) + | println(new DirSrc) + | + | println(new NestedZipBin) + | println(new NestedJarBin) + | println(new NestedDirBin) + | println(new NestedZipSrc) + | println(new NestedJarSrc) + | println(new NestedDirSrc) + | } + """.stripMargin + } + + private def compileFinalApp(): Unit = { + val classPath = mkPath(javaClassPath, binDir.path, zipsDir.path + "/Bin.zip", jarsDir.path + "/Bin.jar") + val sourcePath = mkPath(srcDir.path, zipsDir.path + "/Src.zip", jarsDir.path + "/Src.jar") + + compiler.process(Array(classPathImplFlag, "-cp", classPath, "-sourcepath", sourcePath, + "-d", outDir.path, s"${srcDir.path}/Main.scala")) + } + + private def runApp(): Unit = { + val classPath = mkPath(javaClassPath, outDir.path, binDir.path, zipsDir.path + "/Bin.zip", jarsDir.path + "/Bin.jar") + appRunner.process(Array(classPathImplFlag, "-cp", classPath, "Main")) + } + + private def createStandardSrcHierarchy(baseFileName: String): Unit = + createSources(RootPackage, srcDir, + DirRep("", + nestedDirs = Seq(DirRep("nested", sourceFiles = Seq("Nested" + baseFileName))), + sourceFiles = Seq(baseFileName) + ) + ) + + private def createSources(pkg: String, dirFile: JFile, dirRep: DirRep): Unit = { + dirRep.nestedDirs foreach { rep => + val nestedDir = dirFile createDir rep.name + val nestedPkg = PackageNameUtils.packagePrefix(pkg) + rep.name + createSources(nestedPkg, nestedDir, rep) + } + + val pkgHeader = if (pkg == RootPackage) "" else s"package $pkg\n\n" + dirRep.sourceFiles foreach { srcName => + val text = s"""${pkgHeader}case class $srcName(x: String = "")""" + val srcFile = dirFile createSrcFile srcName + srcFile writeAll text + } + } + + private def compileSrc(baseFileName: String, destination: JFile = outDir): Unit = { + val srcDirPath = srcDir.path + compiler.process(Array(classPathImplFlag, "-cp", javaClassPath, "-d", destination.path, + s"$srcDirPath/$baseFileName.scala", s"$srcDirPath/nested/Nested$baseFileName.scala")) + } + + private def cleanDir(dir: JFile): Unit = + dir.listFiles().foreach { file => + if (file.isDirectory) cleanDir(file) + file.delete() + } + + private def mkPath(pathEntries: String*) = pathEntries.mkString(File.pathSeparator) +} diff --git a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala index e4be42ac96..d61c62784c 100644 --- a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala +++ b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala @@ -3,6 +3,9 @@ package symtab import scala.reflect.ClassTag import scala.reflect.internal.{Phase, NoPhase, SomePhase} +import scala.tools.nsc.classpath.FlatClassPath +import scala.tools.nsc.settings.ClassPathRepresentationType +import scala.tools.util.FlatClassPathResolver import scala.tools.util.PathResolver import util.ClassPath import io.AbstractFile @@ -26,13 +29,28 @@ class SymbolTableForUnitTesting extends SymbolTable { class LazyTreeCopier extends super.LazyTreeCopier with TreeCopier override def isCompilerUniverse: Boolean = true - def classPath = new PathResolver(settings).result + + def classPath = platform.classPath + def flatClassPath: FlatClassPath = platform.flatClassPath object platform extends backend.Platform { val symbolTable: SymbolTableForUnitTesting.this.type = SymbolTableForUnitTesting.this lazy val loaders: SymbolTableForUnitTesting.this.loaders.type = SymbolTableForUnitTesting.this.loaders + def platformPhases: List[SubComponent] = Nil - val classPath: ClassPath[AbstractFile] = new PathResolver(settings).result + + lazy val classPath: ClassPath[AbstractFile] = { + assert(settings.YclasspathImpl.value == ClassPathRepresentationType.Recursive, + "It's not possible to use the recursive classpath representation, when it's not the chosen classpath scanning method") + new PathResolver(settings).result + } + + private[nsc] lazy val flatClassPath: FlatClassPath = { + assert(settings.YclasspathImpl.value == ClassPathRepresentationType.Flat, + "It's not possible to use the flat classpath representation, when it's not the chosen classpath scanning method") + new FlatClassPathResolver(settings).result + } + def isMaybeBoxed(sym: Symbol): Boolean = ??? def needCompile(bin: AbstractFile, src: AbstractFile): Boolean = ??? def externalEquals: Symbol = ??? @@ -50,7 +68,12 @@ class SymbolTableForUnitTesting extends SymbolTable { class GlobalMirror extends Roots(NoSymbol) { val universe: SymbolTableForUnitTesting.this.type = SymbolTableForUnitTesting.this - def rootLoader: LazyType = new loaders.PackageLoader(classPath) + + def rootLoader: LazyType = settings.YclasspathImpl.value match { + case ClassPathRepresentationType.Flat => new loaders.PackageLoaderUsingFlatClassPath(FlatClassPath.RootPackage, flatClassPath) + case ClassPathRepresentationType.Recursive => new loaders.PackageLoader(classPath) + } + override def toString = "compiler mirror" } -- cgit v1.2.3 From a8c43dc5caf7439dbcb47f6c25b33fb6b3ed8705 Mon Sep 17 00:00:00 2001 From: mpociecha Date: Sun, 30 Nov 2014 23:52:37 +0100 Subject: Cleanup and refactoring - semicolons, unused or commented out code This commit contains some minor changes made by the way when implementing flat classpath. Sample JUnit test that shows that all pieces of JUnit infrastructure work correctly now uses assert method form JUnit as it should do from the beginning. I removed commented out lines which were obvious to me. In the case of less obvious commented out lines I added TODOs as someone should look at such places some day and clean them up. I removed also some unnecessary semicolons and unused imports. Many string concatenations using + have been changed to string interpolation. There's removed unused, private walkIterator method from ZipArchive. It seems that it was unused since this commit: https://github.com/scala/scala/commit/9d4994b96c77d914687433586eb6d1f9e49c520f However, I had to add an exception for the compatibility checker because it was complaining about this change. I made some trivial corrections/optimisations like use 'findClassFile' method instead of 'findClass' in combination with 'binary' to find the class file. --- bincompat-backward.whitelist.conf | 5 +++++ bincompat-forward.whitelist.conf | 13 +++++++++++++ src/compiler/scala/tools/nsc/Global.scala | 4 ++-- src/compiler/scala/tools/nsc/PhaseAssembly.scala | 2 +- src/compiler/scala/tools/nsc/plugins/Plugins.scala | 2 +- .../scala/tools/nsc/symtab/SymbolLoaders.scala | 5 ++--- .../scala/tools/nsc/transform/AddInterfaces.scala | 1 + src/compiler/scala/tools/reflect/ReflectMain.scala | 2 +- src/compiler/scala/tools/util/PathResolver.scala | 15 ++++++--------- .../scala/tools/nsc/interactive/Global.scala | 4 ++-- .../scala/tools/partest/BytecodeTest.scala | 6 ++---- .../scala/reflect/internal/SymbolTable.scala | 1 - src/reflect/scala/reflect/internal/Symbols.scala | 5 ++--- .../internal/settings/MutableSettings.scala | 3 +++ src/reflect/scala/reflect/io/VirtualFile.scala | 4 ++-- src/reflect/scala/reflect/io/ZipArchive.scala | 21 +++++++-------------- src/repl/scala/tools/nsc/interpreter/IMain.scala | 8 +++++--- src/scalap/scala/tools/scalap/Arguments.scala | 22 +++++++++++----------- src/scalap/scala/tools/scalap/Main.scala | 2 +- test/junit/scala/tools/nsc/SampleTest.scala | 2 +- .../nsc/symtab/SymbolTableForUnitTesting.scala | 2 +- test/script-tests/README | 7 ++++++- 22 files changed, 75 insertions(+), 61 deletions(-) (limited to 'src/compiler/scala/tools/nsc/Global.scala') diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf index 56d5b0135c..a1706d103d 100644 --- a/bincompat-backward.whitelist.conf +++ b/bincompat-backward.whitelist.conf @@ -203,6 +203,11 @@ filter { { matchName="scala.reflect.runtime.ThreadLocalStorage#MyThreadLocalStorage.values" problemName=MissingMethodProblem + }, + // the below method was the unused private (sic!) method but the compatibility checker was complaining about it + { + matchName="scala.reflect.io.ZipArchive.scala$reflect$io$ZipArchive$$walkIterator" + problemName=MissingMethodProblem } ] } diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf index 228b746fa1..13e4f4ba85 100644 --- a/bincompat-forward.whitelist.conf +++ b/bincompat-forward.whitelist.conf @@ -301,6 +301,19 @@ filter { { matchName="scala.reflect.io.FileZipArchive.root" problemName=MissingMethodProblem + }, + // introduced the harmless method (instead of the repeated code in several places) + { + matchName="scala.reflect.runtime.Settings#MultiStringSetting.valueSetByUser" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.runtime.Settings#BooleanSetting.valueSetByUser" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.runtime.Settings#IntSetting.valueSetByUser" + problemName=MissingMethodProblem } ] } diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 01e8829d6e..9cb4159e60 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -332,7 +332,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) None } - val charset = ( if (settings.encoding.isSetByUser) Some(settings.encoding.value) else None ) flatMap loadCharset getOrElse { + val charset = settings.encoding.valueSetByUser flatMap loadCharset getOrElse { settings.encoding.value = defaultEncoding // A mandatory charset Charset.forName(defaultEncoding) } @@ -347,7 +347,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } } - ( if (settings.sourceReader.isSetByUser) Some(settings.sourceReader.value) else None ) flatMap loadReader getOrElse { + settings.sourceReader.valueSetByUser flatMap loadReader getOrElse { new SourceReader(charset.newDecoder(), reporter) } } diff --git a/src/compiler/scala/tools/nsc/PhaseAssembly.scala b/src/compiler/scala/tools/nsc/PhaseAssembly.scala index cfb4cd23a1..1eb6c9da2c 100644 --- a/src/compiler/scala/tools/nsc/PhaseAssembly.scala +++ b/src/compiler/scala/tools/nsc/PhaseAssembly.scala @@ -199,7 +199,7 @@ trait PhaseAssembly { // Add all phases in the set to the graph val graph = phasesSetToDepGraph(phasesSet) - val dot = if (settings.genPhaseGraph.isSetByUser) Some(settings.genPhaseGraph.value) else None + val dot = settings.genPhaseGraph.valueSetByUser // Output the phase dependency graph at this stage def dump(stage: Int) = dot foreach (n => graphToDotFile(graph, s"$n-$stage.dot")) diff --git a/src/compiler/scala/tools/nsc/plugins/Plugins.scala b/src/compiler/scala/tools/nsc/plugins/Plugins.scala index 6e3d013e52..4b1805479d 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugins.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugins.scala @@ -7,7 +7,7 @@ package scala.tools.nsc package plugins -import scala.reflect.io.{ File, Path } +import scala.reflect.io.Path import scala.tools.nsc.util.ClassPath import scala.tools.util.PathResolver.Defaults diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 6386da5725..9af3efbece 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -88,8 +88,7 @@ abstract class SymbolLoaders { // require yjp.jar at runtime. See SI-2089. if (settings.termConflict.isDefault) throw new TypeError( - root+" contains object and package with same name: "+ - name+"\none of them needs to be removed from classpath" + s"$root contains object and package with same name: $name\none of them needs to be removed from classpath" ) else if (settings.termConflict.value == "package") { warning( @@ -252,7 +251,7 @@ abstract class SymbolLoaders { * Load contents of a package */ class PackageLoader(classpath: ClassPath[AbstractFile]) extends SymbolLoader with FlagAgnosticCompleter { - protected def description = "package loader "+ classpath.name + protected def description = s"package loader ${classpath.name}" protected def doComplete(root: Symbol) { assert(root.isPackageClass, root) diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index c5f46dc140..f786ffb8f3 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -351,6 +351,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => while (owner != sym && owner != impl) owner = owner.owner; if (owner == impl) This(impl) setPos tree.pos else tree + //TODO what about this commented out code? /* !!! case Super(qual, mix) => val mix1 = mix diff --git a/src/compiler/scala/tools/reflect/ReflectMain.scala b/src/compiler/scala/tools/reflect/ReflectMain.scala index a998a44643..8d8418945a 100644 --- a/src/compiler/scala/tools/reflect/ReflectMain.scala +++ b/src/compiler/scala/tools/reflect/ReflectMain.scala @@ -1,10 +1,10 @@ package scala.tools package reflect +import scala.reflect.internal.util.ScalaClassLoader import scala.tools.nsc.Driver import scala.tools.nsc.Global import scala.tools.nsc.Settings -import scala.tools.nsc.util.ScalaClassLoader import scala.tools.util.PathResolverFactory object ReflectMain extends Driver { diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala index 315476953d..8e5b1e0a5c 100644 --- a/src/compiler/scala/tools/util/PathResolver.scala +++ b/src/compiler/scala/tools/util/PathResolver.scala @@ -51,9 +51,8 @@ object PathResolver { /** Values found solely by inspecting environment or property variables. */ object Environment { - private def searchForBootClasspath = ( + private def searchForBootClasspath = systemProperties find (_._1 endsWith ".boot.class.path") map (_._2) getOrElse "" - ) /** Environment variables which java pays attention to so it * seems we do as well. @@ -107,7 +106,7 @@ object PathResolver { else if (scalaLibAsDir.isDirectory) scalaLibAsDir.path else "" - // XXX It must be time for someone to figure out what all these things + // TODO It must be time for someone to figure out what all these things // are intended to do. This is disabled here because it was causing all // the scala jars to end up on the classpath twice: one on the boot // classpath as set up by the runner (or regular classpath under -nobootcp) @@ -177,7 +176,7 @@ object PathResolver { def fromPathString(path: String, context: JavaContext = DefaultJavaContext): JavaClassPath = { val s = new Settings() s.classpath.value = path - new PathResolver(s, context) result + new PathResolver(s, context).result } /** With no arguments, show the interesting values in Environment and Defaults. @@ -263,11 +262,9 @@ abstract class PathResolverBase[BaseClassPathType <: ClassFileLookup[AbstractFil * - Otherwise, if CLASSPATH is set, it is that * - If neither of those, then "." is used. */ - def userClassPath = ( - if (!settings.classpath.isDefault) - settings.classpath.value + def userClassPath = + if (!settings.classpath.isDefault) settings.classpath.value else sys.env.getOrElse("CLASSPATH", ".") - ) import classPathFactory._ @@ -291,7 +288,7 @@ abstract class PathResolverBase[BaseClassPathType <: ClassFileLookup[AbstractFil | javaBootClassPath = ${ppcp(javaBootClassPath)} | javaExtDirs = ${ppcp(javaExtDirs)} | javaUserClassPath = ${ppcp(javaUserClassPath)} - | useJavaClassPath = $useJavaClassPath + | useJavaClassPath = $useJavaClassPath | scalaBootClassPath = ${ppcp(scalaBootClassPath)} | scalaExtDirs = ${ppcp(scalaExtDirs)} | userClassPath = ${ppcp(userClassPath)} diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala index 7df809b6ff..5d00141e6a 100644 --- a/src/interactive/scala/tools/nsc/interactive/Global.scala +++ b/src/interactive/scala/tools/nsc/interactive/Global.scala @@ -128,8 +128,8 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") else NullLogger import log.logreplay - debugLog("logger: " + log.getClass + " writing to " + (new java.io.File(logName)).getAbsolutePath) - debugLog("classpath: "+classPath) + debugLog(s"logger: ${log.getClass} writing to ${(new java.io.File(logName)).getAbsolutePath}") + debugLog(s"classpath: $classPath") private var curTime = System.nanoTime private def timeStep = { diff --git a/src/partest-extras/scala/tools/partest/BytecodeTest.scala b/src/partest-extras/scala/tools/partest/BytecodeTest.scala index 3261cada37..37ef4684ef 100644 --- a/src/partest-extras/scala/tools/partest/BytecodeTest.scala +++ b/src/partest-extras/scala/tools/partest/BytecodeTest.scala @@ -116,10 +116,8 @@ abstract class BytecodeTest { sys.error(s"Didn't find method '$name' in class '${classNode.name}'") protected def loadClassNode(name: String, skipDebugInfo: Boolean = true): ClassNode = { - val classBytes: InputStream = (for { - classRep <- classpath.findClass(name) - binary <- classRep.binary - } yield binary.input) getOrElse sys.error(s"failed to load class '$name'; classpath = $classpath") + val classBytes: InputStream = classpath.findClassFile(name).map(_.input) + .getOrElse(sys.error(s"failed to load class '$name'; classpath = $classpath")) val cr = new ClassReader(classBytes) val cn = new ClassNode() diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index ed5c68fe82..01e4cdf367 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -338,7 +338,6 @@ abstract class SymbolTable extends macros.Universe case _ => false } if (pkgModule.isModule && !fromSource) { - // println("open "+pkgModule)//DEBUG openPackageModule(pkgModule, pkgClass) } } diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index c665f2b91a..8e86e6fad9 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -181,7 +181,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => type AccessBoundaryType = Symbol type AnnotationType = AnnotationInfo - // TODO - don't allow names to be renamed in this unstructured a fashion. + // TODO - don't allow names to be renamed in this unstructured fashion. // Rename as little as possible. Enforce invariants on all renames. type TypeOfClonedSymbol >: Null <: Symbol { type NameType = Symbol.this.NameType } @@ -1461,11 +1461,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => def info: Type = try { var cnt = 0 while (validTo == NoPeriod) { - //if (settings.debug.value) System.out.println("completing " + this);//DEBUG assert(infos ne null, this.name) assert(infos.prev eq null, this.name) val tp = infos.info - //if (settings.debug.value) System.out.println("completing " + this.rawname + tp.getClass());//debug if ((_rawflags & LOCKED) != 0L) { // rolled out once for performance lock { @@ -1474,6 +1472,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => } } else { _rawflags |= LOCKED + // TODO another commented out lines - this should be solved in one way or another // activeLocks += 1 // lockedSyms += this } diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala index a494c7f0d0..38893d8db3 100644 --- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala +++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala @@ -31,6 +31,9 @@ abstract class MutableSettings extends AbsSettings { v = arg postSetHook() } + + /** Returns Some(value) in the case of a value set by user and None otherwise. */ + def valueSetByUser: Option[T] = if (isSetByUser) Some(value) else None } def Xexperimental: BooleanSetting diff --git a/src/reflect/scala/reflect/io/VirtualFile.scala b/src/reflect/scala/reflect/io/VirtualFile.scala index 45f38db745..1cb4f2fe6f 100644 --- a/src/reflect/scala/reflect/io/VirtualFile.scala +++ b/src/reflect/scala/reflect/io/VirtualFile.scala @@ -75,10 +75,10 @@ class VirtualFile(val name: String, override val path: String) extends AbstractF } /** Does this abstract file denote an existing file? */ - def create() { unsupported() } + def create(): Unit = unsupported() /** Delete the underlying file or directory (recursively). */ - def delete() { unsupported() } + def delete(): Unit = unsupported() /** * Returns the abstract file in this abstract directory with the diff --git a/src/reflect/scala/reflect/io/ZipArchive.scala b/src/reflect/scala/reflect/io/ZipArchive.scala index dc2ec848b1..0c63acb86c 100644 --- a/src/reflect/scala/reflect/io/ZipArchive.scala +++ b/src/reflect/scala/reflect/io/ZipArchive.scala @@ -74,12 +74,6 @@ abstract class ZipArchive(override val file: JFile) extends AbstractFile with Eq def container = unsupported() def absolute = unsupported() - private def walkIterator(its: Iterator[AbstractFile]): Iterator[AbstractFile] = { - its flatMap { f => - if (f.isDirectory) walkIterator(f.iterator) - else Iterator(f) - } - } /** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ sealed abstract class Entry(path: String) extends VirtualFile(baseName(path), path) { // have to keep this name for compat with sbt's compiler-interface @@ -87,6 +81,7 @@ abstract class ZipArchive(override val file: JFile) extends AbstractFile with Eq override def underlyingSource = Some(self) override def toString = self.path + "(" + path + ")" } + /** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ class DirEntry(path: String) extends Entry(path) { val entries = mutable.HashMap[String, Entry]() @@ -245,11 +240,9 @@ final class ManifestResources(val url: URL) extends ZipArchive(null) { val manifest = new Manifest(input) val iter = manifest.getEntries().keySet().iterator().filter(_.endsWith(".class")).map(new ZipEntry(_)) - while (iter.hasNext) { - val zipEntry = iter.next() + for (zipEntry <- iter) { val dir = getDir(dirs, zipEntry) - if (zipEntry.isDirectory) dir - else { + if (!zipEntry.isDirectory) { class FileEntry() extends Entry(zipEntry.getName) { override def lastModified = zipEntry.getTime() override def input = resourceInputStream(path) @@ -285,14 +278,14 @@ final class ManifestResources(val url: URL) extends ZipArchive(null) { private def resourceInputStream(path: String): InputStream = { new FilterInputStream(null) { override def read(): Int = { - if(in == null) in = Thread.currentThread().getContextClassLoader().getResourceAsStream(path); + if(in == null) in = Thread.currentThread().getContextClassLoader().getResourceAsStream(path) if(in == null) throw new RuntimeException(path + " not found") - super.read(); + super.read() } override def close(): Unit = { - super.close(); - in = null; + super.close() + in = null } } } diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index 63d95b32b7..f9f7388363 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -1282,9 +1282,11 @@ object IMain { def getProgram(statements: String*): String = null - def getScriptEngine: ScriptEngine = new IMain(this, new Settings() { - usemanifestcp.value = true - }) + def getScriptEngine: ScriptEngine = { + val settings = new Settings() + settings.usemanifestcp.value = true + new IMain(this, settings) + } } // The two name forms this is catching are the two sides of this assignment: diff --git a/src/scalap/scala/tools/scalap/Arguments.scala b/src/scalap/scala/tools/scalap/Arguments.scala index c375a5bac4..de9c30b8af 100644 --- a/src/scalap/scala/tools/scalap/Arguments.scala +++ b/src/scalap/scala/tools/scalap/Arguments.scala @@ -9,7 +9,7 @@ package scala.tools.scalap import scala.collection.mutable -import mutable.{ Buffer, ListBuffer } +import mutable.ListBuffer object Arguments { case class Parser(optionPrefix: Char) { @@ -47,7 +47,7 @@ object Arguments { } def parseBinding(str: String, separator: Char): (String, String) = (str indexOf separator) match { - case -1 => argumentError("missing '" + separator + "' in binding '" + str + "'") ; ("", "") + case -1 => argumentError(s"missing '$separator' in binding '$str'") ; ("", "") case idx => ((str take idx).trim, (str drop (idx + 1)).trim) } @@ -71,7 +71,7 @@ object Arguments { i += 1 } else if (optionalArgs contains args(i)) { if ((i + 1) == args.length) { - argumentError("missing argument for '" + args(i) + "'") + argumentError(s"missing argument for '${args(i)}'") i += 1 } else { res.addArgument(args(i), args(i + 1)) @@ -79,11 +79,11 @@ object Arguments { } } else if (optionalBindings contains args(i)) { if ((i + 1) == args.length) { - argumentError("missing argument for '" + args(i) + "'") + argumentError(s"missing argument for '${args(i)}'") i += 1 } else { res.addBinding(args(i), - parseBinding(args(i + 1), optionalBindings(args(i)))); + parseBinding(args(i + 1), optionalBindings(args(i)))) i += 2 } } else { @@ -92,23 +92,23 @@ object Arguments { while ((i == j) && iter.hasNext) { val prefix = iter.next if (args(i) startsWith prefix) { - res.addPrefixed(prefix, args(i).substring(prefix.length()).trim()); + res.addPrefixed(prefix, args(i).substring(prefix.length()).trim()) i += 1 } } if (i == j) { - val iter = prefixedBindings.keysIterator; + val iter = prefixedBindings.keysIterator while ((i == j) && iter.hasNext) { val prefix = iter.next if (args(i) startsWith prefix) { val arg = args(i).substring(prefix.length()).trim() i = i + 1 res.addBinding(prefix, - parseBinding(arg, prefixedBindings(prefix))); + parseBinding(arg, prefixedBindings(prefix))) } } if (i == j) { - argumentError("unknown option '" + args(i) + "'") + argumentError(s"unknown option '${args(i)}'") i = i + 1 } } @@ -119,7 +119,7 @@ object Arguments { def parse(options: String*)(args: Array[String]): Arguments = { val parser = new Parser('-') - options foreach (parser withOption _) + options foreach parser.withOption parser parse args } } @@ -142,7 +142,7 @@ class Arguments { if (key.length > 0) bindings.getOrElseUpdate(tag, new mutable.HashMap)(key) = value - def addBinding(tag: String, binding: Tuple2[String, String]): Unit = + def addBinding(tag: String, binding: (String, String)): Unit = addBinding(tag, binding._1, binding._2) def addOther(arg: String): Unit = others += arg diff --git a/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala index 34684fc3e1..7c554d196c 100644 --- a/src/scalap/scala/tools/scalap/Main.scala +++ b/src/scalap/scala/tools/scalap/Main.scala @@ -178,7 +178,7 @@ object Main extends Main { verbose = arguments contains opts.verbose printPrivates = arguments contains opts.showPrivateDefs // construct a custom class path - val cpArg = List(opts.classpath, opts.cp) map (arguments getArgument) reduceLeft (_ orElse _) + val cpArg = List(opts.classpath, opts.cp) map arguments.getArgument reduceLeft (_ orElse _) val settings = new Settings() diff --git a/test/junit/scala/tools/nsc/SampleTest.scala b/test/junit/scala/tools/nsc/SampleTest.scala index 810c88ef9d..60bb09e98f 100644 --- a/test/junit/scala/tools/nsc/SampleTest.scala +++ b/test/junit/scala/tools/nsc/SampleTest.scala @@ -11,6 +11,6 @@ import org.junit.runners.JUnit4 class SampleTest { @Test def testMath: Unit = { - assert(2+2 == 4, "you didn't get the math right fellow") + assertTrue("you didn't get the math right fellow", 2 + 2 == 4) } } diff --git a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala index d61c62784c..f0f20acf07 100644 --- a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala +++ b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala @@ -83,7 +83,7 @@ class SymbolTableForUnitTesting extends SymbolTable { rm.asInstanceOf[Mirror] } - def settings: Settings = { + lazy val settings: Settings = { val s = new Settings // initialize classpath using java classpath s.usejavacp.value = true diff --git a/test/script-tests/README b/test/script-tests/README index 3f5c2ce19c..7b3291c407 100755 --- a/test/script-tests/README +++ b/test/script-tests/README @@ -5,4 +5,9 @@ putting self-contained script tests in here to run some way that doesn't depend on all the platform stars aligning all the time. Feel free to join me. --- extempore, Nov 21 2011 \ No newline at end of file +-- extempore, Nov 21 2011 + +But there's a problem that probably nobody would run such tests so they would become outdated quite quickly. +And therefore they wouldn't work (and even compile) after some time - like this one existing currently. + +-- mpociecha, Oct 9 2014 \ No newline at end of file -- cgit v1.2.3