diff options
Diffstat (limited to 'src')
15 files changed, 2 insertions, 1138 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 8746a7fd8d..05d0bcf6b0 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -16,7 +16,6 @@ import scala.reflect.internal.util.{ OffsetPosition, SourceFile, NoSourceFile, B import scala.reflect.internal.pickling.{ PickleBuffer, PickleFormat } import symtab.{ Flags, SymbolTable, SymbolLoaders, SymbolTrackers } import symtab.classfile.Pickler -import dependencies.DependencyAnalysis import plugins.Plugins import ast._ import ast.parser._ @@ -329,9 +328,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } } - if (!dependencyAnalysis.off) - dependencyAnalysis.loadDependencyAnalysis() - if (settings.verbose.value || settings.Ylogcp.value) { // Uses the "do not truncate" inform informComplete("[search path for source files: " + classPath.sourcepaths.mkString(",") + "]") @@ -606,14 +602,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val runsRightAfter = None } with GenASM - // This phase is optional: only added if settings.make option is given. - // phaseName = "dependencyAnalysis" - object dependencyAnalysis extends { - val global: Global.this.type = Global.this - val runsAfter = List("jvm") - val runsRightAfter = None - } with DependencyAnalysis - // phaseName = "terminal" object terminal extends { val global: Global.this.type = Global.this @@ -1472,8 +1460,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } /** Compile list of source files */ - def compileSources(_sources: List[SourceFile]) { - val sources = dependencyAnalysis calculateFiles _sources.distinct + def compileSources(sources: List[SourceFile]) { // there is a problem already, e.g. a plugin was passed a bad option if (reporter.hasErrors) return @@ -1568,10 +1555,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) symSource.keys foreach (x => resetPackageClass(x.owner)) informTime("total", startTime) - // record dependency data - if (!dependencyAnalysis.off) - dependencyAnalysis.saveDependencyAnalysis() - // Clear any sets or maps created via perRunCaches. perRunCaches.clearAll() diff --git a/src/compiler/scala/tools/nsc/Main.scala b/src/compiler/scala/tools/nsc/Main.scala index a4b22b0e11..c3c919fae4 100644 --- a/src/compiler/scala/tools/nsc/Main.scala +++ b/src/compiler/scala/tools/nsc/Main.scala @@ -7,7 +7,6 @@ package scala.tools.nsc import java.io.File import File.pathSeparator -import scala.tools.nsc.interactive.{ RefinedBuildManager, SimpleBuildManager } import scala.tools.nsc.io.AbstractFile /** The main class for NSC, a compiler for the programming @@ -42,23 +41,6 @@ object Main extends Driver with EvalLoop { askShutdown false } - else if (settings.Ybuilderdebug.value != "none") { - def fileSet(files : List[String]) = Set.empty ++ (files map AbstractFile.getFile) - - val buildManager = settings.Ybuilderdebug.value match { - case "simple" => new SimpleBuildManager(settings) - case _ => new RefinedBuildManager(settings) - } - buildManager.addSourceFiles(fileSet(command.files)) - - // enter resident mode - loop { line => - val args = line.split(' ').toList - val command = new CompilerCommand(args.toList, settings) - buildManager.update(fileSet(command.files), Set.empty) - } - false - } else true override def newCompiler(): Global = diff --git a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala index 5cc4404ca1..08602f87dc 100644 --- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala +++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala @@ -38,14 +38,10 @@ trait JavaPlatform extends Platform { // replaces the tighter abstract definition here. If we had DOT typing rules, the two // types would be conjoined and everything would work out. Yet another reason to push for DOT. - private def depAnalysisPhase = - if (settings.make.isDefault) Nil - else List(dependencyAnalysis) - def platformPhases = List( flatten, // get rid of inner classes genASM // generate .class files - ) ++ depAnalysisPhase + ) lazy val externalEquals = getDecl(BoxesRunTimeClass, nme.equals_) lazy val externalEqualsNumNum = getDecl(BoxesRunTimeClass, nme.equalsNumNum) diff --git a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala deleted file mode 100644 index 4d4b6589a0..0000000000 --- a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala +++ /dev/null @@ -1,253 +0,0 @@ -package scala.tools.nsc -package dependencies - -import io.Path -import scala.collection._ -import scala.tools.nsc.io.AbstractFile -import scala.reflect.internal.util.SourceFile - -trait DependencyAnalysis extends SubComponent with Files { - import global._ - - val phaseName = "dependencyAnalysis" - - def off = settings.make.isDefault || settings.make.value == "all" - def shouldCheckClasspath = settings.make.value != "transitivenocp" - - def newPhase(prev: Phase) = new AnalysisPhase(prev) - - private def depPath = Path(settings.dependenciesFile.value) - def loadDependencyAnalysis(): Boolean = ( - depPath.path != "none" && depPath.isFile && loadFrom( - AbstractFile.getFile(depPath), - path => AbstractFile.getFile(depPath.parent resolve Path(path)) - ) - ) - def saveDependencyAnalysis(): Unit = { - if (!depPath.exists) - dependenciesFile = AbstractFile.getFile(depPath.createFile()) - - /** The directory where file lookup should start */ - val rootPath = depPath.parent.normalize - saveDependencies( - file => rootPath.relativize(Path(file.file).normalize).path - ) - } - - lazy val maxDepth = settings.make.value match { - case "changed" => 0 - case "immediate" => 1 - case _ => Int.MaxValue - } - - // todo: order insensible checking and, also checking timestamp? - def validateClasspath(cp1: String, cp2: String): Boolean = cp1 == cp2 - - def nameToFile(src: AbstractFile, name: String) = - settings.outputDirs.outputDirFor(src) - .lookupPathUnchecked(name.toString.replace(".", java.io.File.separator) + ".class", false) - - private var depFile: Option[AbstractFile] = None - - def dependenciesFile_=(file: AbstractFile) { - assert(file ne null) - depFile = Some(file) - } - - def dependenciesFile: Option[AbstractFile] = depFile - - def classpath = settings.classpath.value - def newDeps = new FileDependencies(classpath) - - var dependencies = newDeps - - def managedFiles = dependencies.dependencies.keySet - - /** Top level definitions per source file. */ - val definitions: mutable.Map[AbstractFile, List[Symbol]] = - new mutable.HashMap[AbstractFile, List[Symbol]] { - override def default(f: AbstractFile) = Nil - } - - /** External references used by source file. */ - val references: mutable.Map[AbstractFile, immutable.Set[String]] = - new mutable.HashMap[AbstractFile, immutable.Set[String]] { - override def default(f: AbstractFile) = immutable.Set() - } - - /** External references for inherited members used in the source file */ - val inherited: mutable.Map[AbstractFile, immutable.Set[Inherited]] = - new mutable.HashMap[AbstractFile, immutable.Set[Inherited]] { - override def default(f: AbstractFile) = immutable.Set() - } - - /** Write dependencies to the current file. */ - def saveDependencies(fromFile: AbstractFile => String) = - if(dependenciesFile.isDefined) - dependencies.writeTo(dependenciesFile.get, fromFile) - - /** Load dependencies from the given file and save the file reference for - * future saves. - */ - def loadFrom(f: AbstractFile, toFile: String => AbstractFile): Boolean = { - dependenciesFile = f - FileDependencies.readFrom(f, toFile) match { - case Some(fd) => - val success = if (shouldCheckClasspath) validateClasspath(fd.classpath, classpath) else true - dependencies = if (success) fd else { - if (settings.debug.value) - println("Classpath has changed. Nuking dependencies") - newDeps - } - - success - case None => false - } - } - - def calculateFiles(files: List[SourceFile]): List[SourceFile] = - if (off) files - else if (dependencies.isEmpty) { - println("No known dependencies. Compiling " + - (if (settings.debug.value) files.mkString(", ") else "everything")) - files - } else { - val (direct, indirect) = dependencies.invalidatedFiles(maxDepth); - val filtered = files.filter(x => { - val f = x.file.absolute - direct(f) || indirect(f) || !dependencies.containsFile(f); - }) - filtered match { - case Nil => println("No changes to recompile"); - case x => println("Recompiling " + ( - if(settings.debug.value) x.mkString(", ") else x.length + " files") - ) - } - filtered - } - - case class Inherited(qualifier: String, member: Name) - - class AnalysisPhase(prev: Phase) extends StdPhase(prev) { - - override def cancelled(unit: CompilationUnit) = - super.cancelled(unit) && !unit.isJava - - def apply(unit : global.CompilationUnit) { - val f = unit.source.file.file - // When we're passed strings by the interpreter - // they have no source file. We simply ignore this case - // as irrelevant to dependency analysis. - if (f != null){ - val source: AbstractFile = unit.source.file; - for (d <- unit.icode){ - val name = d.toString - d.symbol match { - case s : ModuleClassSymbol => - val isTopLevelModule = exitingPickler { !s.isImplClass && !s.isNestedClass } - - if (isTopLevelModule && (s.companionModule != NoSymbol)) { - dependencies.emits(source, nameToFile(unit.source.file, name)) - } - dependencies.emits(source, nameToFile(unit.source.file, name + "$")) - case _ => - dependencies.emits(source, nameToFile(unit.source.file, name)) - } - } - - dependencies.reset(source) - for (d <- unit.depends; if (d.sourceFile != null)){ - dependencies.depends(source, d.sourceFile) - } - } - - // find all external references in this compilation unit - val file = unit.source.file - references += file -> immutable.Set.empty[String] - inherited += file -> immutable.Set.empty[Inherited] - - val buf = new mutable.ListBuffer[Symbol] - - (new Traverser { - override def traverse(tree: Tree) { - if ((tree.symbol ne null) - && (tree.symbol != NoSymbol) - && (!tree.symbol.isPackage) - && (!tree.symbol.isJavaDefined) - && (!tree.symbol.tpe.isError) - && ((tree.symbol.sourceFile eq null) - || (tree.symbol.sourceFile.path != file.path)) - && (!tree.symbol.isClassConstructor)) { - updateReferences(tree.symbol.fullName) - // was "at uncurryPhase.prev", which is actually non-deterministic - // because the continuations plugin may or may not supply uncurry's - // immediately preceding phase. - enteringRefchecks(checkType(tree.symbol.tpe)) - } - - tree match { - case cdef: ClassDef if !cdef.symbol.hasPackageFlag && - !cdef.symbol.isAnonymousFunction => - if (cdef.symbol != NoSymbol) buf += cdef.symbol - // was "at erasurePhase.prev" - enteringExplicitOuter { - for (s <- cdef.symbol.info.decls) - s match { - case ts: TypeSymbol if !ts.isClass => - checkType(s.tpe) - case _ => - } - } - super.traverse(tree) - - case ddef: DefDef => - // was "at typer.prev" - enteringTyper { checkType(ddef.symbol.tpe) } - super.traverse(tree) - case a @ Select(q, n) if ((a.symbol != NoSymbol) && (q.symbol != null)) => // #2556 - if (!a.symbol.isConstructor && - !a.symbol.owner.isPackageClass && - !isSameType(q.tpe, a.symbol.owner.tpe)) - inherited += file -> - (inherited(file) + Inherited(q.symbol.tpe.resultType.safeToString, n)) - super.traverse(tree) - case _ => - super.traverse(tree) - } - } - - def checkType(tpe: Type): Unit = - tpe match { - case t: MethodType => - checkType(t.resultType) - for (s <- t.params) checkType(s.tpe) - - case t: TypeRef => - if (t.sym.isAliasType) { - updateReferences(t.typeSymbolDirect.fullName) - checkType(t.typeSymbolDirect.info) - } - updateReferences(t.typeSymbol.fullName) - for (tp <- t.args) checkType(tp) - - case t: PolyType => - checkType(t.resultType) - updateReferences(t.typeSymbol.fullName) - - case t: NullaryMethodType => - checkType(t.resultType) - updateReferences(t.typeSymbol.fullName) - - case t => - updateReferences(t.typeSymbol.fullName) - } - - def updateReferences(s: String): Unit = - references += file -> (references(file) + s) - - }).apply(unit.body) - - definitions(unit.source.file) = buf.toList - } - } -} diff --git a/src/compiler/scala/tools/nsc/dependencies/Files.scala b/src/compiler/scala/tools/nsc/dependencies/Files.scala deleted file mode 100644 index 194351a13f..0000000000 --- a/src/compiler/scala/tools/nsc/dependencies/Files.scala +++ /dev/null @@ -1,177 +0,0 @@ -package scala.tools.nsc -package dependencies - -import java.io.{InputStream, OutputStream, PrintStream, InputStreamReader, BufferedReader} -import io.{AbstractFile, PlainFile, VirtualFile} - -import scala.collection._ - - -trait Files { self : SubComponent => - - class FileDependencies(val classpath: String) { - import FileDependencies._ - - class Tracker extends mutable.OpenHashMap[AbstractFile, mutable.Set[AbstractFile]] { - override def default(key: AbstractFile) = { - this(key) = new mutable.HashSet[AbstractFile] - this(key) - } - } - - val dependencies = new Tracker - val targets = new Tracker - - def isEmpty = dependencies.isEmpty && targets.isEmpty - - def emits(source: AbstractFile, result: AbstractFile) = - targets(source) += result - def depends(from: AbstractFile, on: AbstractFile) = - dependencies(from) += on - - def reset(file: AbstractFile) = dependencies -= file - - def cleanEmpty = { - dependencies foreach {case (_, value) => - value retain (x => x.exists && (x ne removedFile))} - dependencies retain ((key, value) => key.exists && !value.isEmpty) - targets foreach {case (_, value) => value retain (_.exists)} - targets retain ((key, value) => key.exists && !value.isEmpty) - } - - def containsFile(f: AbstractFile) = targets.contains(f.absolute) - - def invalidatedFiles(maxDepth: Int) = { - val direct = new mutable.HashSet[AbstractFile] - - for ((file, products) <- targets) { - // This looks a bit odd. It may seem like one should invalidate a file - // if *any* of its dependencies are older than it. The forall is there - // to deal with the fact that a) Some results might have been orphaned - // and b) Some files might not need changing. - direct(file) ||= products.forall(d => d.lastModified < file.lastModified) - } - - val indirect = dependentFiles(maxDepth, direct) - - for ((source, targets) <- targets - if direct(source) || indirect(source) || (source eq removedFile)) { - targets foreach (_.delete) - targets -= source - } - - (direct, indirect) - } - - /** Return the set of files that depend on the given changed files. - * It computes the transitive closure up to the given depth. - */ - def dependentFiles(depth: Int, changed: Set[AbstractFile]): Set[AbstractFile] = { - val indirect = new mutable.HashSet[AbstractFile] - val newInvalidations = new mutable.HashSet[AbstractFile] - - def invalid(file: AbstractFile) = - indirect(file) || changed(file) || (file eq removedFile) - - def go(i: Int) : Unit = if(i > 0) { - newInvalidations.clear - for((target, depends) <- dependencies if !invalid(target); - d <- depends) - newInvalidations(target) ||= invalid(d) - - indirect ++= newInvalidations - if (!newInvalidations.isEmpty) go(i - 1) - } - - go(depth) - - indirect --= changed - } - - def writeTo(file: AbstractFile, fromFile: AbstractFile => String): Unit = - writeToFile(file)(out => writeTo(new PrintStream(out), fromFile)) - - def writeTo(print: PrintStream, fromFile: AbstractFile => String): Unit = { - def emit(tracker: Tracker) = - for ((f, ds) <- tracker; d <- ds) print.println(fromFile(f) + arrow + fromFile(d)) - - cleanEmpty - print.println(classpath) - print.println(separator) - emit(dependencies) - print.println(separator) - emit(targets) - } - } - - object FileDependencies { - private val separator:String = "-------" - private val arrow = " -> " - private val removedFile = new VirtualFile("removed") - - private def validLine(l: String) = (l != null) && (l != separator) - - def readFrom(file: AbstractFile, toFile: String => AbstractFile): Option[FileDependencies] = - readFromFile(file) { in => - val reader = new BufferedReader(new InputStreamReader(in)) - val it = new FileDependencies(reader.readLine) - - def readLines(valid: Boolean)(f: (AbstractFile, AbstractFile) => Unit): Boolean = { - var continue = valid - var line: String = null - while (continue && {line = reader.readLine; validLine(line)}) { - line.split(arrow) match { - case Array(from, on) => f(toFile(from), toFile(on)) - case _ => - global.inform("Parse error: Unrecognised string " + line) - continue = false - } - } - continue - } - - reader.readLine - - val dResult = readLines(true)( - (_, _) match { - case (null, _) => // fromFile is removed, it's ok - case (fromFile, null) => - // onFile is removed, should recompile fromFile - it.depends(fromFile, removedFile) - case (fromFile, onFile) => it.depends(fromFile, onFile) - }) - - readLines(dResult)( - (_, _) match { - case (null, null) => - // source and target are all removed, it's ok - case (null, targetFile) => - // source is removed, should remove relative target later - it.emits(removedFile, targetFile) - case (_, null) => - // it may has been cleaned outside, or removed during last phase - case (sourceFile, targetFile) => it.emits(sourceFile, targetFile) - }) - - Some(it) - } - } - - def writeToFile[T](file: AbstractFile)(f: OutputStream => T) : T = { - val out = file.bufferedOutput - try { - f(out) - } finally { - out.close - } - } - - def readFromFile[T](file: AbstractFile)(f: InputStream => T) : T = { - val in = file.input - try{ - f(in) - } finally { - in.close - } - } -} diff --git a/src/compiler/scala/tools/nsc/interactive/BuildManager.scala b/src/compiler/scala/tools/nsc/interactive/BuildManager.scala deleted file mode 100644 index 6b72eb12f8..0000000000 --- a/src/compiler/scala/tools/nsc/interactive/BuildManager.scala +++ /dev/null @@ -1,83 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2009-2013 Typesafe/Scala Solutions and LAMP/EPFL - * @author Iulian Dragos - * @author Hubert Plocinicak - */ -package scala.tools.nsc -package interactive - -import scala.collection._ -import io.AbstractFile -import scala.language.implicitConversions - -trait BuildManager { - - /** Add the given source files to the managed build process. */ - def addSourceFiles(files: Set[AbstractFile]) - - /** The given files have been modified by the user. Recompile - * them and their dependent files. - */ - def update(added: Set[AbstractFile], removed: Set[AbstractFile]) - - /** Notification that the supplied set of files is being built */ - def buildingFiles(included: Set[AbstractFile]) {} - - /** Load saved dependency information. */ - def loadFrom(file: AbstractFile, toFile: String => AbstractFile) : Boolean - - /** Save dependency information to `file`. */ - def saveTo(file: AbstractFile, fromFile: AbstractFile => String) - - def compiler: scala.tools.nsc.Global - - /** Delete classfiles derived from the supplied set of sources */ - def deleteClassfiles(sources : Set[AbstractFile]) { - val targets = compiler.dependencyAnalysis.dependencies.targets - for(source <- sources; cf <- targets(source)) - cf.delete - } -} - - -/** Simple driver for testing the build manager. It presents - * the user to a 'resident compiler' prompt. Each line is - * interpreted as a set of files that have changed. The builder - * then derives the dependent files and recompiles them. - */ -object BuildManagerTest extends EvalLoop { - - def prompt = "builder > " - - private def buildError(msg: String) { - println(msg + "\n scalac -help gives more information") - } - - def main(args: Array[String]) { - implicit def filesToSet(fs: List[String]): Set[AbstractFile] = { - def partition(s: String, r: Tuple2[List[AbstractFile], List[String]])= { - val v = AbstractFile.getFile(s) - if (v == null) (r._1, s::r._2) else (v::r._1, r._2) - } - val result = fs.foldRight((List[AbstractFile](), List[String]()))(partition) - if (!result._2.isEmpty) - Console.err.println("No such file(s): " + result._2.mkString(",")) - Set.empty ++ result._1 - } - - val settings = new Settings(buildError) - settings.Ybuildmanagerdebug.value = true - val command = new CompilerCommand(args.toList, settings) - val buildManager: BuildManager = new RefinedBuildManager(settings) - - buildManager.addSourceFiles(command.files) - - // enter resident mode - loop { line => - val args = line.split(' ').toList - val command = new CompilerCommand(args, settings) - buildManager.update(command.files, Set.empty) - } - - } -} diff --git a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala deleted file mode 100644 index 9873276f05..0000000000 --- a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala +++ /dev/null @@ -1,354 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2009-2013 Typesafe/Scala Solutions and LAMP/EPFL - * @author Iulian Dragos - * @author Hubert Plocinicak - */ -package scala.tools.nsc -package interactive - -import scala.collection._ -import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} -import scala.util.control.Breaks._ -import scala.tools.nsc.symtab.Flags - -import dependencies._ -import util.ClassPath -import io.AbstractFile -import scala.tools.util.PathResolver - -/** A more defined build manager, based on change sets. For each - * updated source file, it computes the set of changes to its - * definitions, then checks all dependent units to see if the - * changes require a compilation. It repeats this process until - * a fixpoint is reached. - */ -@deprecated("Use sbt incremental compilation mechanism", "2.10.0") -class RefinedBuildManager(val settings: Settings) extends Changes with BuildManager { - - class BuilderGlobal(settings: Settings, reporter : Reporter) extends scala.tools.nsc.Global(settings, reporter) { - - def this(settings: Settings) = - this(settings, new ConsoleReporter(settings)) - - override def computeInternalPhases() { - super.computeInternalPhases - phasesSet += dependencyAnalysis - } - lazy val _classpath = new NoSourcePathPathResolver(settings).result - override def classPath = _classpath.asInstanceOf[ClassPath[platform.BinaryRepr]] - // See discussion in JavaPlatForm for why we need a cast here. - - def newRun() = new Run() - } - - class NoSourcePathPathResolver(settings: Settings) extends PathResolver(settings) { - override def containers = Calculated.basis.dropRight(1).flatten.distinct - } - - protected def newCompiler(settings: Settings) = new BuilderGlobal(settings) - - val compiler = newCompiler(settings) - import compiler.{ Symbol, Type, enteringErasure } - import compiler.dependencyAnalysis.Inherited - - private case class SymWithHistory(sym: Symbol, befErasure: Type) - - /** Managed source files. */ - private val sources: mutable.Set[AbstractFile] = new mutable.HashSet[AbstractFile] - - private val definitions: mutable.Map[AbstractFile, List[SymWithHistory]] = - new mutable.HashMap[AbstractFile, List[SymWithHistory]] { - override def default(key: AbstractFile) = Nil - } - - /** External references used by source file. */ - private var references: mutable.Map[AbstractFile, immutable.Set[String]] = _ - - /** External references for inherited members */ - private var inherited: mutable.Map[AbstractFile, immutable.Set[Inherited]] = _ - - /** Reverse of definitions, used for caching */ - private val classes: mutable.Map[String, AbstractFile] = - new mutable.HashMap[String, AbstractFile] { - override def default(key: String) = null - } - - /** Add the given source files to the managed build process. */ - def addSourceFiles(files: Set[AbstractFile]) { - sources ++= files - update(files) - } - - /** Remove the given files from the managed build process. */ - def removeFiles(files: Set[AbstractFile]) { - sources --= files - deleteClassfiles(files) - update(invalidatedByRemove(files)) - } - - /** Return the set of invalidated files caused by removing the given files. - */ - private def invalidatedByRemove(files: Set[AbstractFile]): Set[AbstractFile] = { - val changes = new mutable.HashMap[Symbol, List[Change]] - for (f <- files; SymWithHistory(sym, _) <- definitions(f)) - changes += sym -> List(Removed(Class(sym.fullName))) - invalidated(files, changes) - } - - def update(added: Set[AbstractFile], removed: Set[AbstractFile]) { - sources --= removed - deleteClassfiles(removed) - update(added ++ invalidatedByRemove(removed)) - } - - /** The given files have been modified by the user. Recompile - * them and all files that depend on them. Only files that - * have been previously added as source files are recompiled. - * Files that were already compiled are taken out from the result - * of the dependency analysis. - */ - private def update(files: Set[AbstractFile]) = { - val coll: mutable.Map[AbstractFile, immutable.Set[AbstractFile]] = - mutable.HashMap[AbstractFile, immutable.Set[AbstractFile]]() - compiler.reporter.reset() - - // See if we really have corresponding symbols, not just those - // which share the name - def isCorrespondingSym(from: Symbol, to: Symbol): Boolean = - (from.hasFlag(Flags.TRAIT) == to.hasFlag(Flags.TRAIT)) && // has to run in 2.8, so no hasTraitFlag - (from.hasFlag(Flags.MODULE) == to.hasFlag(Flags.MODULE)) - - // For testing purposes only, order irrelevant for compilation - def toStringSet(set: Set[AbstractFile]): String = - set.toList sortBy (_.name) mkString("Set(", ", ", ")") - - def update0(files: Set[AbstractFile]): Unit = if (!files.isEmpty) { - deleteClassfiles(files) - val run = compiler.newRun() - if (settings.Ybuildmanagerdebug.value) - compiler.inform("compiling " + toStringSet(files)) - buildingFiles(files) - - run.compileFiles(files.toList) - if (compiler.reporter.hasErrors) { - return - } - - // Deterministic behaviour required by partest - val changesOf = new mutable.HashMap[Symbol, List[Change]] { - override def toString: String = { - val changesOrdered = - toList.map(e => { - e._1.toString + " -> " + - e._2.sortBy(_.toString).mkString("List(", ", ", ")") - }) - changesOrdered.sorted.mkString("Map(", ", ", ")") - } - } - val additionalDefs: mutable.HashSet[AbstractFile] = mutable.HashSet.empty - - val defs = compiler.dependencyAnalysis.definitions - for (src <- files) { - if (definitions(src).isEmpty) - additionalDefs ++= compiler.dependencyAnalysis. - dependencies.dependentFiles(1, mutable.Set(src)) - else { - val syms = defs(src) - for (sym <- syms) { - definitions(src).find( - s => (s.sym.fullName == sym.fullName) && - isCorrespondingSym(s.sym, sym)) match { - case Some(SymWithHistory(oldSym, info)) => - val changes = changeSet(oldSym.info, sym) - val changesErasure = enteringErasure(changeSet(info, sym)) - - changesOf(oldSym) = (changes ++ changesErasure).distinct - case _ => - // a new top level definition - changesOf(sym) = sym.parentSymbols filter (_.isSealed) map (p => - changeChangeSet(p, sym+" extends a sealed "+p)) - } - } - // Create a change for the top level classes that were removed - val removed = definitions(src) filterNot ((s:SymWithHistory) => - syms.find(_.fullName == (s.sym.fullName)) != None) - for (s <- removed) { - changesOf(s.sym) = List(removeChangeSet(s.sym)) - } - } - } - if (settings.Ybuildmanagerdebug.value) - compiler.inform("Changes: " + changesOf) - updateDefinitions(files) - val invalid = invalidated(files, changesOf, additionalDefs) - update0(checkCycles(invalid, files, coll)) - } - - update0(files) - // remove the current run in order to save some memory - compiler.dropRun() - } - - // Attempt to break the cycling reference deps as soon as possible and reduce - // the number of compilations to minimum without having too coarse grained rules - private def checkCycles(files: Set[AbstractFile], initial: Set[AbstractFile], - collect: mutable.Map[AbstractFile, immutable.Set[AbstractFile]]): - Set[AbstractFile] = { - def followChain(set: Set[AbstractFile], rest: immutable.Set[AbstractFile]): - immutable.Set[AbstractFile] = { - val deps:Set[AbstractFile] = set.flatMap( - s => collect.get(s) match { - case Some(x) => x - case _ => Set[AbstractFile]() - }) - val newDeps = deps -- rest - if (newDeps.isEmpty) rest else followChain(newDeps, rest ++ newDeps) - } - var res:Set[AbstractFile] = mutable.Set() - files.foreach( f => - if (collect contains f) { - val chain = followChain(Set(f), immutable.Set()) ++ files - chain.foreach((fc: AbstractFile) => collect += fc -> chain) - res ++= chain - } else - res += f - ) - - initial.foreach((f: AbstractFile) => collect += (f -> (collect.getOrElse(f, immutable.Set()) ++ res))) - if (res.subsetOf(initial)) Set() else res - } - - /** Return the set of source files that are invalidated by the given changes. */ - def invalidated(files: Set[AbstractFile], changesOf: scala.collection.Map[Symbol, List[Change]], - processed: Set[AbstractFile] = Set.empty): - Set[AbstractFile] = { - val buf = new mutable.HashSet[AbstractFile] - val newChangesOf = new mutable.HashMap[Symbol, List[Change]] - var directDeps = - compiler.dependencyAnalysis.dependencies.dependentFiles(1, files) - - def invalidate(file: AbstractFile, reason: String, change: Change) = { - if (settings.Ybuildmanagerdebug.value) - compiler.inform("invalidate " + file + " because " + reason + " [" + change + "]") - buf += file - directDeps -= file - for (syms <- definitions(file)) // fixes #2557 - newChangesOf(syms.sym) = List(change, parentChangeSet(syms.sym)) - break - } - - for ((oldSym, changes) <- changesOf; change <- changes) { - def checkParents(cls: Symbol, file: AbstractFile) { - val parentChange = cls.parentSymbols exists (_.fullName == oldSym.fullName) - // if (settings.buildmanagerdebug.value) - // compiler.inform("checkParents " + cls + " oldSym: " + oldSym + " parentChange: " + parentChange + " " + cls.info.parents) - change match { - case Changed(Class(_)) if parentChange => - invalidate(file, "parents have changed", change) - - case Changed(Definition(_)) if parentChange => - invalidate(file, "inherited method changed", change) - - case Added(Definition(_)) if parentChange => - invalidate(file, "inherited new method", change) - - case Removed(Definition(_)) if parentChange => - invalidate(file, "inherited method removed", change) - - case _ => () - } - } - - def checkInterface(cls: Symbol, file: AbstractFile) { - change match { - case Added(Definition(name)) => - if (cls.info.decls.iterator.exists(_.fullName == name)) - invalidate(file, "of new method with existing name", change) - case Changed(Class(name)) => - if (cls.info.typeSymbol.fullName == name) - invalidate(file, "self type changed", change) - case _ => - () - } - } - - def checkReferences(file: AbstractFile) { - //if (settings.buildmanagerdebug.value) - // compiler.inform(file + ":" + references(file)) - val refs = references(file) - if (refs.isEmpty) - invalidate(file, "it is a direct dependency and we don't yet have finer-grained dependency information", change) - else { - change match { - case Removed(Definition(name)) if refs(name) => - invalidate(file, "it references deleted definition", change) - case Removed(Class(name)) if (refs(name)) => - invalidate(file, "it references deleted class", change) - case Changed(Class(name)) if (refs(name)) => - invalidate(file, "it references changed class", change) - case Changed(Definition(name)) if (refs(name)) => - invalidate(file, "it references changed definition", change) - case Added(Definition(name)) if (refs(name)) => - invalidate(file, "it references added definition", change) - case _ => () - } - } - } - - def checkInheritedReferences(file: AbstractFile) { - val refs = inherited(file) - if (!refs.isEmpty) - change match { - case ParentChanged(Class(name)) => - for (Inherited(q, member) <- refs.find(p => (p != null && p.qualifier == name)); - classFile <- classes.get(q); - defs <- definitions.get(classFile); - s <- defs.find(p => p.sym.fullName == q) - if ((s.sym).tpe.nonPrivateMember(member) == compiler.NoSymbol)) - invalidate(file, "it references invalid (no longer inherited) definition", change) - () - case _ => () - } - } - - for (file <- directDeps) { - breakable { - for (cls <- definitions(file)) checkParents(cls.sym, file) - for (cls <- definitions(file)) checkInterface(cls.sym, file) - checkReferences(file) - checkInheritedReferences(file) - } - } - } - if (buf.isEmpty) - processed - else - invalidated(buf.clone() --= processed, newChangesOf, processed ++ buf) - } - - /** Update the map of definitions per source file */ - private def updateDefinitions(files: Set[AbstractFile]) { - for (src <- files; localDefs = compiler.dependencyAnalysis.definitions(src)) { - definitions(src) = (localDefs map (s => { - this.classes += s.fullName -> src - SymWithHistory(s.cloneSymbol, enteringErasure(s.info.cloneInfo(s))) - })) - } - this.references = compiler.dependencyAnalysis.references - this.inherited = compiler.dependencyAnalysis.inherited - } - - /** Load saved dependency information. */ - def loadFrom(file: AbstractFile, toFile: String => AbstractFile) : Boolean = { - val success = compiler.dependencyAnalysis.loadFrom(file, toFile) - if (success) - sources ++= compiler.dependencyAnalysis.managedFiles - success - } - - /** Save dependency information to `file`. */ - def saveTo(file: AbstractFile, fromFile: AbstractFile => String) { - compiler.dependencyAnalysis.dependenciesFile = file - compiler.dependencyAnalysis.saveDependencies(fromFile) - } -} diff --git a/src/compiler/scala/tools/nsc/interactive/SimpleBuildManager.scala b/src/compiler/scala/tools/nsc/interactive/SimpleBuildManager.scala deleted file mode 100644 index ff25dac7ac..0000000000 --- a/src/compiler/scala/tools/nsc/interactive/SimpleBuildManager.scala +++ /dev/null @@ -1,100 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2009-2013 Typesafe/Scala Solutions and LAMP/EPFL - * @author Martin Odersky - */ -package scala.tools.nsc -package interactive - -import scala.collection._ - -import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} -import io.AbstractFile - -/** A simple build manager, using the default scalac dependency tracker. - * The transitive closure of all dependent files on a modified file - * is recompiled at once. - * - * It is equivalent to using a resident compiler mode with the - * '-make:transitive' option. - */ -class SimpleBuildManager(val settings: Settings) extends BuildManager { - - class BuilderGlobal(settings: Settings, reporter : Reporter) extends scala.tools.nsc.Global(settings, reporter) { - - def this(settings: Settings) = - this(settings, new ConsoleReporter(settings)) - - def newRun() = new Run() - } - - protected def newCompiler(settings: Settings) = new BuilderGlobal(settings) - - val compiler = newCompiler(settings) - - /** Managed source files. */ - private val sources: mutable.Set[AbstractFile] = new mutable.HashSet[AbstractFile] - - /** Add the given source files to the managed build process. */ - def addSourceFiles(files: Set[AbstractFile]) { - sources ++= files - update(files) - } - - /** Remove the given files from the managed build process. */ - def removeFiles(files: Set[AbstractFile]) { - sources --= files - deleteClassfiles(files) - update(invalidatedByRemove(files)) - } - - - /** Return the set of invalidated files caused by removing the given files. */ - private def invalidatedByRemove(files: Set[AbstractFile]): Set[AbstractFile] = { - val deps = compiler.dependencyAnalysis.dependencies - deps.dependentFiles(Int.MaxValue, files) - } - - def update(added: Set[AbstractFile], removed: Set[AbstractFile]) { - sources --= removed - deleteClassfiles(removed) - update(added ++ invalidatedByRemove(removed)) - } - - /** The given files have been modified by the user. Recompile - * them and all files that depend on them. Only files that - * have been previously added as source files are recompiled. - */ - def update(files: Set[AbstractFile]) { - deleteClassfiles(files) - - val deps = compiler.dependencyAnalysis.dependencies - val run = compiler.newRun() - compiler.inform("compiling " + files) - - val toCompile = - (files ++ deps.dependentFiles(Int.MaxValue, files)) intersect sources - - - compiler.inform("Recompiling " + - (if(settings.debug.value) toCompile.mkString(", ") - else toCompile.size + " files")) - - buildingFiles(toCompile) - - run.compileFiles(files.toList) - } - - /** Load saved dependency information. */ - def loadFrom(file: AbstractFile, toFile: String => AbstractFile) : Boolean = { - val success = compiler.dependencyAnalysis.loadFrom(file, toFile) - if (success) - sources ++= compiler.dependencyAnalysis.managedFiles - success - } - - /** Save dependency information to `file`. */ - def saveTo(file: AbstractFile, fromFile: AbstractFile => String) { - compiler.dependencyAnalysis.dependenciesFile = file - compiler.dependencyAnalysis.saveDependencies(fromFile) - } -} diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 9c8ffc5ae3..36e6a74820 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -162,7 +162,6 @@ trait ScalaSettings extends AbsScalaSettings val refinementMethodDispatch = ChoiceSetting ("-Ystruct-dispatch", "policy", "structural method dispatch policy", List("no-cache", "mono-cache", "poly-cache", "invoke-dynamic"), "poly-cache") val Yrangepos = BooleanSetting ("-Yrangepos", "Use range positions for syntax trees.") - val Ybuilderdebug = ChoiceSetting ("-Ybuilder-debug", "manager", "Compile using the specified build manager.", List("none", "refined", "simple"), "none") val Yreifycopypaste = BooleanSetting ("-Yreify-copypaste", "Dump the reified trees in copypasteable representation.") val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup") val Yreploutdir = StringSetting ("-Yrepl-outdir", "path", "Write repl-generated classfiles to given output directory (use \"\" to generate a temporary dir)" , "") @@ -177,7 +176,6 @@ trait ScalaSettings extends AbsScalaSettings /** Area-specific debug output. */ - val Ybuildmanagerdebug = BooleanSetting("-Ybuild-manager-debug", "Generate debug information for the Refined Build Manager compiler.") val Ydocdebug = BooleanSetting("-Ydoc-debug", "Trace all scaladoc activity.") val Yidedebug = BooleanSetting("-Yide-debug", "Generate, validate and output trees using the interactive compiler.") val Yinferdebug = BooleanSetting("-Yinfer-debug", "Trace type inference and implicit search.") diff --git a/src/partest/README b/src/partest/README index 0434aa7499..17594dbb1e 100644 --- a/src/partest/README +++ b/src/partest/README @@ -24,7 +24,6 @@ Other arguments: * --run next files test the interpreter and all backends * --jvm next files test the JVM backend * --res next files test the resident compiler - * --buildmanager next files test the build manager * --shootout next files are shootout tests * --script next files test the script runner * ''-Dpartest.scalac_opts=...'' -> add compiler options diff --git a/src/partest/scala/tools/partest/PartestTask.scala b/src/partest/scala/tools/partest/PartestTask.scala index 41d69a5448..d320f20616 100644 --- a/src/partest/scala/tools/partest/PartestTask.scala +++ b/src/partest/scala/tools/partest/PartestTask.scala @@ -43,7 +43,6 @@ import org.apache.tools.ant.types.Commandline.Argument * - `runtests`, * - `jvmtests`, * - `residenttests`, - * - `buildmanagertests`, * - `shootouttests`, * - `scalaptests`, * - `scalachecktests`, @@ -76,10 +75,6 @@ class PartestTask extends Task with CompilationPathProperty { residentFiles = Some(input) } - def addConfiguredBuildManagerTests(input: FileSet) { - buildManagerFiles = Some(input) - } - def addConfiguredScalacheckTests(input: FileSet) { scalacheckFiles = Some(input) } @@ -187,7 +182,6 @@ class PartestTask extends Task with CompilationPathProperty { private var runFiles: Option[FileSet] = None private var jvmFiles: Option[FileSet] = None private var residentFiles: Option[FileSet] = None - private var buildManagerFiles: Option[FileSet] = None private var scalacheckFiles: Option[FileSet] = None private var scriptFiles: Option[FileSet] = None private var shootoutFiles: Option[FileSet] = None @@ -244,7 +238,6 @@ class PartestTask extends Task with CompilationPathProperty { private def getRunFiles = getFilesAndDirs(runFiles) private def getJvmFiles = getFilesAndDirs(jvmFiles) private def getResidentFiles = getFiles(residentFiles) - private def getBuildManagerFiles = getFilesAndDirs(buildManagerFiles) private def getScalacheckFiles = getFilesAndDirs(scalacheckFiles) private def getScriptFiles = getFiles(scriptFiles) private def getShootoutFiles = getFiles(shootoutFiles) @@ -363,7 +356,6 @@ class PartestTask extends Task with CompilationPathProperty { (getRunFiles, "run", "Compiling and running files"), (getJvmFiles, "jvm", "Compiling and running files"), (getResidentFiles, "res", "Running resident compiler scenarii"), - (getBuildManagerFiles, "buildmanager", "Running Build Manager scenarii"), (getScalacheckFiles, "scalacheck", "Running scalacheck tests"), (getScriptFiles, "script", "Running script files"), (getShootoutFiles, "shootout", "Running shootout tests"), diff --git a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala index d146618d0e..6a24926b14 100644 --- a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala +++ b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala @@ -31,7 +31,6 @@ class ConsoleRunner extends DirectRunner { TestSet("run", stdFilter, "Testing interpreter and backend"), TestSet("jvm", stdFilter, "Testing JVM backend"), TestSet("res", x => x.isFile && (x hasExtension "res"), "Testing resident compiler"), - TestSet("buildmanager", _.isDirectory, "Testing Build Manager"), TestSet("shootout", stdFilter, "Testing shootout tests"), TestSet("script", stdFilter, "Testing script tests"), TestSet("scalacheck", stdFilter, "Testing ScalaCheck tests"), diff --git a/src/partest/scala/tools/partest/nest/NestUI.scala b/src/partest/scala/tools/partest/nest/NestUI.scala index ab90d387d0..df90b22448 100644 --- a/src/partest/scala/tools/partest/nest/NestUI.scala +++ b/src/partest/scala/tools/partest/nest/NestUI.scala @@ -73,7 +73,6 @@ object NestUI { println(" --run run interpreter and backend tests") println(" --jvm run JVM backend tests") println(" --res run resident compiler tests") - println(" --buildmanager run Build Manager tests") println(" --scalacheck run ScalaCheck tests") println(" --script run script runner tests") println(" --shootout run shootout tests") diff --git a/src/partest/scala/tools/partest/nest/RunnerManager.scala b/src/partest/scala/tools/partest/nest/RunnerManager.scala index fbef97dab4..0ed14dc858 100644 --- a/src/partest/scala/tools/partest/nest/RunnerManager.scala +++ b/src/partest/scala/tools/partest/nest/RunnerManager.scala @@ -19,7 +19,6 @@ import scala.tools.nsc.util.{ ClassPath, FakePos, ScalaClassLoader, stackTraceSt import ClassPath.{ join, split } import scala.tools.scalap.scalax.rules.scalasig.ByteCode import scala.collection.{ mutable, immutable } -import scala.tools.nsc.interactive.{ BuildManager, RefinedBuildManager } import scala.sys.process._ import java.util.concurrent.{ Executors, TimeUnit, TimeoutException } import PartestDefaults.{ javaCmd, javacCmd } @@ -530,121 +529,6 @@ class RunnerManager(kind: String, val fileManager: FileManager, params: TestRunP case "ant" => runAntTest(file) - case "buildmanager" => - val (swr, wr) = newTestWriters() - printInfoStart(file, wr) - val (outDir, testFile, changesDir) = { - if (!file.isDirectory) - (null, null, null) - else { - NestUI.verbose(this+" running test "+fileBase) - val outDir = createOutputDir() - val testFile = new File(file, fileBase + ".test") - val changesDir = new File(file, fileBase + ".changes") - - if (changesDir.isFile || !testFile.isFile) { - // if changes exists then it has to be a dir - if (!testFile.isFile) NestUI.verbose("invalid build manager test file") - if (changesDir.isFile) NestUI.verbose("invalid build manager changes directory") - (null, null, null) - } - else { - copyTestFiles(file, outDir) - NestUI.verbose("outDir: "+outDir) - NestUI.verbose("logFile: "+logFile) - (outDir, testFile, changesDir) - } - } - } - if (outDir == null) - return (false, LogContext(logFile)) - - // Pre-conditions satisfied - val sourcepath = outDir.getAbsolutePath+File.separator - - // configure input/output files - val logWriter = new PrintStream(new FileOutputStream(logFile), true) - val testReader = new BufferedReader(new FileReader(testFile)) - val logConsoleWriter = new PrintWriter(logWriter, true) - - // create proper settings for the compiler - val settings = new Settings(workerError) - settings.outdir.value = outDir.getAbsoluteFile.getAbsolutePath - settings.sourcepath.value = sourcepath - settings.classpath.value = fileManager.CLASSPATH - settings.Ybuildmanagerdebug.value = true - - // simulate Build Manager loop - val prompt = "builder > " - val reporter = new ConsoleReporter(settings, scala.Console.in, logConsoleWriter) - val bM: BuildManager = - new RefinedBuildManager(settings) { - override protected def newCompiler(settings: Settings) = - new BuilderGlobal(settings, reporter) - } - - def testCompile(line: String): Boolean = { - NestUI.verbose("compiling " + line) - val args = (line split ' ').toList - val command = new CompilerCommand(args, settings) - command.ok && { - bM.update(filesToSet(settings.sourcepath.value, command.files), Set.empty) - !reporter.hasErrors - } - } - - val updateFiles = (line: String) => { - NestUI.verbose("updating " + line) - (line split ' ').toList forall (u => - (u split "=>").toList match { - case origFileName::(newFileName::Nil) => - val newFile = new File(changesDir, newFileName) - if (newFile.isFile) { - val v = overwriteFileWith(new File(outDir, origFileName), newFile) - if (!v) - NestUI.verbose("'update' operation on " + u + " failed") - v - } else { - NestUI.verbose("File " + newFile + " is invalid") - false - } - case a => - NestUI.verbose("Other =: " + a) - false - } - ) - } - - def loop(): Boolean = { - testReader.readLine() match { - case null | "" => - NestUI.verbose("finished") - true - case s if s startsWith ">>update " => - updateFiles(s stripPrefix ">>update ") && loop() - case s if s startsWith ">>compile " => - val files = s stripPrefix ">>compile " - logWriter.println(prompt + files) - // In the end, it can finish with an error - if (testCompile(files)) loop() - else { - val t = testReader.readLine() - (t == null) || (t == "") - } - case s => - NestUI.verbose("wrong command in test file: " + s) - false - } - } - - Output.withRedirected(logWriter) { - try loop() - finally testReader.close() - } - fileManager.mapFile(logFile, replaceSlashes(new File(sourcepath), _)) - - (diffCheck(file, compareOutput(file, logFile)), LogContext(logFile, swr, wr)) - case "res" => { // simulate resident compiler loop val prompt = "\nnsc> " diff --git a/src/partest/scala/tools/partest/nest/TestFile.scala b/src/partest/scala/tools/partest/nest/TestFile.scala index 87177772ab..880c6e431b 100644 --- a/src/partest/scala/tools/partest/nest/TestFile.scala +++ b/src/partest/scala/tools/partest/nest/TestFile.scala @@ -54,7 +54,6 @@ abstract class TestFile(val kind: String) extends TestFileCommon { case class PosTestFile(file: JFile, fileManager: FileManager) extends TestFile("pos") case class NegTestFile(file: JFile, fileManager: FileManager) extends TestFile("neg") case class RunTestFile(file: JFile, fileManager: FileManager) extends TestFile("run") -case class BuildManagerTestFile(file: JFile, fileManager: FileManager) extends TestFile("bm") case class ScalaCheckTestFile(file: JFile, fileManager: FileManager) extends TestFile("scalacheck") case class JvmTestFile(file: JFile, fileManager: FileManager) extends TestFile("jvm") case class ShootoutTestFile(file: JFile, fileManager: FileManager) extends TestFile("shootout") { |