Open nomeata opened 2 years ago
Did a quick experiment to see to what extend DefineE x e
and x := e
do the same thing, at least when the type is mutable:
-let define_idE x mut exp1 =
- { it = DefineE (x, mut, exp1);
- at = no_region;
- note = Note.{ def with typ = T.unit }
- }
+let define_idE (x,t) mut exp1 = match mut with
+ | Const ->
+ { it = DefineE (x, mut, exp1);
+ at = no_region;
+ note = Note.{ def with typ = T.unit }
+ }
+ | Var -> assignE (x,T.Mut t) exp1
but that didn’t quite work. This may need more thought.
I think I'm for it, even at the source level to be honest. I've always missed the ML ref type.
I'll have to think about/revist declareE and defineE but I think it's essentially allocating an uninitialised ref and then initialising it, without a definedness check on read. We needed it to be able to await within recursive blocks, IIRC.
I think the problem with declare and define here is that they don't just allocate refs, but also non-refs?
But maybe it's fine to turn them all into proper refs (including changing the type) in the lowering pass?
The PR at #3084 shows that the handling of mutable variables and mutable fields on the IR level is lacking. Instead of increasing the complexity, I think we can actually simplify the existing code and trivially unblock the features needed for #3084 (i.e. without any IR changes there).
The plan would be roughly this:
mut t
as its own first-class type. This applies to mutable variables (var x
) and object fields ({var x : t}
), but not the elements of mutable arrays. No moreas_immut
in `Check_IR!NewE : exp -> exp
with typet -> mut t
;ReadE : exp -> exp
with typemut t -> t
andWriteLE : exp -> lexp
for the left of an assignments. It is backed via aMutBox
, just as it is now.VarD x e
can go. It now simply becomesLetD x (NewE e)
.LodLE e n
can go. We can useWriteLE (DotE e n)
mut
anywhere! Much simplification here, and unblocking #3084.VarE
, has to check the type and if it is mutable, insert aReadE
.Two things are not clear to me:
What about
DeclareE
andDefineE
? Can they be replaced byNewUndefinedE : exp
andReadE : exp -> exp
, working on theseMutBoxes
directly? @crusso might know.In
module AllocHow
we notice when a mutable variable is never captured, and then just use a wasm local. Can we recover this optimization here as well?It seems we might need a separate API
NewLocalE
,ReadLocalE
andWriteLocalLE
(or a flag on these), do a control flow analysis to see if the mutbox is ever used in a first-class way (captured, written to a record). Maybe it is good enough to match on cases ofLetD x (NewLocalE e)
, and then check howx
is used, quite similar to what we do right now. But even then we have to treatReadE (VarE x)
differently from other, higher-order uses ofVarE x
. Hmm.