The first formal-links milestone shipped clause-5 + 8 links across the
existing file layout. Browsing surfaced that file-only granularity is
only as precise as the file boundaries — three files mixed two or
three navigation targets under one address, so the 8 links could not
multiply without ambiguity. This commit fixes the substrate, then
applies the sweep the original milestone deferred.
Splits (each extracts an already-self-contained section into its own
file so links land on the topic, not the parent doc's TOC):
contracts/typeclasses.md
→ +contracts/prelude-classes.md (Eq/Ord/Show ships, polymorphic `print`)
→ +contracts/method-dispatch.md (5-step dispatch rule, candidate index)
contracts/memory-model.md
→ +contracts/language-constraints.md (the 4 binding constraints
making RC sound without a
cycle collector)
models/authoring-surface.md
→ +models/prose-projection.md (Form-B / `ail prose` / merge-prose)
Each new file enters design/INDEX.md as its own row (three contracts
share show_no_instance_e2e.rs / uniqueness.rs as ratifying tests;
prose-projection is a model). Two pre-existing links rebind to the
new topic-files (memory-model.md → method-dispatch.md;
float-semantics.md → prelude-classes.md).
Link sweep: 8 → 88 formal Markdown links over 23 files. Every file
in design/contracts/ + design/models/ now has at least one outgoing
link; the tree is fully connected. Links are file-relative
`[label](path)` per the established convention, fenced code blocks
are skipped (a `](` inside ```jsonc``` is literal text), the durable
tier (design/ + crates/ + runtime/) is enforced by clause-5.
Tests:
- design_index_pin.rs (5/5 clauses): clean-cut, INDEX resolution,
ratifying-test resolution, no decision-record prose in contracts/,
body links durable + resolving.
- docs_honesty_pin.rs (5/5): one assertion rebinds from typeclasses.md
to prelude-classes.md (where the gated sentence now lives);
design_corpus widens to include the 4 new files so the Wunschdenken
/ doc-archaeology sweeps continue to cover everything that used to
live in the parents.
No spec/plan/journal for this batch — interactive collaboration after
the milestone closed; the user gated the splits explicitly before the
sweep.
1.9 KiB
Language-design constraints (binding)
Language-design constraints (binding)
The four constraints below are necessary preconditions for RC to be sound and complete without a cycle-collector backstop. They are not new — AILang already satisfies all four — but Decision 10 makes them load-bearing rather than incidental:
- Strict evaluation. Every
Term::App(see Data model) argument is fully evaluated before the call. No laziness, no thunks. (Already true.) - No recursive value bindings.
(let x EXPR ...)evaluatesEXPRin a scope wherexis not bound. Recursion is exclusively viaTerm::LetRec(which binds a fn, not a value) and module-level fn defs. (Already true.) - No shared mutable refs. Values are immutable once
constructed. There is no
ref,IORef,Mutex, or any primitive that allows a value to be mutated from a position outside its allocation. (Already true.) - ADTs are acyclic by construction. Strict evaluation + no-recursive-value-bindings + no-shared-mutable-refs together guarantee that any value graph reachable from a binding is a DAG. The reference graph has no cycles. (Follows from 1–3.)
Laziness, recursive value bindings, shared mutable state, or any feature that creates cycles is rejected at design time unless the proposal proves the cycle is collectible by an extension (e.g. linear ownership).
These constraints are the precondition for the memory model: a sound RC implementation without a cycle-collector backstop requires the reference graph to be a DAG, which constraint 4 establishes from 1–3. They are also the load-bearing structural reason behind several feature-acceptance clause-3 rejections (notably iterated-mutable-state reasoning).
Ratified by: crates/ailang-check/src/uniqueness.rs (in-source mod tests).