As far as Typer specifically, I tried to keep it object safe for precisely that reason, but ran into other issues (I unfortunately don’t recall what they precisely were now, but I’m sure you will find it quickly if you start messing around with it
). I think arielb1 presented a good way forward long term with Typer (and actually, part of the reason I started working on trans next was because it’s one of the biggest non-typeck consumers of Typer, if not the biggest).
If you’re looking or specific things that would make refactoring like this easier in the future, the single biggest is of course nonlexical lifetimes, but this isn’t news to anyone
). Being able to skip writing out all the lifetime parameters when you really just need to specify one of them would also help ergonomics a lot, as well as the “group” thing I mentioned.
I actually LIKE the current compiler structure where things are written in distinct phases and passes. Probably we need clearer documentation, but I think in the end pass-oriented structure is easier to reason about than when things occur in a lazy order (the usual alternative). It’s also more parallel friendly (maps to fork-join in a trivial way, whereas laziness requires a kind of micro-task-graph). I’ve certainly found when reading other compilers that those which use a more lazy scheme can be harder to understand, because the control-flow is very data-dependent, versus those that use a series of passes are relatively easy to diagram and describe.
Hopefully, I conveyed in my post that I don’t think it’s bad to do things in phases, exactly. What I was getting at was that it feels extremely difficult to make alterations to the high level structure of the compiler (e.g. changing order of phases) because the contracts are relatively fragile, affect tons of code, and aren’t compiler-checked. Obviously, it’s a fairly large project and it’s never going to be easy to make sweeping changes, but more flexibility can’t be a bad thing, surely!
My only concern with the ivars was that we’re paying a runtime cost for the privilege, and this time one not required for memory safety. But the cost isn’t all that high and it’s not like the compiler is exactly microoptimized anyway, so adding something that will help us catch bugs can only be a good thing, I suppose. I do feel like it should be possible to do in a way that you don’t usually have to pay the cost, though: e.g., once you’re done with pass x, go double check to make sure all values you’re expecting to be set are set, and then turn them from Cell<Option<T>> into just T as a “type” transformation that only takes place at compile time (this is easier without the Option, and easier still if when the types are modifiable you have &mut references, since you can just shuttle your reference off to live behind something immutable whenever you want to freeze them, which lets you do a whole bunch of them at a time; BTW, am I wrong in thinking that if you have &mut Cell<T> you should be allowed to take direct references into its inner value?)). Anyway… like you said, extending Cell's functionality is really a separate discussion.