The 09-13 handoff says it is a snapshot, and two settled questions stop reading as open

NEXT.md prepends, so its second section still opened with "Read this first" while
pinning a tree six lanes behind and listing as live a queue most of which has
landed. It keeps its contents; what it gains is the sentence saying when it
stopped being where the tree is, and the survey count it quotes measured again on
this tree -- 103 MATCH, 0 DIFFER, 38 skipped.

The two generics entries get the file's own strikethrough treatment, which their
siblings already had: the {K V} catch resolved exactly as it predicted it would,
and there are five predicates rather than four.

Also here: conditions.org gains ArithError beside BoundsError, with the split
between the two runtime conditions that offer retry and the two that deliberately
offer nothing; and tast.ml's header stops naming a tree-walking interpreter among
the backends that consume the typed IR.
This commit is contained in:
Joseph Ferano 2026-09-14 07:34:02 +07:00
parent 0aebef62f3
commit dcba88ffd6
3 changed files with 34 additions and 10 deletions

24
NEXT.md
View File

@ -18,8 +18,17 @@ IEEE already answers it.
# Where this is — end of 2026-09-13, second handoff
**This section is the record of that evening and is no longer where the tree is.** It is kept because the
reasoning in it is still the reasoning, but read the section above this one first, and take the state below
as a snapshot: it pins `dev-loop` at `e725a5a`, and since then the arithmetic-condition lane, the
redefinition emitter, the aggregate case across the reload boundary, the two unreached guards, DWARF for
`--x86`, the cost measurements, the last two raylib ports and the `dune test` noise have all landed. The
x86 survey it quotes at 97 now reports **103 MATCH, 0 DIFFER, 0 refused by name, 38 skipped**, and of the
seven remaining items it lists from `HANDOFF-x86-rt.md`, items 1, 3, 4, 5, 6 and 7 are done — each has a
`HANDOFF-x86-*.md` of its own.
**Branch `dev-loop` at `e725a5a`, working tree clean, `dune test` green, every lane merged.**
Nothing is running and nothing is half-built. Read this first.
Nothing is running and nothing is half-built.
## The x86 backend is correct, and is not yet the dev backend
@ -466,13 +475,14 @@ clause tells the abstract pass what it may assume, so the body checks at the def
- The clause is written as a **Clojure-style map at the head of the body**, `{:where (ordered? $t)}`, chosen by
the author over a bare keyword. It disambiguates because a bare `{}` in expression position is already refused
(`parse.ml:110`), so a `{}` there can be nothing else, and Clojure's `{:pre [...] :post [...]}` is the
precedent. It leaves room for further keys without new syntax. **One catch to settle first:** `{K V}` is
precedent. It leaves room for further keys without new syntax. ~~**One catch to settle first:** `{K V}` is
currently a legal return type, so `(defn f [...] {string i32} {:where ...} body)` puts two braces in a row
meaning different things. That resolves itself if `{K V}` goes in favour of `(Map K V)`, which is a separate
open question in this file.
- A `where` clause over **compile-time type predicates** admits the operators the body needs. Four are wanted —
`ordered?`, `equal?`, `hashable?`, `numeric?` — against Odin's forty-one. The prelude's nine non-collapsing
functions need only the first two.
meaning different things.~~ — resolved the way this predicted: `{K V}` went in favour of `(Map K V)`,
braces in type position are refused by name, and the two-braces-in-a-row case cannot arise.
- A `where` clause over **compile-time type predicates** admits the operators the body needs. ~~Four are
wanted — `ordered?`, `equal?`, `hashable?`, `numeric?`~~ — against Odin's forty-one. Five landed: `copyable?`
is the fifth, and it has no Odin counterpart because a `$T` there never has to answer whether it moves. The
prelude's nine non-collapsing functions need only the first two.
- Each instantiation checks the concrete type satisfies the predicates and refuses **that call site** if not.
**This is not a type class, and the distinction is the one to keep straight.** A type class carries

View File

@ -102,6 +102,19 @@ the agent's socket instead.
~BoundsError~ rather than ending the process, abandoning a frame and retrying
it is a real thing to do, and a non-idempotent mutation is what makes it go
wrong.
- *Four conditions come from below your program*, all with ~error~:
~StorageExhausted~ when an allocator cannot satisfy a request, ~FileError~
when a file operation fails, ~BoundsError~ for an index or slice outside its
container, and ~ArithError~ for arithmetic with no answer — a divide or
remainder by zero, ~INT64_MIN / -1~, and a float-to-integer cast that does not
fit, each of which used to be a bare ~SIGFPE~ with no message and no location.
The first two offer a ~retry~ at the failing site, because freeing something
or supplying another path makes the same operation succeed. The last two offer
*nothing*: no handler makes index 51 valid for a length-50 array or gives a
division by zero a quotient, so there is nothing to resume into. The restart
that answers those is the one your program already established — the frame
loop's ~continue~ — and it is on the stack and reachable without anything
being pushed at the failure.
- *An unknown restart name is a hard stop.* No ~find-restart~ to test with.
- *So are the wrong arguments*, and for the same reason: nothing static can
know what a name will find. The message names both signatures.

View File

@ -1,8 +1,9 @@
(** The typed IR: what the checker produces and what every backend consumes.
Three backends share this the tree-walking interpreter, dev redefinition
and the release AOT build (plan.org, Compilation) so everything a backend
would otherwise have to re-derive is resolved here and nowhere else:
Every backend shares this the LLVM emitter and the hand-written x86-64
one, each of them under dev redefinition and under the release AOT build
(plan.org, Compilation) so everything a backend would otherwise have to
re-derive is resolved here and nowhere else:
- names are gone. A local is a slot index into the frame, a global is a
name, and a call names its callee directly. No environment lookup.