What I especially like about this is getting the infrastructure needed to implement copying GC in early. This is really important to add at the beginning. It's very costly to add it later once you have an entire production-quality engine built on top of non-moving or conservative GC.
(In fact I only know of one project that successfully made the transition from conservative to precise moving GC after many years of deployment: SpiderMonkey.)
Aside from the difficulty of changing, can you give a couple of sentences on the pros/cons?
Are "moving GCs" mostly good for reducing fragmentation? I guess you'd get fewer annoying "holes" if you can compact memory, and better cache behaviour if live objects tend to be nearer to each other.
For a simple baseline JIT like that, you can improve the quality of the generated code a lot at basically no compile-time cost (still one pass) by doing some flavor of "destination driven code generation".
It also adds very little complexity to the compiler itself so it's a nice win.
I introduced myself to Rust by writing a compiler. It was a real trial-by-fire thanks to how tree structures have to be handled with the borrow checker.
> It was a real trial-by-fire thanks to how tree structures have to be handled with the borrow checker.
Eh, without parent-pointers you can just use a Box<T> in the obvious way. For more elaborate graphs you'd use arena allocation. Maybe not something a beginner would realize, but it's not that hard
(In fact I only know of one project that successfully made the transition from conservative to precise moving GC after many years of deployment: SpiderMonkey.)