All 176 files in the four accumulating directories now use a zero-padded 4-digit counter prefix that reflects creation order (`NNNN-slug.md`). The counter is assigned per directory in strict git-log creation order; ties broken alphabetically by original name. The old `YYYY-MM-DD-` prefix on docs/specs/ and docs/plans/ files is dropped — the date is recoverable from git log and the counter carries the ordering. A file's counter is stable for the life of the file: never reassigned, never reused, never compacted. Deleted files retire their counter; subsequent files do not fill the gap. This is the property that lets cross-references stay literal — refs use the full filename including the counter (`design/contracts/0007-honesty-rule.md`) so they grep cleanly and resolve directly without a glob step. 313 cross-references updated across .md/.rs/.toml/.c/.json files (test pins, include_str! paths, design-INDEX entries, baseline notes, runtime C comments, inter-contract markdown links incl. bare basename and `../models/foo.md` forms). CLAUDE.md gets a new "File-naming convention" section spelling out the rule and rationale. skills/brainstorm/SKILL.md and skills/planner/SKILL.md updated so new spec/plan creation produces counter-prefixed names from the start. The full test suite (cargo test --workspace) passes.
4.0 KiB
Prelude (built-in) classes
Prelude (built-in) classes
The prelude ships the Ordering ADT, the Eq and Ord
classes, primitive Eq Int/Bool/Str/Unit and
Ord Int/Bool/Str instances, and the five polymorphic free-fn
helpers ne/lt/le/gt/ge. The primitive Eq / Ord
instance bodies are placeholder lambdas in examples/prelude.ail;
the codegen intercept try_emit_primitive_instance_body overrides
them with single-instruction bodies (icmp eq i64 for eq__Int,
icmp eq i1 for eq__Bool, @ail_str_eq for eq__Str,
ret i1 1 for eq__Unit; a three-way icmp ladder constructing
LT/EQ/GT for compare__T) and attaches alwaysinline so
the call folds to the single instruction at every use site.
The five Ord-class free helpers (ne/lt/le/gt/ge) have
source-level bodies that route through eq / compare plus
match over Ordering — written that way so the surface form is
LLM-natural and so user-ADT instances of Eq/Ord automatically
pick up working helpers without any per-type opt-in. At Int the
codegen intercept short-circuits this indirection: lt__Int,
le__Int, gt__Int, ge__Int, and ne__Int are intercept-
overridden to emit icmp slt i64 / sle i64 / sgt i64 /
sge i64 / ne i64 directly, bypassing the compare__Int →
Ordering-ctor → match path. Without this short-circuit the
Ordering ctor allocates per call inside hot loops — a real
cost surfaced by the bench_closure_chain regression at the
operator-routing-eq-ord milestone and pinned by
crates/ail/tests/ord_int_intercept_ir_pin.rs. The short-circuit
is Int-only by deliberate asymmetry: no current bench or
example fixture exercises Ord-lt/le/gt/ge at Bool or
Str at sufficient call frequency to justify the intercept-arm
maintenance; the symmetric extensions are mechanical when the
first such workload appears.
Float has neither Eq nor Ord instance per Float semantics; a polymorphic helper invoked at Float fires
NoInstance at typecheck with a Float-aware diagnostic that names
the explicit float_eq / float_lt alternatives and
cross-references this section. The lookup machinery that turns a
show x call site into the right monomorphic instance is
documented in method dispatch.
Float comparison is a separate surface: the six monomorphic prelude
fns float_eq / float_ne / float_lt / float_le / float_gt
/ float_ge each carry the type (Float, Float) -> Bool without
a class constraint. They lower via the same intercept machinery as
the primitive Eq instances (single fcmp instruction with the
matching predicate oeq / une / olt / ole / ogt / oge,
plus alwaysinline). They replace what would otherwise be a
polymorphic == / < on Float — Float gets full comparability
via explicit named fns, not via an implicit class instance.
The prelude ships class Show a where show : (a borrow) -> Str and
primitive Show Int, Show Bool, Show Str, Show Float
instances. Float is included in Show (unlike Eq/Ord) — IEEE-754
makes structural equality and total ordering semantically dubious,
but textual representation of a Float is well-defined modulo the
NaN-spelling caveat in Float semantics. Each
Show <T> instance body is a single-application lambda invoking the
corresponding runtime primitive (int_to_str, bool_to_str,
str_clone, float_to_str; see Str ABI for the
heap-Str primitives); no codegen intercept is required. The
polymorphic helper print : forall a. Show a => a -> () !IO has body
\x -> let s = show x in do io/print_str s (explicit let-binder for
heap-Str RC discipline per the Str carve-out in
Str ABI). The let-binder is
structurally pinned by crates/ail/tests/print_mono_body_shape.rs.
Routing through print is the path for non-Str primitives;
io/print_str is the only built-in direct-output effect-op.
Ratified by: crates/ail/tests/show_no_instance_e2e.rs.