1260 Commits

Author SHA1 Message Date
f986c0728a A test binary names the signal that killed a daemon, and the break buffer keeps its keys under Evil 2026-09-25 07:40:58 +07:00
414e1e5ae6 The temp directory is left to the build-plumbing lane, and under Evil the break buffer takes only the keys it binds
The dead-session sweep and the remove-on-close half are dropped: the sweep contradicts the recorded non-goals, and the other lane owns removal on a clean close. The Evil keys are defined per state from the map's own bindings, so special-mode-map's h, SPC, < and - no longer shadow Evil's.
2026-09-25 07:40:33 +07:00
88584f76bc The records say what the tree does, and an arena grown in place answers to its budget 2026-09-25 07:39:11 +07:00
f83e803ef8 An aggregate that reads its own destination sees the old value on x86, as it does on LLVM 2026-09-25 07:39:03 +07:00
918edfb0b5 plan.org describes containers, pools and classes as they are after the repeal 2026-09-25 07:37:37 +07:00
cf71caefc2 spec-memory.md cites the defer_ok field on the line it is declared 2026-09-25 07:36:57 +07:00
cbd910c117 An arena's budget holds when a block grows in place, and a shrink is never over budget 2026-09-25 07:36:52 +07:00
52681ec58c Two gaps found on the way are on record: the half-write abort flake and the one-shot commands' empty work directory 2026-09-25 07:33:32 +07:00
cda939c8be Only a place has an address in the inspector, and a watched dyn value and string are pinned armed 2026-09-25 07:32:25 +07:00
7d75cc0a5d The CLI and the tests load, check and link a program through one module in the library 2026-09-25 07:30:55 +07:00
54ec52fde6 A dev session that ends cleanly takes its directories with it, and Build.executable says where the IR it kept is 2026-09-25 07:28:34 +07:00
377ada8d27 The inspector says where a slot's value is stored 2026-09-25 07:27:25 +07:00
5477c75909 Three of the four under-load and dogfooding entries are settled, and the fourth records what was tried 2026-09-25 07:24:20 +07:00
37ccca56a3 Every sweep reads the corpus through one alias, and a build that raises is a FAIL line in each of them
The sanitizer sweep also lists the five macro programs that run.
2026-09-25 07:23:12 +07:00
85b9f35a66 (watch "name" v) renders any value into the watch table the way print renders it 2026-09-25 07:22:59 +07:00
04f5d5a349 Under Evil, a digit in the break buffer takes the restart, because the buffer's keys take precedence over Evil's 2026-09-25 07:22:42 +07:00
2250548b07 A test that sees a process die on a signal names the signal, not OCaml's number for it
OCaml numbers the signals negatively and in its own order: SIGTERM is -11. The globals daemon's "transient signal 11" was a SIGTERM, not a segfault.
2026-09-25 07:21:44 +07:00
991e4423aa A dev session removes its build directory when it closes, and the next session sweeps the ones whose process is gone
Every daemon left about 8MB in $TMPDIR/flan-dev-<pid>. A test_dev run left 300MB, and a few concurrent runs filled the tmpfs /tmp, after which every daemon died on its link before binding. The half-write test's abort also goes through [aborted] now, since an abort that worked can arrive as the socket closing.
2026-09-25 07:19:52 +07:00
7b843f6753 TODO.org records what this lane settled and the one decision it left 2026-09-25 07:17:07 +07:00
f142cfaadf A u64 constant above 2^63 can be written in decimal, and a cast's integer literal too wide for i32 is read at the cast's type 2026-09-25 07:16:42 +07:00
aa5052e401 A dyn value an expression answers is the reply's value, not the program's output 2026-09-25 07:14:13 +07:00
aa629da2e5 vec-new and map-new take a type expression where they take a type, so (vec-new [u8]) makes a Vec of byte slices 2026-09-25 07:10:48 +07:00
cf028e23ea A class and each case of a data type are names on the definitions list 2026-09-25 07:09:46 +07:00
b4e19bebf8 A loop's initialisers are checked in order and each sees the names bound before it, as a let's do 2026-09-25 07:06:17 +07:00
8b354d4bc8 The notes say what is built: no pool, frames on x86, implicit widening, and the budget in the spec 2026-09-25 07:05:55 +07:00
9194f918fc An aggregate that reads its own destination sees the old value, on x86 too
x86 built a settling right-hand side straight into its destination, so (set p (P {.a (.b p) .b (.a p)})) wrote .a and read it back for .b. assign now also asks whether the value reads storage the destination lies in, and goes through the temporary when it does. The global-initialiser entry was already closed by startup_plan's Set; the unrooted-temporary entry turns out to be a both-backends rooting gap and stays open for a decision.
2026-09-25 07:05:18 +07:00
2e58880160 The break buffer hides the prelude's frames and opens the source behind a frame 2026-09-25 07:04:56 +07:00
3a3674efb7 A gensym is never the same name twice in one compiler process, however many macro modules it loads 2026-09-25 07:04:10 +07:00
9c0e659209 next-error stops on a diagnostic's notes, and CFn is drawn as a type 2026-09-25 07:01:48 +07:00
6b9d1fa644 A cast of NaN or an infinity to an integer says so by name, on both backends 2026-09-25 06:58:06 +07:00
5557594f31 What the dogfooding session turned up 2026-09-25 06:45:26 +07:00
9d7da2ba7a A stop takes the window, because the next key is aimed at it 2026-09-22 11:12:53 +07:00
45cc4d20e8 One file holds what five did
# Conflicts:
#	FIX.org
2026-09-21 21:07:40 +07:00
57fe91f303 Five records become one, and every citation lands somewhere
FIX.org, NEXT.md, DISCUSS.org, docs/DISCUSS.md and the session handoff at the
root are one TODO.org now: 293 entries under seven subsystem headings, each
carrying an org keyword that says where it stands. A DONE entry is a few lines
saying what was decided and what that rules out; the reasoning that would not
compress — the embedding spike and the four reports the hand-written x86
backend was built from — moved into docs/BUILT.md instead, and its entries
point there in one line.

