@@ -757,95 +757,102 @@ object Denotations {
757
757
* is brought forward to be valid in the new runId. Otherwise
758
758
* the symbol is stale, which constitutes an internal error.
759
759
*/
760
- def current (using Context ): SingleDenotation = {
760
+ def current (using Context ): SingleDenotation =
761
+ util.Stats .record(" current" )
761
762
val currentPeriod = ctx.period
762
763
val valid = myValidFor
763
- if (valid.code <= 0 ) {
764
- // can happen if we sit on a stale denotation which has been replaced
765
- // wholesale by an installAfter; in this case, proceed to the next
766
- // denotation and try again.
767
- val nxt = nextDefined
768
- if (nxt.validFor != Nowhere ) return nxt
769
- assert(false , this )
770
- }
771
764
772
- if (valid.runId != currentPeriod.runId)
773
- if (exists) initial.bringForward().current
774
- else this
775
- else {
765
+ def signalError () = println(s " error while transforming $this" )
766
+
767
+ def assertNotPackage (d : SingleDenotation , transformer : DenotTransformer ) = d match
768
+ case d : ClassDenotation =>
769
+ assert(! d.is(Package ), s " illegal transformation of package denotation by transformer $transformer" )
770
+ case _ =>
771
+
772
+ def escapeToNext = nextDefined.ensuring(_.validFor != Nowhere )
773
+
774
+ def toNewRun =
775
+ util.Stats .record(" current.bringForward" )
776
+ if exists then initial.bringForward().current else this
777
+
778
+ def goForward =
776
779
var cur = this
777
- if (currentPeriod.code > valid.code) {
778
- // search for containing period as long as nextInRun increases.
779
- var next = nextInRun
780
- while (next.validFor.code > valid.code && ! (next.validFor contains currentPeriod)) {
781
- cur = next
782
- next = next.nextInRun
783
- }
784
- if (next.validFor.code > valid.code) {
785
- // in this case, next.validFor contains currentPeriod
786
- cur = next
787
- cur
788
- }
789
- else {
790
- // println(s"might need new denot for $cur, valid for ${cur.validFor} at $currentPeriod")
791
- // not found, cur points to highest existing variant
792
- val nextTransformerId = ctx.base.nextDenotTransformerId(cur.validFor.lastPhaseId)
793
- if (currentPeriod.lastPhaseId <= nextTransformerId)
794
- cur.validFor = Period (currentPeriod.runId, cur.validFor.firstPhaseId, nextTransformerId)
795
- else {
796
- var startPid = nextTransformerId + 1
797
- val transformer = ctx.base.denotTransformers(nextTransformerId)
798
- // println(s"transforming $this with $transformer")
799
- try
800
- util.Stats .record(" denot transform" )
801
- next = ctx.evalAt(transformer)(transformer.transform(cur))
802
- // We temporarily update the context with the new phase instead of creating a
803
- // new one. This is done for performance. We cut down on about 30% of context
804
- // creations that way, and also avoid phase caches in contexts to get large.
805
- // To work correctly, we need to demand that the context with the new phase
806
- // is not retained in the result.
807
- catch {
808
- case ex : CyclicReference =>
809
- println(s " error while transforming $this" ) // DEBUG
810
- throw ex
811
- }
812
- if (next eq cur)
813
- startPid = cur.validFor.firstPhaseId
814
- else {
815
- next match {
816
- case next : ClassDenotation =>
817
- assert(! next.is(Package ), s " illegal transformation of package denotation by transformer $transformer" )
818
- case _ =>
819
- }
820
- next.insertAfter(cur)
821
- cur = next
822
- }
823
- cur.validFor = Period (currentPeriod.runId, startPid, transformer.lastPhaseId)
824
- // printPeriods(cur)
825
- // println(s"new denot: $cur, valid for ${cur.validFor}")
826
- }
827
- cur.current // multiple transformations could be required
828
- }
829
- }
830
- else {
831
- // currentPeriod < end of valid; in this case a version must exist
832
- // but to be defensive we check for infinite loop anyway
833
- var cnt = 0
834
- while (! (cur.validFor contains currentPeriod)) {
835
- // println(s"searching: $cur at $currentPeriod, valid for ${cur.validFor}")
836
- cur = cur.nextInRun
837
- // Note: One might be tempted to add a `prev` field to get to the new denotation
838
- // more directly here. I tried that, but it degrades rather than improves
839
- // performance: Test setup: Compile everything in dotc and immediate subdirectories
840
- // 10 times. Best out of 10: 18154ms with `prev` field, 17777ms without.
841
- cnt += 1
842
- if (cnt > MaxPossiblePhaseId )
843
- return atPhase(coveredInterval.firstPhaseId)(current)
844
- }
780
+ // search for containing period as long as nextInRun increases.
781
+ var next = nextInRun
782
+ while next.validFor.code > valid.code && ! (next.validFor contains currentPeriod) do
783
+ cur = next
784
+ next = next.nextInRun
785
+ if next.validFor.code > valid.code then
786
+ // in this case, next.validFor contains currentPeriod
787
+ cur = next
845
788
cur
846
- }
847
- }
848
- }
789
+ else
790
+ // println(s"might need new denot for $cur, valid for ${cur.validFor} at $currentPeriod")
791
+ // not found, cur points to highest existing variant
792
+ val nextTransformerId = ctx.base.nextDenotTransformerId(cur.validFor.lastPhaseId)
793
+ if (currentPeriod.lastPhaseId <= nextTransformerId)
794
+ cur.validFor = Period (currentPeriod.runId, cur.validFor.firstPhaseId, nextTransformerId)
795
+ else
796
+ var startPid = nextTransformerId + 1
797
+ val transformer = ctx.base.denotTransformers(nextTransformerId)
798
+ // println(s"transforming $this with $transformer")
799
+ val savedPeriod = ctx.period
800
+ val mutCtx = ctx.asInstanceOf [FreshContext ]
801
+ try
802
+ mutCtx.setPhase(transformer)
803
+ next = transformer.transform(cur)
804
+ // We temporarily update the context with the new phase instead of creating a
805
+ // new one. This is done for performance. We cut down on about 30% of context
806
+ // creations that way, and also avoid phase caches in contexts to get large.
807
+ // To work correctly, we need to demand that the context with the new phase
808
+ // is not retained in the result.
809
+ catch case ex : CyclicReference =>
810
+ signalError()
811
+ throw ex
812
+ finally
813
+ mutCtx.setPeriod(savedPeriod)
814
+ if next eq cur then
815
+ startPid = cur.validFor.firstPhaseId
816
+ else
817
+ assertNotPackage(next, transformer)
818
+ next.insertAfter(cur)
819
+ cur = next
820
+ cur.validFor = Period (currentPeriod.runId, startPid, transformer.lastPhaseId)
821
+ // printPeriods(cur)
822
+ // println(s"new denot: $cur, valid for ${cur.validFor}")
823
+ cur.current // multiple transformations could be required
824
+ end goForward
825
+
826
+ def goBack : SingleDenotation =
827
+ // currentPeriod < end of valid; in this case a version must exist
828
+ // but to be defensive we check for infinite loop anyway
829
+ var cur = this
830
+ var cnt = 0
831
+ while ! (cur.validFor contains currentPeriod) do
832
+ // println(s"searching: $cur at $currentPeriod, valid for ${cur.validFor}")
833
+ cur = cur.nextInRun
834
+ // Note: One might be tempted to add a `prev` field to get to the new denotation
835
+ // more directly here. I tried that, but it degrades rather than improves
836
+ // performance: Test setup: Compile everything in dotc and immediate subdirectories
837
+ // 10 times. Best out of 10: 18154ms with `prev` field, 17777ms without.
838
+ cnt += 1
839
+ if cnt > MaxPossiblePhaseId then
840
+ return atPhase(coveredInterval.firstPhaseId)(current)
841
+ cur
842
+ end goBack
843
+
844
+ if valid.code <= 0 then
845
+ // can happen if we sit on a stale denotation which has been replaced
846
+ // wholesale by an installAfter; in this case, proceed to the next
847
+ // denotation and try again.
848
+ escapeToNext
849
+ else if valid.runId != currentPeriod.runId then
850
+ toNewRun
851
+ else if currentPeriod.code > valid.code then
852
+ goForward
853
+ else
854
+ goBack
855
+ end current
849
856
850
857
private def demandOutsideDefinedMsg (using Context ): String =
851
858
s " demanding denotation of $this at phase ${ctx.phase}( ${ctx.phaseId}) outside defined interval: defined periods are ${definedPeriodsString}"
@@ -900,7 +907,7 @@ object Denotations {
900
907
901
908
/** Insert this denotation instead of `old`.
902
909
* Also ensure that `old` refers with `nextInRun` to this denotation
903
- * and set its `validFor` field to `NoWhere `. This is necessary so that
910
+ * and set its `validFor` field to `Nowhere `. This is necessary so that
904
911
* references to the old denotation can be brought forward via `current`
905
912
* to a valid denotation.
906
913
*
0 commit comments