@@ -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 // `creationTrace`-related code. To enable, uncomment the code below and the
317333 // call to `setCreationTrace()` in this file.
@@ -478,8 +494,7 @@ object Contexts {
478494
479495 def reuseIn (outer : Context ): this .type =
480496 implicitsCache = null
481- phasedCtxs = null
482- sourceCtx = null
497+ related = null
483498 init(outer, outer)
484499
485500 /** A fresh clone of this context embedded in this context. */
@@ -493,29 +508,6 @@ object Contexts {
493508 final def withOwner (owner : Symbol ): Context =
494509 if (owner ne this .owner) fresh.setOwner(owner) else this
495510
496- private var sourceCtx : SimpleIdentityMap [SourceFile , Context ] = null
497-
498- final def withSource (source : SourceFile ): Context =
499- if (source `eq` this .source) this
500- else if ((source `eq` outer.source) &&
501- outer.sourceCtx != null &&
502- (outer.sourceCtx(this .source) `eq` this )) outer
503- else {
504- if (sourceCtx == null ) sourceCtx = SimpleIdentityMap .Empty
505- val prev = sourceCtx(source)
506- if (prev != null ) prev
507- else {
508- val newCtx = fresh.setSource(source)
509- if (newCtx.compilationUnit == null )
510- // `source` might correspond to a file not necessarily
511- // in the current project (e.g. when inlining library code),
512- // so set `mustExist` to false.
513- newCtx.setCompilationUnit(CompilationUnit (source, mustExist = false ))
514- sourceCtx = sourceCtx.updated(source, newCtx)
515- newCtx
516- }
517- }
518-
519511 final def withProperty [T ](key : Key [T ], value : Option [T ]): Context =
520512 if (property(key) == value) this
521513 else value match {
@@ -734,6 +726,7 @@ object Contexts {
734726 result
735727
736728 inline def comparing [T ](inline op : TypeComparer => T )(using Context ): T =
729+ util.Stats .record(" comparing" )
737730 val saved = ctx.base.comparersInUse
738731 try op(comparer)
739732 finally ctx.base.comparersInUse = saved
0 commit comments