floats iter 1: JOURNAL — iteration close (schema layer)

This commit is contained in:
2026-05-10 14:50:42 +02:00
parent b2d31824a1
commit f227cce846
+90
View File
@@ -13082,3 +13082,93 @@ the wrong section. A future widening would either (a) constrain
the test to scan only §Data-model + ParamMode block, or (b)
extract the JSON-schema blocks from §Data-model into a
machine-readable file the test consumes. Queued.
## 2026-05-10 — Iteration Floats.1: schema layer
Added `Literal::Float { bits: u64 }` as the fifth `Literal` AST
variant. Bits are an IEEE-754 binary64 bit pattern, serialised as
a 16-character lowercase hex *string* in canonical JSON
(`{"bits":"<hex>","kind":"float"}`) via a private `hex_u64` serde
helper module on `ast.rs`. Routing the field through the JSON
string path bypasses `serde_json::Number::to_string` (not
bit-stable across `serde_json` versions for floats) and lets NaN /
±Inf survive canonicalisation at all — they collapse to `null` as
JSON numbers and are silently lost.
`Float` is now registered as a primitive type name in
`primitives.rs`; the lockstep test was extended with explicit
`assert!` lines after the loop because the loop's `assert_eq!`
passes vacuously when both functions return `false` / `None` for
a missing primitive.
Adding the variant broke Rust's enum exhaustiveness at eight
downstream `match Literal { … }` source sites and at two
drift-test exhaustive matches. Each got either the permanent
semantic arm (`ailang-check` typecheck:
`Literal::Float { .. } => Type::float()`) or a named-iteration
`unimplemented!("Floats milestone iter N: <subsystem>")` arm
(`ailang-codegen` → iter 4, `ailang-surface` print → iter 2,
`ailang-prose` → iter 5). The arms are honest about which
iteration owns the semantics, so future debugging starts with the
right pointer rather than a generic `unreachable!`.
The two drift-test exhaustive matches
(`spec_mentions_every_literal_variant`,
`design_md_anchors_every_literal_variant`) were extended along
with their exemplars and the corresponding spec anchors:
`crates/ailang-core/specs/form_a.md` gained a `` `FLOAT` `` atom
form line; `docs/DESIGN.md` gained a `{ "kind": "float", "bits":
"<16-lowercase-hex>" }` line in the Literal JSON-schema block at
line 1866. The drift tests are *the enforcement mechanism* of the
schema invariant — the original 5-iter plan put DESIGN.md changes
in iter 5, but the drift-test break revealed that schema-layer
DESIGN.md anchors belong in iter 1 (where they get added together
with the AST variant they document). Iter 5 retains the §"Float
semantics" subsection and the line-2033 "supported primitive
types" list update — those depend on later iterations being
shipped.
Bit-stability tests pin the A1 / A5 spec guarantees: `-0``+0`
at the canonical-bytes level (distinct hex strings); NaN bits
preserved; ±Inf bits preserved; serde round-trip is bit-exact for
the saturating boundary values (zero, sign-bit-only, 1.5, qNaN,
±Inf, all-ones).
Pre-existing `def_hash` regression hashes (`db33f57cb329935e` for
`sum.sum`, `b082192bd0c99202` for `IntList`) stayed GREEN —
adding a `Literal` variant does not perturb any pre-existing
canonical bytes, because `serde(tag = "kind")` keeps the
discriminator-only-on-construct path.
Rustdoc warning count stayed at the milestone-open baseline (1
pre-existing warning on `desugar`). Two new private-intra-doc-link
warnings introduced by the initial `Literal::Float` doc-comment
(`[`hex_u64`]` linking to a private mod) were caught by the
acceptance gate and fixed inline by dropping the link form in
favour of a plain-text `hex_u64` reference.
Per-task commits:
- `ec28111` floats iter 1.1: Literal::Float variant + canonical hex serde + drift-test anchors
- `93fe2da` floats iter 1.1 fixup: trim form_a.md FLOAT bullet to match neighbour style
- `aa5b88e` floats iter 1.2: register Float as a primitive type name
- `93bae2d` floats iter 1.2 fixup: replace iter-N comment with durable rationale for explicit assertions
- `7c95a69` floats iter 1.3: bit-stability tests for Literal::Float
- `1a4e2f0` floats iter 1.4: refresh canonical.rs 'no floats' doc comment
- `b2d3182` floats iter 1.4 fixup: drop intra-doc-links to private hex_u64 (rustdoc baseline preservation)
Known debt deliberately deferred to later iterations of this
milestone:
- Surface lex / parse / print round-trip for `1.5`, `1.5e3`,
`1e10` — iter 2.
- Typecheck widening of `+`/`-`/`*`/`/`/`<`/`<=`/`>`/`>=` from
monomorphic Int to polymorphic-`{Int, Float}` — iter 3.
- Codegen Float lowering paths (`fadd`/`fsub`/`fmul`/`fdiv`,
`fcmp o*`/`une`, `sitofp`, `@llvm.fptosi.sat.i64.f64`,
`fcmp uno` for `is_nan`, hex-float literal constants for
`nan`/`inf`/`neg_inf`) — iter 4.
- Prose round-trip for Float literals — iter 5.
- DESIGN.md §"Float semantics" subsection (A5 determinism
contract) and line-2033 "supported primitive types" list
update — iter 5.