From 797b2aeda3786b4d38ad389380ee5f24fff1c9d6 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Thu, 26 Nov 2009 12:05:45 +0000 Subject: Closes #2562 --- .../nsc/interactive/RefinedBuildManager.scala | 54 +++++++++++++++++----- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala index 6af23f8fde..893ed7b0e9 100644 --- a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala +++ b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala @@ -87,7 +87,10 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana * of the dependency analysis. */ private def update(files: Set[AbstractFile]) = { - def update0(files: Set[AbstractFile], updated: Set[AbstractFile]): Unit = if (!files.isEmpty) { + val coll: mutable.Map[AbstractFile, immutable.Set[AbstractFile]] = + mutable.HashMap[AbstractFile, immutable.Set[AbstractFile]]() + + def update0(files: Set[AbstractFile]): Unit = if (!files.isEmpty) { deleteClassfiles(files) val run = compiler.newRun() compiler.inform("compiling " + files) @@ -105,8 +108,8 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana val defs = compiler.dependencyAnalysis.definitions for (src <- files) { if (definitions(src).isEmpty) - additionalDefs ++= compiler.dependencyAnalysis. - dependencies.dependentFiles(1, mutable.Set(src)) + additionalDefs ++= compiler.dependencyAnalysis. + dependencies.dependentFiles(1, mutable.Set(src)) else { val syms = defs(src) for (sym <- syms) { @@ -130,29 +133,56 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana } println("Changes: " + changesOf) updateDefinitions(files) - val compiled = updated ++ files - val invalid = invalidated(files, changesOf, additionalDefs.clone() ++= compiled) - update0(invalid -- compiled, compiled) + val invalid = invalidated(files, changesOf, additionalDefs) + update0(checkCycles(invalid, files, coll)) } - update0(files, immutable.Set()) + update0(files) } + // 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: collection.Map[Symbol, List[Change]], - processed: Set[AbstractFile] = Set.empty): Set[AbstractFile] = { + 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) - directDeps --= processed def invalidate(file: AbstractFile, reason: String, change: Change) = { println("invalidate " + file + " because " + reason + " [" + change + "]") buf += file directDeps -= file - for (sym <- definitions(file)) + for (sym <- definitions(file)) // fixes #2557 newChangesOf(sym) = List(change) break } @@ -160,7 +190,7 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana for ((oldSym, changes) <- changesOf; change <- changes) { def checkParents(cls: Symbol, file: AbstractFile) { val parentChange = cls.info.parents.exists(_.typeSymbol.fullNameString == oldSym.fullNameString) -// println("checkParents " + cls + " oldSym: " + oldSym + " parentChange: " + parentChange + " " + cls.info.parents) + // println("checkParents " + cls + " oldSym: " + oldSym + " parentChange: " + parentChange + " " + cls.info.parents) change match { case Changed(Class(_)) if parentChange => invalidate(file, "parents have changed", change) @@ -192,7 +222,7 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana } def checkReferences(file: AbstractFile) { -// println(file + ":" + references(file)) + // println(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) -- cgit v1.2.3