floats iter 1: JOURNAL — iteration close (schema layer)
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user