summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHubert Plociniczak <hubert.plociniczak@epfl.ch>2010-01-20 17:15:49 +0000
committerHubert Plociniczak <hubert.plociniczak@epfl.ch>2010-01-20 17:15:49 +0000
commit164fa5151c1f2fdb59350c1051d20c95014bc231 (patch)
tree4c880af0a78ddc41b03c6a5cbac88085cead6132
parenta259a744bb38c1cad070d459c8a59ad6c601cf74 (diff)
downloadscala-164fa5151c1f2fdb59350c1051d20c95014bc231.tar.gz
scala-164fa5151c1f2fdb59350c1051d20c95014bc231.tar.bz2
scala-164fa5151c1f2fdb59350c1051d20c95014bc231.zip
Closes #2653, #2652, #2556.
-rw-r--r--src/compiler/scala/tools/nsc/dependencies/Changes.scala12
-rw-r--r--src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala20
-rw-r--r--src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala50
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. */