diff options
author | Martin Odersky <odersky@gmail.com> | 2014-02-10 19:17:00 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-02-10 19:17:00 +0100 |
commit | 5870fbb7297b1b4bb70cbcf27cd88d4e12197234 (patch) | |
tree | 855fa843dde8b90041629786a22fa7e0187be4b3 /src/dotty/tools/dotc | |
parent | 18ae13dcf4f5d40d528e2bcf43a19e84bf475084 (diff) | |
download | dotty-5870fbb7297b1b4bb70cbcf27cd88d4e12197234.tar.gz dotty-5870fbb7297b1b4bb70cbcf27cd88d4e12197234.tar.bz2 dotty-5870fbb7297b1b4bb70cbcf27cd88d4e12197234.zip |
New scheme for incremental invalidation of parents.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r-- | src/dotty/tools/dotc/config/Printers.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Denotations.scala | 24 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/SymDenotations.scala | 115 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 8 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Implicits.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 9 |
6 files changed, 87 insertions, 74 deletions
diff --git a/src/dotty/tools/dotc/config/Printers.scala b/src/dotty/tools/dotc/config/Printers.scala index 67f05c2e7..183ab35b9 100644 --- a/src/dotty/tools/dotc/config/Printers.scala +++ b/src/dotty/tools/dotc/config/Printers.scala @@ -21,5 +21,6 @@ object Printers { val unapp: Printer = noPrinter val completions = noPrinter val gadts = noPrinter + val incremental = new Printer }
\ No newline at end of file diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala index 0d35f3cf9..6cbcd982f 100644 --- a/src/dotty/tools/dotc/core/Denotations.scala +++ b/src/dotty/tools/dotc/core/Denotations.scala @@ -17,8 +17,6 @@ import config.Config import util.common._ import Decorators.SymbolIteratorDecorator - - /** Denotations represent the meaning of symbols and named types. * The following diagram shows how the principal types of denotations * and their denoting entities relate to each other. Lines ending in @@ -463,12 +461,13 @@ object Denotations { protected def bringForward()(implicit ctx: Context): SingleDenotation = this match { case denot: SymDenotation if ctx.stillValid(denot) => + if (denot.exists) assert(ctx.runId > validFor.runId) var d: SingleDenotation = denot do { d.validFor = Period(ctx.period.runId, d.validFor.firstPhaseId, d.validFor.lastPhaseId) d = d.nextInRun } while (d ne denot) - initial.copyIfParentInvalid + initial.syncWithParents case _ => staleSymbolError } @@ -506,7 +505,7 @@ object Denotations { var startPid = cur.validFor.lastPhaseId + 1 val transformers = ctx.transformersFor(cur) val transformer = transformers.nextTransformer(startPid) - next = transformer.transform(cur).copyIfParentInvalid + next = transformer.transform(cur).syncWithParents if (next eq cur) startPid = cur.validFor.firstPhaseId else { @@ -530,14 +529,20 @@ object Denotations { } } - def staleSymbolError(implicit ctx: Context) = - throw new StaleSymbol(s"stale symbol; $this in ${this.asSymDenotation.owner}, defined in run ${myValidFor.runId}, is referred to in run ${ctx.period.runId}") + def staleSymbolError(implicit ctx: Context) = { + def ownerMsg = this match { + case denot: SymDenotation => s"in ${denot.owner}" + case _ => "" + } + def msg = s"stale symbol; $this#${symbol.id}$ownerMsg, defined in run ${myValidFor.runId}, is referred to in run ${ctx.period.runId}" + throw new StaleSymbol(msg) + } /** For ClassDenotations only: * If caches influenced by parent classes are still valid, the denotation * itself, otherwise a freshly initialized copy. */ - def copyIfParentInvalid(implicit ctx: Context): SingleDenotation = this + def syncWithParents(implicit ctx: Context): SingleDenotation = this override def toString = if (symbol == NoSymbol) symbol.toString @@ -759,6 +764,9 @@ object Denotations { NoSymbol } - class StaleSymbol(msg: String) extends Exception(msg) + /** An exception for accessing symbols that are no longer valid in current run */ + class StaleSymbol(msg: => String) extends Exception { + override def getMessage() = msg + } } diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index a3e8c4f62..1bb912059 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -30,26 +30,28 @@ trait SymDenotations { this: Context => initPrivateWithin: Symbol = NoSymbol)(implicit ctx: Context): SymDenotation = { val result = if (symbol.isClass) - if (initFlags is Package) new PackageClassDenotation(symbol, owner, name, initFlags, initInfo, initPrivateWithin) - else new ClassDenotation(symbol, owner, name, initFlags, initInfo, initPrivateWithin) + if (initFlags is Package) new PackageClassDenotation(symbol, owner, name, initFlags, initInfo, initPrivateWithin, ctx.runId) + else new ClassDenotation(symbol, owner, name, initFlags, initInfo, initPrivateWithin, ctx.runId) else new SymDenotation(symbol, owner, name, initFlags, initInfo, initPrivateWithin) - result.firstRunId = ctx.runId result.validFor = stablePeriod result } - def stillValid(denot: SymDenotation): Boolean = try + def stillValid(denot: SymDenotation): Boolean = if (denot is ValidForever) true - else if (denot.owner is PackageClass) denot.owner.decls.lookup(denot.name) eq denot.symbol - else - stillValid(denot.owner) && ( - (denot.owner.firstRunId == denot.firstRunId) || { - println(s"no longer valid: $denot, was defined in ${denot.firstRunId}, owner ${denot.owner} was defined in ${denot.owner.firstRunId}") - false - }) - catch { - case ex: StaleSymbol => false - } + else try { + val owner = denot.owner.denot + def isSelfSym = owner.infoOrCompleter match { + case ClassInfo(_, _, _, _, selfInfo) => selfInfo == denot.symbol + case _ => false + } + stillValid(owner) && owner.isClass && ( + (owner.decls.lookupAll(denot.name) contains denot.symbol) + || isSelfSym + ) + } catch { + case ex: StaleSymbol => false + } } object SymDenotations { @@ -69,8 +71,6 @@ object SymDenotations { override def hasUniqueSym: Boolean = exists - private[SymDenotations] var firstRunId: RunId = _ - // ------ Getting and setting fields ----------------------------- private[this] var myFlags: FlagSet = adaptFlags(initFlags) @@ -731,8 +731,6 @@ object SymDenotations { val annotations1 = if (annotations != null) annotations else this.annotations val d = ctx.SymDenotation(symbol, owner, name, initFlags1, info1, privateWithin1) d.annotations = annotations1 - d.firstRunId = firstRunId - // what about validFor? d } } @@ -745,7 +743,8 @@ object SymDenotations { name: Name, initFlags: FlagSet, initInfo: Type, - initPrivateWithin: Symbol = NoSymbol) + initPrivateWithin: Symbol, + initRunId: RunId) extends SymDenotation(symbol, ownerIfExists, name, initFlags, initInfo, initPrivateWithin) { import util.LRUCache @@ -771,8 +770,9 @@ object SymDenotations { myTypeParams } - private def myClassParents(implicit ctx: Context): List[TypeRef] = info match { - case classInfo: ClassInfo => classInfo.myClassParents + /** The denotations of all parents in this class. */ + def classParents(implicit ctx: Context): List[TypeRef] = info match { + case classInfo: ClassInfo => classInfo.classParents case _ => Nil } @@ -781,51 +781,45 @@ object SymDenotations { * @see Namer#ClassCompleter */ private def isFullyCompleted(implicit ctx: Context): Boolean = - isCompleted && myClassParents.nonEmpty - - /** A key to verify that all caches influenced by parent classes are valid */ - private var parentDenots: List[Denotation] = null + isCompleted && classParents.nonEmpty - /** The denotations of all parents in this class. - * Note: Always use this method instead of `classInfo.myClassParents` - * because the latter does not ensure that the `parentDenots` key - * is up-to-date, which might lead to invalid caches later on. - */ - def classParents(implicit ctx: Context): List[TypeRef] = { - val ps = myClassParents - if (parentDenots == null && ps.nonEmpty) parentDenots = ps map (_.denot) - ps - } + // ------ syncing inheritance-related info ----------------------------- - /** Are caches influenced by parent classes still valid? */ - private def parentsAreValid(implicit ctx: Context): Boolean = - parentDenots == null || - parentDenots.corresponds(myClassParents map (_.denot))(_ eq _) - - private var copied = 0 + private var firstRunId: RunId = initRunId /** If caches influenced by parent classes are still valid, the denotation * itself, otherwise a freshly initialized copy. */ - override def copyIfParentInvalid(implicit ctx: Context): SingleDenotation = - if (!parentsAreValid) { - println(s"parents of $this are invalid; copying $hashCode, symbol id = ${symbol.id} ...") - for ((pd1, pd2) <- parentDenots zip (myClassParents map (_.denot))) - if (pd1 ne pd2) println(s"different: $pd1 != $pd2") - assert(copied == 0) - copied += 1 - copySymDenotation() + override def syncWithParents(implicit ctx: Context): SingleDenotation = { + def isYounger(tref: TypeRef) = tref.symbol.denot match { + case denot: ClassDenotation => + if (denot.validFor.runId < ctx.runId) denot.current // syncs with its parents in turn + val result = denot.firstRunId > this.firstRunId + if (result) incremental.println(s"$denot is younger than $this") + result + case _ => false } - else this - - protected override def bringForward()(implicit ctx: Context): SingleDenotation = { - assert(ctx.runId >= symbol.defRunId, s"$this, defrunid = ${symbol.defRunId}, ctx.runid = ${ctx.runId}") - if (symbol.defRunId == ctx.runId) symbol.denot - else { - val d = super.bringForward() - symbol.denot = d.asSymDenotation - d + val parentIsYounger = (firstRunId < ctx.runId) && { + infoOrCompleter match { + case cinfo: ClassInfo => cinfo.classParents exists isYounger + case _ => false + } + } + if (parentIsYounger) { + incremental.println(s"parents of $this are invalid; symbol id = ${symbol.id}, copying ...\n") + invalidateInheritedInfo() + firstRunId = ctx.runId } + this + } + + /** Invalidate all caches and fields that depend on base classes and their contents */ + private def invalidateInheritedInfo(): Unit = { + myBaseClasses = null + mySuperClassBits = null + myMemberFingerPrint = FingerPrint.unknown + myMemberCache = null + memberNamesCache = SimpleMap.Empty } // ------ class-specific operations ----------------------------------- @@ -1175,8 +1169,9 @@ object SymDenotations { name: Name, initFlags: FlagSet, initInfo: Type, - initPrivateWithin: Symbol = NoSymbol) - extends ClassDenotation(symbol, ownerIfExists, name, initFlags, initInfo, initPrivateWithin) { + initPrivateWithin: Symbol, + initRunId: RunId) + extends ClassDenotation(symbol, ownerIfExists, name, initFlags, initInfo, initPrivateWithin, initRunId) { private[this] var packageObjCache: SymDenotation = _ private[this] var packageObjRunId: RunId = NoRunId diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 28a7f9e67..49b57d32f 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -1793,7 +1793,7 @@ object Types { abstract case class ClassInfo( prefix: Type, cls: ClassSymbol, - myClassParents: List[TypeRef], // to be used only in ClassDenotation! + classParents: List[TypeRef], decls: Scope, selfInfo: DotClass /* should be: Type | Symbol */) extends CachedGroundType with TypeType { @@ -1842,10 +1842,10 @@ object Types { def derivedClassInfo(prefix: Type)(implicit ctx: Context) = if (prefix eq this.prefix) this - else ClassInfo(prefix, cls, myClassParents, decls, selfInfo) + else ClassInfo(prefix, cls, classParents, decls, selfInfo) - def derivedClassInfo(prefix: Type = this.prefix, classParents: List[TypeRef] = myClassParents, selfInfo: DotClass = this.selfInfo)(implicit ctx: Context) = - if ((prefix eq this.prefix) && (classParents eq this.myClassParents) && (selfInfo eq this.selfInfo)) this + def derivedClassInfo(prefix: Type = this.prefix, classParents: List[TypeRef] = classParents, selfInfo: DotClass = this.selfInfo)(implicit ctx: Context) = + if ((prefix eq this.prefix) && (classParents eq this.classParents) && (selfInfo eq this.selfInfo)) this else ClassInfo(prefix, cls, classParents, decls, selfInfo) override def computeHash = doHash(cls, prefix) diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index f40b63bba..a5cbef571 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -343,7 +343,7 @@ trait ImplicitRunInfo { self: RunInfo => } /** A map that counts the number of times an implicit ref was picked */ - val useCount = new mutable.HashMap[TermRef, Int] { + val useCount: mutable.Map[TermRef, Int] = new mutable.HashMap[TermRef, Int] { // !!! override def default(key: TermRef) = 0 } } @@ -628,7 +628,7 @@ class SearchHistory(val searchDepth: Int, val seen: Map[ClassSymbol, Int]) { class TermRefSet(implicit ctx: Context) extends mutable.Traversable[TermRef] { import collection.JavaConverters._ private val elems = (new java.util.LinkedHashMap[TermSymbol, List[Type]]).asScala - + def += (ref: TermRef): Unit = { val pre = ref.prefix val sym = ref.symbol.asTerm diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index bce9d225a..697441ca1 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -63,6 +63,15 @@ class Typer extends Namer with Applications with Implicits { */ private var importedFromRoot: Set[Symbol] = Set() + /** A denotation exists really if it exists and does not point to a stale symbol. + def reallyExists(denot: Denotation)(implicit ctx: Context): Boolean = denot match { + case denot: SymDenotation => + denot.ensureCompleted + denot.exists && !denot.isAbsent + case _ => + true + }*/ + /** A denotation exists really if it exists and does not point to a stale symbol. */ def reallyExists(denot: Denotation)(implicit ctx: Context): Boolean = try |