Every entry was checked against the tree before it got a keyword, and the
prose was wrong in both directions. Things the deleted files called open were
built: the first-evaluation stall, main being redefinable, macro parameter
lists, the type-limit constants, the array constructors, the byte fills,
inc/dec, the discard's fontification, the Emacs buffers, rt_die's _exit, the
backtrace surface, and the acceptance failure that could print and still exit
zero. Things they called done were not: the backend reports' no-plan buckets
had gone stale in the other direction, the value-dependent defvar was
superseded rather than built, and macro-expansion source locations are on an
unmerged lane, so that entry is NEXT and names the branch.

Every comment that cited one of the five by name now cites a heading that
exists, in TODO.org or in docs/BUILT.md. The session reports under
docs/handoffs/ keep naming the files they worked on, because rewriting them
would falsify what those sessions did; each carries a note saying where the
content went.
2026-09-21 21:05:48 +07:00
91ba4a0743 The reference page says what the language is
# Conflicts:
#	FIX.org
2026-09-21 20:41:50 +07:00
594b4bae2e A macro call records a handful of forms, not sixty-four 2026-09-21 20:37:30 +07:00
cc90aa6655 An error in a macro-expanded body points at the line that was written 2026-09-21 19:58:18 +07:00
23e272a24f The reference page describes the language that exists, dyn and classes included 2026-09-21 19:34:08 +07:00
37d4e7b32b The standing rules go in the repository, and three dated reports leave it 2026-09-21 19:23:42 +07:00
Joseph Ferano
a14a872a44 A form a macro splices through is reported on the line it was written on 2026-09-21 19:16:45 +07:00
bcfcf130f7 The README says what the collector touches, and what a dyn is 2026-09-21 19:15:34 +07:00
612411021c The colour goes on the language, and the program is left plain 2026-09-21 19:06:16 +07:00
d9bb882bbe A dev build's main is reached through its cell like every other call
# Conflicts:
#	FIX.org
#	test/test_dev.ml
2026-09-21 18:29:02 +07:00
ca237adb22 A function that captures and a function that cannot are two types
# Conflicts:
#	FIX.org
2026-09-21 16:17:10 +07:00
f2c20e2a4a The editor learns the language again, and then learns the program 2026-09-21 16:07:09 +07:00
2d1d88e9d1 A macro has a body, and the entry that said otherwise
Review follow-ups on the mode pass.

