Skip to content

Streamline treatment of withPhase and withSource #9589

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 19, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 44 additions & 51 deletions compiler/src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ object Contexts {

/** Execute `op` at given phase */
inline def atPhase[T](phase: Phase)(inline op: Context ?=> T)(using Context): T =
atPhase(phase.id)(op)
op(using ctx.withPhase(phase))

inline def atNextPhase[T](inline op: Context ?=> T)(using Context): T =
atPhase(ctx.phase.next)(op)
Expand Down Expand Up @@ -262,7 +262,7 @@ object Contexts {

/** Sourcefile corresponding to given abstract file, memoized */
def getSource(file: AbstractFile, codec: => Codec = Codec(settings.encoding.value)) = {
util.Stats.record("getSource")
util.Stats.record("Context.getSource")
base.sources.getOrElseUpdate(file, new SourceFile(file, codec))
}

Expand All @@ -285,33 +285,49 @@ object Contexts {
/** Sourcefile with given path, memoized */
def getSource(path: String): SourceFile = getSource(path.toTermName)

/** Those fields are used to cache phases created in withPhase.
* phasedCtx is first phase with altered phase ever requested.
* phasedCtxs is array that uses phaseId's as indexes,
* contexts are created only on request and cached in this array
*/
private var phasedCtx: Context = this
private var phasedCtxs: Array[Context] = null
private var related: SimpleIdentityMap[Phase | SourceFile, Context] = null

/** This context at given phase.
* This method will always return a phase period equal to phaseId, thus will never return a fused phase
*/
final def withPhase(phaseId: PhaseId): Context =
if (this.period.phaseId == phaseId) this
else if (phasedCtx.period.phaseId == phaseId) phasedCtx
else if (phasedCtxs != null && phasedCtxs(phaseId) != null) phasedCtxs(phaseId)
else {
val ctx1 = fresh.setPhase(phaseId)
if (phasedCtx eq this) phasedCtx = ctx1
else {
if (phasedCtxs == null) phasedCtxs = new Array[Context](base.phases.length)
phasedCtxs(phaseId) = ctx1
}
private def lookup(key: Phase | SourceFile): Context =
util.Stats.record("Context.related.lookup")
if related == null then
related = SimpleIdentityMap.Empty
null
else
related(key)

private def withPhase(phase: Phase, pid: PhaseId): Context =
util.Stats.record("Context.withPhase")
val curId = phaseId
if curId == pid then
this
else
var ctx1 = lookup(phase)
if ctx1 == null then
util.Stats.record("Context.withPhase.new")
ctx1 = fresh.setPhase(pid)
related = related.updated(phase, ctx1)
ctx1
}

final def withPhase(phase: Phase): Context =
withPhase(phase.id)
final def withPhase(phase: Phase): Context = withPhase(phase, phase.id)
final def withPhase(pid: PhaseId): Context = withPhase(base.phases(pid), pid)

final def withSource(source: SourceFile): Context =
util.Stats.record("Context.withSource")
if this.source eq source then
this
else
var ctx1 = lookup(source)
if ctx1 == null then
util.Stats.record("Context.withSource.new")
val ctx2 = fresh.setSource(source)
if ctx2.compilationUnit == null then
// `source` might correspond to a file not necessarily
// in the current project (e.g. when inlining library code),
// so set `mustExist` to false.
ctx2.setCompilationUnit(CompilationUnit(source, mustExist = false))
ctx1 = ctx2
related = related.updated(source, ctx2)
ctx1

// `creationTrace`-related code. To enable, uncomment the code below and the
// call to `setCreationTrace()` in this file.
Expand Down Expand Up @@ -478,8 +494,7 @@ object Contexts {

def reuseIn(outer: Context): this.type =
implicitsCache = null
phasedCtxs = null
sourceCtx = null
related = null
init(outer, outer)

/** A fresh clone of this context embedded in this context. */
Expand All @@ -493,29 +508,6 @@ object Contexts {
final def withOwner(owner: Symbol): Context =
if (owner ne this.owner) fresh.setOwner(owner) else this

private var sourceCtx: SimpleIdentityMap[SourceFile, Context] = null

final def withSource(source: SourceFile): Context =
if (source `eq` this.source) this
else if ((source `eq` outer.source) &&
outer.sourceCtx != null &&
(outer.sourceCtx(this.source) `eq` this)) outer
else {
if (sourceCtx == null) sourceCtx = SimpleIdentityMap.Empty
val prev = sourceCtx(source)
if (prev != null) prev
else {
val newCtx = fresh.setSource(source)
if (newCtx.compilationUnit == null)
// `source` might correspond to a file not necessarily
// in the current project (e.g. when inlining library code),
// so set `mustExist` to false.
newCtx.setCompilationUnit(CompilationUnit(source, mustExist = false))
sourceCtx = sourceCtx.updated(source, newCtx)
newCtx
}
}

final def withProperty[T](key: Key[T], value: Option[T]): Context =
if (property(key) == value) this
else value match {
Expand Down Expand Up @@ -734,6 +726,7 @@ object Contexts {
result

inline def comparing[T](inline op: TypeComparer => T)(using Context): T =
util.Stats.record("comparing")
val saved = ctx.base.comparersInUse
try op(comparer)
finally ctx.base.comparersInUse = saved
Expand Down