| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
| |
One new issue: the traces for all tests are perturbed by the .mu files we
choose to load.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
And it caught a bug: I mean to always update type names and types in
sync.
The last month or so I've been getting reluctantly but inexorably
converted to the need and value of a type system. First I thought I just
need a minimal but rigorous type system to avoid memory corruption and
security issues. Now I think I also want it to be expressive enough to
be able to express what data different phases in a compiler read and
write, and to be able to designate specific fields as 'fully computed'
so that we can statically check that phases wait until their data is
available.
The phase-ordering problem in a compiler is perhaps the canary in the
coal-mine for a more general problem: even small changes can
dramatically explode the state space if they violate assumptions
previously held about the domain. My understanding of when type pointers
are null and not null is immeasurably more nuanced today than it was a
week ago, but I didn't need the nuance until I introduced generic
functions. That initial draft of a hundred lines bumped me up to a much
larger state space. How to make it more obvious when something happens
that is akin to discovering a new continent, or finding oneself
teleported to Jupiter?
Assumptions can be implicit or explicit. Perhaps a delete of an
assertion should be estimated at 1000 LoC of complexity?
|
|
|
|
|
|
|
| |
Is that like a Maybe type in a type system? No it's more, it captures
the wistful longing of several hours spent trying to make an assertion
true. Not even by moving my phases relating to the types around could I
make this assertion true.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
I tried to not populate the type at an early stage, and to pull out the
type computations for all reagents into a separate transform grouped
with but before the other type deduction transforms. But it seemed less
readable to not mention types at all in layer 10. So we'll stick with
our current approach, but try to be disciplined about grouping all the
type transforms together, so that we can reason about whether a pass
belongs before or after type deduction. (Doesn't seem rigorous enough
for the name 'type inference'.) In particular, static dispatch and
specialization of generics (resolve_ambiguous_calls) needs to happen
after all type inference has completed, so that the only missing types
are the generic type ingredients.
In general I've been living in constant fear of the phase-ordering
problem. No matter how many tests I write, I can't be sure that there
isn't some corner case where my phases will be proven to be in a
sub-optimal ordering. When I build the mu compiler in mu I'll want to
also use the ability to perform static analyses in mu programs using mu
userland capabilities. That would allow me to be sure that no phase
writes to some field of reagent after some other purely checking phase
reads it. Then all you have to do is be disciplined about not doing
checking in mutating phases (which we currently aren't; hello
check_or_set_invalid_types).
Hmm, but I think this line of thought gives me some confidence now that
I'm ok so far. The only field of reagents being modified after
parsing/initialization is the type. So all I care about is whether each
transform happens before or after all types are available. If I later
start writing other fields or properties then I'll need to perform
similar analysis for them, and it might get complicated enough to need a
state diagram where partially filled out properties inhabit separate
states from completely inferred properties.
|
| |
|
| |
|
| |
|
|
|
|
|
| |
Fix that stray issue with a better phase ordering.
Another thing I'm not testing.
|
|
|
|
|
|
|
|
|
|
|
| |
Still some spurious warnings.
This was an insane experience building out generics. Time to reflect.
Where did I go wrong? How did I end up writing no tests? Let's take some
time and go over the last 50 commits with a fine-tooth comb.
Generics seems to be the feature that has moved mu from a VM project to
a compiler project.
|
| |
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Got that idea to work with a special-case for 'new'. Requires parsing
new's first ingredient, performing the replacement, and then turning it
back into a string. I didn't want to replace NEW with ALLOCATE right
here, because then it messes with my invariant that transform should
never see a naked ALLOCATE.
Layer 11 still not working, but everything else is. Let's clean up
before we diagnose the new breakage.
|
|
|
|
| |
Yup, type ingredients were taking size 1 by default.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
No, my idea was abortive. My new plan was to run no transforms for
generic recipes, and instead only run them on concrete specializations
as they're created.
The trouble with this approach is that new contains a type specification
in its ingredient which apparently needed to be transformed into an
allocate before specialization.
But no, how was that working? How was new computing size based on type
ingredients? It might have been wrong all along.
|
|
|
|
| |
Ooh, I think I see a solution.
|
|
|
|
|
|
|
|
| |
Now we're back to trying to rerunning idempotent transforms on
specialized recipes. Still doesn't work, but at least we don't see
different results depending on whether the trace is enabled inside the
test or right at the start. That got fixed by the more disciplined
insertion into maps, looks like.
|
| |
|
| |
|
|
|
|
| |
Layer 1 of edit/ is introducing spurious types, though.
|
| |
|
| |
|
|
|
|
|
| |
I'd not paid any attention to it so far, but I need to do so from now
on.
|
|
|
|
| |
Starting to leave commented out prints again out of desperation.
|
| |
|
|
|
|
|
|
|
|
| |
New assertions still failing during tests.
This whole implementation of generic recipes is like an extended spike.
I don't have nearly enough tests. Ideally I'd have confidence in
generics once layer 59 passed its tests.
|
|
|
|
|
|
|
| |
Commands run:
$ sed -i 's/\([^. (]*\)\.find(\([^)]*\)) != [^.]*\.end()/contains_key(\1, \2)/g' 0[^0]*cc
$ sed -i 's/\([^. (]*\)\.find(\([^)]*\)) == [^.]*\.end()/!contains_key(\1, \2)/g' 0[^0]*cc
|
|
|
|
|
|
| |
Now we're starting to run up against the misbehavior introduced by
generics: Type tries to insert rows for type ingredients. That is a
no-no.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
I'm still seeing all sorts of failures in turning on layer 11 of edit/,
so I'm backing away and nailing down every culprit I run into. First up:
stop accidentally inserting empty objects into maps during lookups.
Commands run:
$ sed -i 's/\(Recipe_ordinal\|Recipe\|Type_ordinal\|Type\|Memory\)\[\([^]]*\)\] = \(.*\);/put(\1, \2, \3);/' 0[1-9]*
$ vi 075scenario_console.cc # manually fix up Memory[Memory[CONSOLE]]
$ sed -i 's/\(Memory\)\[\([^]]*\)\]/get_or_insert(\1, \2)/' 0[1-9]*
$ sed -i 's/\(Recipe_ordinal\|Type_ordinal\)\[\([^]]*\)\]/get(\1, \2)/' 0[1-9]*
$ sed -i 's/\(Recipe\|Type\)\[\([^]]*\)\]/get(\1, \2)/' 0[1-9]*
Now mu dies pretty quickly because of all the places I try to lookup a
missing value.
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
One nice consequence of all my deduction of reply ingredients is that I
can insert the same fragment into recipes with different headers, and
everything works as long as reply instructions are implicitly deduced.
One thing I had to fix to make this work was to move reply-deduction out
of rewrite rules and turn it into a first-class transform, so that it
happens after tangling.
I'm glad to see the back of that hack inside <scroll-down>.
|
| |
|
|
|
|
|
| |
Still seeing repeated null refinements. Maybe my approach to fixing
those errors is fundamentally broken.
|
| |
|
|
|
|
|
| |
Not only can such recipes not have variants, their bodies too will be
oblivious to multiple variants or generics.
|
| |
|
| |
|
|
|
|
| |
It wasn't a phase-ordering issue after all..
|
|
|
|
|
|
| |
Now we try to be smarter about checking for presence in the Type array.
Still can't get generic duplex-list to work.
|
| |
|
|
|
|
|
|
|
|
|
| |
More flailing around trying to come up with the right phase ordering.
I've tried to narrow down each transform's constraints wrt transforms in
previous layers.
One issue that keeps biting me is the Type map containing empty records
because of stray [] operations. That's gotta be important.
|
| |
|
|
|
|
|
|
|
| |
A new externality is starting to make its presence felt.
Until I sort this out it's going to be hard to finish making duplex-list
generic.
|