The regression first, because it is the one that cost something: giving
macros a kind of their own took them out of three completion tables.
flan-disassemble, flan-disassemble-ir and flan-lowering each filtered
flan--defs on kind "fn", which had been the whole truth right up until
this branch made it half of one. A macro is compiled -- defmacro is a
defn by the time anything emits code -- so all three genuinely work on
one, and only the offer had gone. One flan--compiled-kinds names both
words and the three sites read it.

Then four sentences in the FIX.org entry that were not true, which
matters more than it sounds: that file is the history somebody reads
later to find out what happened.

The corpus claim was the bad one. It said the whole corpus round-trips
with zero differing lines. It does not, and never did -- the script that
measured it bound inhibit-message around its own reporting, which in
batch means the differences were found and then swallowed. Measured
properly: 317 files, 22 files and 389 lines differing before, 20 and 373
after. Sixteen lines fixed in two files, no new difference introduced,
and 373 lines still differing that this pass never looked at.

The other three: the fns/macros dedup is required by the new rows and is
not a fix to a bug that was there before -- a macro used to appear once,
as a fn. handler-case was already a keyword. loops.flan has three
labelled loops and dotimes-range.flan has the other two.

And three gaps the review found while checking: array-fill and array-gen
were never in the keyword list, Unit was in the type rule while the
parser refuses the word, and a prelude macro's row carried a bare name
where a program's carried its parameters. A check that pulls every head
out of parse.ml and diffs it against the three lists now comes back
empty, which is what the docstring had started claiming.
2026-09-21 16:00:49 +07:00
0c711942f7 A thunk named for the order it was minted in is a different signature after a reorder
Three from a review of the commit before this one, and the first is a dev
loop defect.  Naming the widening thunk thick/<count so far> put traversal
order into a symbol, and Session.compatible compares a reload's functions
against the running program's by name -- so swapping two calls in a body
renamed nothing the programmer can see and reported "thick/0 changes
signature, from [i32] i32 to [i64] i64.  Restart to change it."  The name is
the signature again, written by thick_enc: every type self-delimiting, an
atom as its length and then its spelling, so the boundaries mangle_ty loses
are in the string rather than inferred from the separators.  mangle_ty is
untouched -- it is load-bearing for the instantiation names a backtrace, a
Reach edge and a dev cell show -- and the memo stays keyed on the types.
fn-thunk-reload.flan is the pair of widenings and test_session reorders them.

The second was a silent miscompile.  bind_ty's Fn-pattern-against-CFn-argument
arm was structural, so it matched nested function positions too, and the
catch-up pass that builds the thunk compares the whole substituted parameter
list -- false when the mismatch is inside one, and the fallthrough handed the
argument over unchanged: one word where the instance declares two, 255 on
both backends with nothing said anywhere.  The widening is a value the caller
builds around the whole argument and there is nowhere inside one to build it,
so the arm is admitted at the top of an argument's type and nowhere else, and
the catch-up arm is total over the pair rather than guarded -- bind_ty's
fallthrough is Types.fits, which admits Never, so a binding can still succeed
over a pair the two words cannot bridge.  fn-generic-nested.flan is the
parameter position and fn-generic-nested-return.flan the return one.

And the third closes the hole the escaping inversion was for.  A match arm
binds the case's fields to slots and the store that fills them is inside the
branch, not in any form escape_check reads as a binding, so (match o (Some f)
f ...) handed back through a name what a case-field read cannot hand back at
all -- sound only because Some_ denies suspects.  An arm's slots of function
type are suspect now, for the same reason the read itself is.
2026-09-21 15:44:28 +07:00
2ba6a6cbf0 One list for the parser, one for the checker, and one the program fills
flan--special was three kinds of name in one list: the forms the parser
dispatches on, the functions the compiler provides, and the words that
stand for themselves. Drawing push like let said they were the same kind
of thing. They are three lists now, each read off the file that decides
it, and the two names in the old one that are not in the language at all
-- cast and none -- are gone with it.

What else had been missed: dyn, Allocator, Vec, Map, Fn, int and float
were not types, $t was not anything, handler-case was not a keyword, a
comma was not whitespace, & was not a name character -- which a macro's
parameter list needs, now that it destructures -- imenu had no heading
for a macro and none for the four dispatch forms, and a labelled loop
indented its body under its own binding vector, which loops.flan has
four of and would have said.

