@@ -69,7 +69,7 @@ object Contexts {
6969
7070 /** Execute `op` at given phase */
7171 inline def atPhase [T ](phase : Phase )(inline op : Context ?=> T )(using Context ): T =
72- atPhase(phase.id)(op )
72+ op( using ctx.withPhase(phase) )
7373
7474 inline def atNextPhase [T ](inline op : Context ?=> T )(using Context ): T =
7575 atPhase(ctx.phase.next)(op)
@@ -262,7 +262,7 @@ object Contexts {
262262
263263 /** Sourcefile corresponding to given abstract file, memoized */
264264 def getSource (file : AbstractFile , codec : => Codec = Codec (settings.encoding.value)) = {
265- util.Stats .record(" getSource" )
265+ util.Stats .record(" Context. getSource" )
266266 base.sources.getOrElseUpdate(file, new SourceFile (file, codec))
267267 }
268268
@@ -285,33 +285,49 @@ object Contexts {
285285 /** Sourcefile with given path, memoized */
286286 def getSource (path : String ): SourceFile = getSource(path.toTermName)
287287
288- /** Those fields are used to cache phases created in withPhase.
289- * phasedCtx is first phase with altered phase ever requested.
290- * phasedCtxs is array that uses phaseId's as indexes,
291- * contexts are created only on request and cached in this array
292- */
293- private var phasedCtx : Context = this
294- private var phasedCtxs : Array [Context ] = null
288+ private var related : SimpleIdentityMap [Phase | SourceFile , Context ] = null
295289
296- /** This context at given phase.
297- * This method will always return a phase period equal to phaseId, thus will never return a fused phase
298- */
299- final def withPhase (phaseId : PhaseId ): Context =
300- if (this .period.phaseId == phaseId) this
301- else if (phasedCtx.period.phaseId == phaseId) phasedCtx
302- else if (phasedCtxs != null && phasedCtxs(phaseId) != null ) phasedCtxs(phaseId)
303- else {
304- val ctx1 = fresh.setPhase(phaseId)
305- if (phasedCtx eq this ) phasedCtx = ctx1
306- else {
307- if (phasedCtxs == null ) phasedCtxs = new Array [Context ](base.phases.length)
308- phasedCtxs(phaseId) = ctx1
309- }
290+ private def lookup (key : Phase | SourceFile ): Context =
291+ util.Stats .record(" Context.related.lookup" )
292+ if related == null then
293+ related = SimpleIdentityMap .Empty
294+ null
295+ else
296+ related(key)
297+
298+ private def withPhase (phase : Phase , pid : PhaseId ): Context =
299+ util.Stats .record(" Context.withPhase" )
300+ val curId = phaseId
301+ if curId == pid then
302+ this
303+ else
304+ var ctx1 = lookup(phase)
305+ if ctx1 == null then
306+ util.Stats .record(" Context.withPhase.new" )
307+ ctx1 = fresh.setPhase(pid)
308+ related = related.updated(phase, ctx1)
310309 ctx1
311- }
312310
313- final def withPhase (phase : Phase ): Context =
314- withPhase(phase.id)
311+ final def withPhase (phase : Phase ): Context = withPhase(phase, phase.id)
312+ final def withPhase (pid : PhaseId ): Context = withPhase(base.phases(pid), pid)
313+
314+ final def withSource (source : SourceFile ): Context =
315+ util.Stats .record(" Context.withSource" )
316+ if this .source eq source then
317+ this
318+ else
319+ var ctx1 = lookup(source)
320+ if ctx1 == null then
321+ util.Stats .record(" Context.withSource.new" )
322+ val ctx2 = fresh.setSource(source)
323+ if ctx2.compilationUnit == null then
324+ // `source` might correspond to a file not necessarily
325+ // in the current project (e.g. when inlining library code),
326+ // so set `mustExist` to false.
327+ ctx2.setCompilationUnit(CompilationUnit (source, mustExist = false ))
328+ ctx1 = ctx2
329+ related = related.updated(source, ctx2)
330+ ctx1
315331
316332 inline def evalAt [T ](phase : Phase )(inline op : Context ?=> T ): T =
317333 val saved = period
@@ -482,8 +498,7 @@ object Contexts {
482498
483499 def reuseIn (outer : Context ): this .type =
484500 implicitsCache = null
485- phasedCtxs = null
486- sourceCtx = null
501+ related = null
487502 init(outer, outer)
488503
489504 /** A fresh clone of this context embedded in this context. */
@@ -497,29 +512,6 @@ object Contexts {
497512 final def withOwner (owner : Symbol ): Context =
498513 if (owner ne this .owner) fresh.setOwner(owner) else this
499514
500- private var sourceCtx : SimpleIdentityMap [SourceFile , Context ] = null
501-
502- final def withSource (source : SourceFile ): Context =
503- if (source `eq` this .source) this
504- else if ((source `eq` outer.source) &&
505- outer.sourceCtx != null &&
506- (outer.sourceCtx(this .source) `eq` this )) outer
507- else {
508- if (sourceCtx == null ) sourceCtx = SimpleIdentityMap .Empty
509- val prev = sourceCtx(source)
510- if (prev != null ) prev
511- else {
512- val newCtx = fresh.setSource(source)
513- if (newCtx.compilationUnit == null )
514- // `source` might correspond to a file not necessarily
515- // in the current project (e.g. when inlining library code),
516- // so set `mustExist` to false.
517- newCtx.setCompilationUnit(CompilationUnit (source, mustExist = false ))
518- sourceCtx = sourceCtx.updated(source, newCtx)
519- newCtx
520- }
521- }
522-
523515 final def withProperty [T ](key : Key [T ], value : Option [T ]): Context =
524516 if (property(key) == value) this
525517 else value match {
@@ -738,6 +730,7 @@ object Contexts {
738730 result
739731
740732 inline def comparing [T ](inline op : TypeComparer => T )(using Context ): T =
733+ util.Stats .record(" comparing" )
741734 val saved = ctx.base.comparersInUse
742735 try op(comparer)
743736 finally ctx.base.comparersInUse = saved
0 commit comments