diff options
author | Hubert Plociniczak <hubert.plociniczak@epfl.ch> | 2010-01-20 17:15:49 +0000 |
---|---|---|
committer | Hubert Plociniczak <hubert.plociniczak@epfl.ch> | 2010-01-20 17:15:49 +0000 |
commit | 164fa5151c1f2fdb59350c1051d20c95014bc231 (patch) | |
tree | 4c880af0a78ddc41b03c6a5cbac88085cead6132 | |
parent | a259a744bb38c1cad070d459c8a59ad6c601cf74 (diff) | |
download | scala-164fa5151c1f2fdb59350c1051d20c95014bc231.tar.gz scala-164fa5151c1f2fdb59350c1051d20c95014bc231.tar.bz2 scala-164fa5151c1f2fdb59350c1051d20c95014bc231.zip |
Closes #2653, #2652, #2556.
3 files changed, 79 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/nsc/dependencies/Changes.scala b/src/compiler/scala/tools/nsc/dependencies/Changes.scala index 530519b148..5d261c67a2 100644 --- a/src/compiler/scala/tools/nsc/dependencies/Changes.scala +++ b/src/compiler/scala/tools/nsc/dependencies/Changes.scala @@ -18,6 +18,9 @@ abstract class Changes { abstract class Change + private lazy val annotationsChecked = + List(definitions.getClass("scala.specialized")) // Any others that should be checked? + /** Are the new modifiers more restrictive than the old ones? */ private def moreRestrictive(from: Long, to: Long): Boolean = ((((to & PRIVATE) != 0L) && (from & PRIVATE) == 0L) @@ -36,11 +39,15 @@ abstract class Changes { case class Changed(e: Entity)(implicit val reason: String) extends Change { override def toString = "Changed(" + e + ")[" + reason + "]" } + case class ParentChanged(e: Entity) extends Change private def sameSymbol(sym1: Symbol, sym2: Symbol): Boolean = sym1.fullNameString == sym2.fullNameString private def sameFlags(sym1: Symbol, sym2: Symbol): Boolean = sym1.flags == sym2.flags + private def sameAnnotations(sym1: Symbol, sym2: Symbol): Boolean = + annotationsChecked.forall(a => + (sym1.hasAnnotation(a) == sym2.hasAnnotation(a))) private def sameType(tp1: Type, tp2: Type) = { def typeOf(tp: Type): String = tp.toString + "[" + tp.getClass + "]" @@ -69,6 +76,7 @@ abstract class Changes { value1 == value2 case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => sameType(pre1, pre2) && sameSymbol(sym1, sym2) && + (sym1.variance == sym2.variance) && ((tp1.isHigherKinded && tp2.isHigherKinded && tp1.normalize =:= tp2.normalize) || sameTypes(args1, args2)) // @M! normalize reduces higher-kinded case to PolyType's @@ -133,7 +141,8 @@ abstract class Changes { private def sameTypeParams(tparams1: List[Symbol], tparams2: List[Symbol]) = sameTypes(tparams1 map (_.info), tparams2 map (_.info)) && - sameTypes(tparams1 map (_.tpe), tparams2 map (_.tpe)) + sameTypes(tparams1 map (_.tpe), tparams2 map (_.tpe)) && + (tparams1 corresponds tparams2)((t1, t2) => sameAnnotations(t1, t2)) def sameTypes(tps1: List[Type], tps2: List[Type]) = (tps1 corresponds tps2)(sameType) @@ -183,6 +192,7 @@ abstract class Changes { } def removeChangeSet(sym: Symbol): Change = Removed(toEntity(sym)) def changeChangeSet(sym: Symbol, msg: String): Change = Changed(toEntity(sym))(msg) + def parentChangeSet(sym: Symbol): Change = ParentChanged(toEntity(sym)) private def toEntity(sym: Symbol): Entity = if (sym.isClass) Class(sym.fullNameString) diff --git a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala index 5ce0cfdb1c..40198fbadd 100644 --- a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala +++ b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala @@ -57,6 +57,12 @@ trait DependencyAnalysis extends SubComponent with Files { 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) @@ -106,6 +112,8 @@ trait DependencyAnalysis extends SubComponent with Files { filtered } + case class Inherited(q: String, name: Name) + class AnalysisPhase(prev : Phase) extends StdPhase(prev){ def apply(unit : global.CompilationUnit) { val f = unit.source.file.file; @@ -139,6 +147,7 @@ trait DependencyAnalysis extends SubComponent with Files { // 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] @@ -172,7 +181,16 @@ trait DependencyAnalysis extends SubComponent with Files { checkType(ddef.symbol.tpe) } super.traverse(tree) - + case a @ Select(q, n) if (q.symbol != null) => // #2556 + if (!a.symbol.isConstructor && !a.symbol.owner.isPackage) { + val tpe1 = q.symbol.tpe match { + case MethodType(_, t) => t // Constructor + case t => t + } + if (!isSameType(tpe1, a.symbol.owner.tpe)) + inherited += file -> (inherited(file) + Inherited(tpe1.safeToString, n)) + } + super.traverse(tree) case _ => super.traverse(tree) } diff --git a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala index 9ca9a740df..5e1729a515 100644 --- a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala +++ b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala @@ -41,6 +41,7 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana val compiler = newCompiler(settings) import compiler.{Symbol, Type, atPhase, currentRun} + import compiler.dependencyAnalysis.Inherited private case class SymWithHistory(sym: Symbol, befErasure: Type) @@ -55,6 +56,15 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana /** 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 var 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 @@ -200,7 +210,7 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana buf += file directDeps -= file for (syms <- definitions(file)) // fixes #2557 - newChangesOf(syms.sym) = List(change) + newChangesOf(syms.sym) = List(change, parentChangeSet(syms.sym)) break } @@ -260,11 +270,32 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana } } + def checkInheritedReferences(file: AbstractFile) { + val refs = inherited(file) + if (!inherited.isEmpty) + change match { + case ParentChanged(Class(name)) => + refs.find(p => (p != null && p.q == name)) match { + case Some(Inherited(q, member)) => + findSymbol(q) match { + case Some(s) => + if (s.tpe.nonPrivateMember(member) == compiler.NoSymbol) + invalidate(file, "it references invalid (no longer inherited) defintion", change) + case None => // TODO: log/throw error? + } + case None => + } + () + 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) } } } @@ -274,10 +305,26 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana invalidated(buf.clone() --= processed, newChangesOf, processed ++ buf) } + private def findSymbol(classFullName: String): Option[Symbol] = { + classes.get(classFullName) match { + case Some(file) => + definitions.get(file) match { + case Some(defs) => + defs.find(p => (p.sym.fullNameString == classFullName)) match { + case Some(s) => Some(s.sym) + case _ => None + } + case None => None + } + case None => None + } + } + /** Update the map of definitions per source file */ private def updateDefinitions(files: Set[AbstractFile]) { for (src <- files; val localDefs = compiler.dependencyAnalysis.definitions(src)) { definitions(src) = (localDefs map (s => { + this.classes += s.fullNameString -> src SymWithHistory( s.cloneSymbol, atPhase(currentRun.erasurePhase.prev) { @@ -286,6 +333,7 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana })) } this.references = compiler.dependencyAnalysis.references + this.inherited = compiler.dependencyAnalysis.inherited } /** Load saved dependency information. */ |