@@ -655,8 +655,7 @@ object Denotations {
655
655
next.resetFlag(Frozen )
656
656
case _ =>
657
657
}
658
- next.nextInRun = cur.nextInRun
659
- cur.nextInRun = next
658
+ next.insertAfter(cur)
660
659
cur = next
661
660
}
662
661
cur.validFor = Period (currentPeriod.runId, startPid, transformer.lastPhaseId)
@@ -672,6 +671,10 @@ object Denotations {
672
671
while (! (cur.validFor contains currentPeriod)) {
673
672
// println(s"searching: $cur at $currentPeriod, valid for ${cur.validFor}")
674
673
cur = cur.nextInRun
674
+ // Note: One might be tempted to add a `prev` field to get to the new denotation
675
+ // more directly here. I tried that, but it degrades rather than improves
676
+ // performance: Test setup: Compile everything in dotc and immediate subdirectories
677
+ // 10 times. Best out of 10: 18154ms with `prev` field, 17777ms without.
675
678
cnt += 1
676
679
if (cnt > MaxPossiblePhaseId ) return NotDefinedHereDenotation
677
680
}
@@ -708,12 +711,10 @@ object Denotations {
708
711
// printPeriods(current)
709
712
this .validFor = Period (ctx.runId, targetId, current.validFor.lastPhaseId)
710
713
if (current.validFor.firstPhaseId >= targetId)
711
- replaceDenotation (current)
714
+ insertInsteadOf (current)
712
715
else {
713
- // insert this denotation after current
714
716
current.validFor = Period (ctx.runId, current.validFor.firstPhaseId, targetId - 1 )
715
- this .nextInRun = current.nextInRun
716
- current.nextInRun = this
717
+ insertAfter(current)
717
718
}
718
719
// printPeriods(this)
719
720
}
@@ -731,19 +732,35 @@ object Denotations {
731
732
val current1 : SingleDenotation = f(current.asSymDenotation)
732
733
if (current1 ne current) {
733
734
current1.validFor = current.validFor
734
- current1.replaceDenotation (current)
735
+ current1.insertInsteadOf (current)
735
736
}
736
737
hasNext = current1.nextInRun.validFor.code > current1.validFor.code
737
738
current = current1.nextInRun
738
739
}
739
740
}
740
741
741
- private def replaceDenotation ( current : SingleDenotation ) : Unit = {
742
- var prev = current
743
- while (prev .nextInRun ne current) prev = prev.nextInRun
742
+ /** Insert this denotation so that it follows `prev`. */
743
+ private def insertAfter ( prev : SingleDenotation ) = {
744
+ this .nextInRun = prev.nextInRun
744
745
prev.nextInRun = this
745
- this .nextInRun = current.nextInRun
746
- current.validFor = Nowhere
746
+ }
747
+
748
+ /** Insert this denotation instead of `old`.
749
+ * Also ensure that `old` refers with `nextInRun` to this denotation
750
+ * and set its `validFor` field to `NoWhere`. This is necessary so that
751
+ * references to the old denotation can be brought forward via `current`
752
+ * to a valid denotation.
753
+ *
754
+ * The code to achieve this is subtle in that it works correctly
755
+ * whether the replaced denotation is the only one in its cycle or not.
756
+ */
757
+ private def insertInsteadOf (old : SingleDenotation ): Unit = {
758
+ var prev = old
759
+ while (prev.nextInRun ne old) prev = prev.nextInRun
760
+ // order of next two assignments is important!
761
+ prev.nextInRun = this
762
+ this .nextInRun = old.nextInRun
763
+ old.validFor = Nowhere
747
764
}
748
765
749
766
def staleSymbolError (implicit ctx : Context ) = {
0 commit comments