Track public inherited dependencies.

There is a public inherited dependency on each (normalized) base
class of a public template (class, module, trait, structural type).
This commit is contained in:
Mark Harrah 2013-04-26 22:35:27 -04:00
parent 0e1f211fe5
commit c355bef200
3 changed files with 26 additions and 4 deletions

View File

@ -39,6 +39,7 @@ final class API(val global: CallbackGlobal) extends Compat
def processScalaUnit(unit: CompilationUnit)
{
val sourceFile = unit.source.file.file
currentSourceFile = sourceFile
debug("Traversing " + sourceFile)
val traverser = new TopLevelHandler(sourceFile)
traverser.apply(unit.body)
@ -50,6 +51,10 @@ final class API(val global: CallbackGlobal) extends Compat
}
}
// Tracks the source file associated with the CompilationUnit currently being processed by the API phase.
// This is used when recording inheritance dependencies.
private[this] var currentSourceFile: File = _
// this cache reduces duplicate work both here and when persisting
// caches on other structures had minimal effect on time and cache size
// (tried: Definition, Modifier, Path, Id, String)
@ -237,8 +242,18 @@ final class API(val global: CallbackGlobal) extends Compat
mkStructure(s, baseTypes, ds, is)
}
private def mkStructure(s: Symbol, bases: List[Type], declared: List[Symbol], inherited: List[Symbol]): xsbti.api.Structure =
// If true, this template is publicly visible and should be processed as a public inheritance dependency.
// Local classes and local refinements will never be traversed by the api phase, so we don't need to check for that.
private[this] def isPublicStructure(s: Symbol): Boolean =
s.isStructuralRefinement ||
// do not consider templates that are private[this] or private
!(s.isPrivate && (s.privateWithin == NoSymbol || s.isLocal))
private def mkStructure(s: Symbol, bases: List[Type], declared: List[Symbol], inherited: List[Symbol]): xsbti.api.Structure = {
if(isPublicStructure(s))
addInheritedDependencies(currentSourceFile, bases.map(_.dealias.typeSymbol))
new xsbti.api.Structure(lzy(types(s, bases)), lzy(processDefinitions(s, declared)), lzy(processDefinitions(s, inherited)))
}
private def processDefinitions(in: Symbol, defs: List[Symbol]): Array[xsbti.api.Definition] =
sort(defs.toArray).flatMap( (d: Symbol) => definition(in, d))
private[this] def sort(defs: Array[Symbol]): Array[Symbol] = {

View File

@ -33,9 +33,11 @@ final class Analyzer(val global: CallbackGlobal) extends Compat
// build dependencies structure
val sourceFile = unit.source.file.file
callback.beginSource(sourceFile)
for(on <- unit.depends)
for(on <- unit.depends) processDependency(on, inherited=false)
for(on <- inheritedDependencies.getOrElse(sourceFile, Nil: Iterable[Symbol])) processDependency(on, inherited=true)
def processDependency(on: Symbol, inherited: Boolean)
{
def binaryDependency(file: File, className: String) = callback.binaryDependency(file, className, sourceFile)
def binaryDependency(file: File, className: String) = callback.binaryDependency(file, className, sourceFile /*, inherited*/)
val onSource = on.sourceFile
if(onSource == null)
{
@ -53,7 +55,7 @@ final class Analyzer(val global: CallbackGlobal) extends Compat
}
}
else
callback.sourceDependency(onSource.file, sourceFile)
callback.sourceDependency(onSource.file, sourceFile /*, inherited*/)
}
// build list of generated classes

View File

@ -42,6 +42,11 @@ sealed abstract class CallbackGlobal(settings: Settings, reporter: reporters.Rep
case multi: MultipleOutput => multi.outputGroups.toStream map (_.outputDirectory)
}
}
// Map source files to public inherited dependencies. These dependencies are tracked as the symbol for the dealiased base class.
val inheritedDependencies = new mutable.HashMap[File, mutable.Set[Symbol]]
def addInheritedDependencies(file: File, deps: Iterable[Symbol]) {
inheritedDependencies.getOrElseUpdate(file, new mutable.HashSet) ++= deps
}
}
class InterfaceCompileFailed(val arguments: Array[String], val problems: Array[Problem], override val toString: String) extends xsbti.CompileFailed