Then the second half. The defs op already told the editor what every
name is, and only completion and eldoc were listening, so a macro you
defined looked exactly like a function you defined. It carried no macro
kind to listen for and could not have: a macro is a defn by the time
there is a program. So the op answers with one -- keeping the location
off the defn it drops, so M-. still goes there -- and with the type
names, read off the checker's environment, since an enum is an i32 and
an alias is gone by then.

The editor draws them by kind, after the static rules and never over
them: a program defining its own length does not get to repaint the
builtin. A hash table and a matcher rather than a regexp of every name,
rebuilt when the cache is and not when a key is pressed. With no session
the rules come off and the buffer is what it always was.
2026-09-21 15:31:32 +07:00
a28aeda633 The thunk memo was keyed on a name that two signatures can share
Review found it, and it is a silent miscompile on both backends rather
than a refusal anywhere.  mangle_ty flattens a whole signature into one
hyphen-joined string, so (CFn [(Ptr i32)] i32) and (CFn [ptr i32] i32) --
the second over a struct someone called ptr -- flatten alike; keyed on
that, the second widening reused the first's thunk at the wrong arity.
The key is the types now, compared with Types.equal, and the symbol is a
counter over the thunks already minted, so nothing is derived from a
spelling.  fn-thunk-share.flan is the pair, and it prints 5 and 17.

And a regression beside it: a generic whose function parameter binds the
type variable.  (defn apply2 [f (Fn [$t] $t) x $t] ...) called as
(apply2 bump 1) compiled before this lane and stopped, because bind_ty
had no arm admitting a CFn argument at an Fn pattern -- and once it had
one, the call still handed one word to an instance declaring two, because
a parameter that still mentions a variable is checked with no expectation
and expect never sees the pair.  Both halves: the arm, and the widening
in generic_call's catch-up pass beside the numeric one.  The same gap hid
new functionality -- a CFn argument at a (CFn [$t] $t) parameter had no
arm either -- and mentions had no CFn case, so bound_exactly answered
wrong for a variable living only inside one.

The corpus missed all of it because the prelude binds $t from an earlier
argument, so the parameter is concrete before bind_ty sees it.

While here: escaping's enumeration is the *clean* set now rather than the
suspect set.  It had a hole where a list like that cannot -- an (at s 0)
over a slice of Fn read as clean while the Vec, struct and pointer
spellings were refused.  Unreachable today, and the header claims the
list is closed.  The same inversion fixes which refusal message an index
read gets.

Three minors: Anull was defined and never constructed; the capture-dyn
message substituted a descriptor into a noun slot; and session.ml
rendered a defn's changed signature as (Fn [...] ...), which is now a
real type and not the same as (CFn [...] ...) -- it writes the parameters
and the return the way a defn writes them.

And one rounding corrected in the docs: handler-bind is not free for a
program that captures nothing.  %handler grew from 24 bytes to 32, every
push writes a null into the new field, every clause gains ptr %env with
an alloca and a store, and flan_signal passes one more argument per
dispatch -- twenty changed x86 lines on loops.flan.  Small, real, and
paid by every conditions program.
2026-09-21 13:41:44 +07:00
4cb53a0a9f What the two function types changed in the documents
The four refusals the function-value lane wrote down are now three and a
half: capture is a feature, the escape is the refusal in its place, and a
struct field or a global of function type is refused for the same zero as
before with a sharper reason behind it.  The handler note is amended
rather than deleted -- its reading was right, and saying so is worth more
than a clean paragraph.

The convention section carries both rulings, the name and every name it
beat, the warning that CFn is not C interop today, the four reasons to
reach for it, what was measured rather than asserted about an ordinary
defn, and the wasm32 finding that killed the first design -- being
exactly typed is checkable by a verifier and the alternative was an
argument from a calling convention.

FIX.org carries the rulings verbatim, what the escaping lane inherits and
changes, the thunk's environment holding a code pointer rather than a GC
object, and two things recorded and not built: a CFn under a future
--no-conditions reaching C's exact convention, and CFn in a struct or a
fixed array, which ZII refuses and capture has nothing to do with.
2026-09-21 13:41:44 +07:00