iter 24.2: class Show + 4 primitive instances + 22b TShow migration
Ships class Show a where show : (a borrow) -> Str in the prelude
plus primitive Show Int / Bool / Str / Float instances. Each
instance body is a single-application lambda invoking the
corresponding runtime primitive (int_to_str, bool_to_str,
str_clone, float_to_str) — first prelude instance bodies to call
runtime primitives directly. Float is included in Show (unlike
Eq/Ord) because textual representation is well-defined modulo the
NaN-spelling caveat at DESIGN.md §Float semantics.
The 22b typeclass test corpus is migrated preemptively: 21 fixture
files and 6 consumer files (typeclass_22b{2,3}.rs +
hash.rs ct4 pin + workspace.rs iter22b1 tests + the
instance_present.prose.txt snapshot) rename class Show / show
to class TShow / tshow, analogous to the existing TEq/TOrd
convention. Migration runs before the prelude additions so the
workspace stays green throughout.
Three new tests pin the post-mono shape: show_mono_synthesis.rs
(existence of show__Int/Bool/Str/Float as Def::Fn entries in the
prelude post-mono module), show_dispatch_pin.rs (bare show and
tshow both Step-2 singletons workspace-globally),
mono_hash_stability.rs::primitive_show_mono_symbol_hashes_stay_bit_identical
(body hashes pinned for the 4 new mono symbols).
DESIGN.md §Prelude (built-in) classes drops Show from the
deferred-features list and appends a milestone-24 paragraph
naming the class signature + the 4 instances + the body shape.
print rewire stays deferred to iter 24.3.
Tests: 552 passed (was 548 + 4 new). bench/compile_check +
bench/cross_lang exit 0. bench/check exits 1 on the recurring
noise envelope per the conservative-call lineage.
This commit is contained in:
+20
-6
@@ -1888,12 +1888,26 @@ end-to-end path is the milestone's typeclass acceptance gate
|
||||
Milestone 23 amends the above: the prelude now ships the `Ordering`
|
||||
ADT, the `Eq` and `Ord` classes, primitive `Eq Int/Bool/Str` and
|
||||
`Ord Int/Bool/Str` instances, and the five polymorphic free-fn helpers
|
||||
`ne` / `lt` / `le` / `gt` / `ge`. `Show`, operator routing through
|
||||
`Eq`/`Ord`, and `print`-rewire remain out of scope per their original
|
||||
substantive reasons (heap-`Str` ABI, bench rebaseline). 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 cross-referencing this section.
|
||||
`ne` / `lt` / `le` / `gt` / `ge`. Operator routing through `Eq`/`Ord`
|
||||
and `print`-rewire remain out of scope per their original substantive
|
||||
reasons (bench rebaseline, milestone-24 dependency on the post-mq
|
||||
dispatcher); `Show` itself ships in milestone 24. 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 cross-referencing this section.
|
||||
|
||||
Milestone 24 amends the above further: 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`); no codegen intercept is required. The
|
||||
polymorphic helper `print : forall a. Show a => a -> () !IO` ships in
|
||||
the same milestone as the second iteration (24.3) and routes through
|
||||
`show` and `io/print_str`.
|
||||
|
||||
Primitive output goes through `io/print_int` / `io/print_bool` /
|
||||
`io/print_str` directly.
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
# iter 24.2 — Show class + 4 primitive instances + 22b TShow/tshow migration
|
||||
|
||||
**Date:** 2026-05-13
|
||||
**Started from:** 64cea0e
|
||||
**Status:** DONE
|
||||
**Tasks completed:** 8 of 8
|
||||
|
||||
## Summary
|
||||
|
||||
Ships `class Show a where show : (a borrow) -> Str` in
|
||||
`examples/prelude.ail.json` alongside primitive instances `Show Int`,
|
||||
`Show Bool`, `Show Str`, `Show Float`. Each instance body is a
|
||||
single-application lambda invoking the corresponding runtime primitive
|
||||
(`int_to_str`, `bool_to_str`, `str_clone`, `float_to_str`) — first
|
||||
prelude instance bodies to call runtime primitives directly
|
||||
(prior Eq/Ord bodies used operator + codegen intercept). The 22b
|
||||
typeclass test corpus migrates `class Show` / `show` →
|
||||
`class TShow` / `tshow` preemptively (Tasks 1–2 before Task 3 lands
|
||||
`prelude.Show`) so the workspace stays green throughout. Three new
|
||||
tests pin the post-mono shape: mono-synthesis existence
|
||||
(`show_mono_synthesis.rs`), dispatch singleton (`show_dispatch_pin.rs`
|
||||
× 2 cases), and body-hash stability (`mono_hash_stability.rs::primitive_show_mono_symbol_hashes_stay_bit_identical`).
|
||||
DESIGN.md §"Prelude (built-in) classes" gains a milestone-24 paragraph
|
||||
naming Show + instances + the Float caveat. `print`-rewire stays
|
||||
deferred to iter 24.3.
|
||||
|
||||
## Per-task notes
|
||||
|
||||
- iter 24.2.1: Renamed `"Show"`/`"show"` → `"TShow"`/`"tshow"` across 21
|
||||
`test_22b*_*.ail.json` fixture files; cross-module qualifier forms
|
||||
(`"<modname>.Show"` → `"<modname>.TShow"`) handled by regex in 3
|
||||
fixtures (`test_22b1_dup_a`, `test_22b1_dup_b`,
|
||||
`test_22b1_orphan_third`). False-positive scan empty; fixture
|
||||
parse round-trip green.
|
||||
- iter 24.2.2: Renamed literals in `crates/ail/tests/typeclass_22b{2,3}.rs`
|
||||
(`"Show"` → `"TShow"`, `"show"` → `"tshow"`, `show__T` → `tshow__T`),
|
||||
including comment-prose forms (`` `Show` `` → `` `TShow` ``,
|
||||
`class Show` → `class TShow`, etc.) and one assertion-message string
|
||||
("exactly one show__Int across the workspace" → "tshow__Int...").
|
||||
Plan undercount surfaced: the rename touches more than the 2 named
|
||||
test files — see Concerns below.
|
||||
- iter 24.2.3: Inserted 5 new top-level defs into `examples/prelude.ail.json`
|
||||
immediately before `fn ne` (line 223 pre-edit). The `instance Show Str`
|
||||
body invokes `str_clone` as `Term::Var` — first prelude instance body
|
||||
to do so. Round-trip green; `primitive_eq_ord_mono_symbol_hashes_stay_bit_identical`
|
||||
stays green (Eq/Ord hashes unaffected by Show defs).
|
||||
- iter 24.2.4: New fixture `examples/show_mono_pin_smoke.ail.json`
|
||||
exercises `show 42`, `show true`, `show "x"`, `show 1.5` in a
|
||||
let-chain ending in `io/print_str s1`. New test
|
||||
`crates/ail/tests/show_mono_synthesis.rs::primitive_show_mono_symbols_synthesise`
|
||||
asserts `show__Int`/`show__Bool`/`show__Str`/`show__Float` materialise
|
||||
as `Def::Fn` entries in the `prelude` post-mono module. `str_clone`
|
||||
reachability in instance-lambda position verified implicitly:
|
||||
`show__Str` materialises, which means the lambda body's `Term::Var
|
||||
"str_clone"` resolved against the checker's builtin table during
|
||||
typecheck.
|
||||
- iter 24.2.5: New pin test `crates/ailang-check/tests/show_dispatch_pin.rs`
|
||||
asserts `env.method_to_candidate_classes["show"] == {"prelude.Show"}`
|
||||
(singleton) and `env.method_to_candidate_classes["tshow"] == {"*.TShow"}`
|
||||
(singleton). API spelled `build_check_env(&ws)` not `Env::from_workspace`
|
||||
(plan's placeholder name). 2/2 cases pass first-shot.
|
||||
- iter 24.2.6: Extended `crates/ail/tests/mono_hash_stability.rs` with
|
||||
a second test function `primitive_show_mono_symbol_hashes_stay_bit_identical`
|
||||
loading `show_mono_pin_smoke.ail.json` (kept separate from the
|
||||
Eq/Ord fixture to avoid coupling). Hashes captured first-run:
|
||||
`show__Int 891eaebe64b3180d`, `show__Bool 1bdb621494e50607`,
|
||||
`show__Str 3f1d57c90ddce081`, `show__Float 5ab0bdd40b9f8b8f`.
|
||||
- iter 24.2.7: DESIGN.md §"Prelude (built-in) classes" amended:
|
||||
milestone-23 paragraph drops "Show" from the deferred list and notes
|
||||
Show ships in milestone 24; new milestone-24 paragraph names class
|
||||
signature, instance set (including Float), body shape (single-app
|
||||
lambda invoking runtime primitive), and the iter-24.3 carry-forward
|
||||
for `print`-rewire.
|
||||
- iter 24.2.8: Workspace tests 552 passed / 0 failed
|
||||
(was 548 pre-iter, +4 new: 1 `show_mono_synthesis` + 2 `show_dispatch_pin`
|
||||
+ 1 hash-stability). `bench/compile_check.py` exit 0 (24/24 stable).
|
||||
`bench/cross_lang.py` exit 0 (25/25 stable). `bench/check.py` exit 1
|
||||
with 2 noise-class metrics (`bench_list_sum.bump_s` +11.71% — 4th
|
||||
consecutive sighting per `audit-mq` / `mq.tidy` lineage;
|
||||
`latency.implicit_at_rc.max_us` +145.55% — 7th consecutive sighting of
|
||||
the documented noise envelope, metric-identity-migrating across runs).
|
||||
Baseline pristine per the conservative-call convention.
|
||||
|
||||
## Concerns
|
||||
|
||||
- **Plan undercount on 22b migration scope.** The plan's "2 Rust test
|
||||
files" carrier (typeclass_22b{2,3}.rs) missed 4 additional consumer
|
||||
sites that hardcode the renamed literals: (a)
|
||||
`crates/ailang-core/src/hash.rs` ct4 canonical-form hash pin (2
|
||||
entries); (b) `crates/ailang-core/src/workspace.rs` 3 in-crate iter22b1
|
||||
tests; (c) `crates/ailang-prose/tests/snapshot.rs` (1 snapshot file at
|
||||
`examples/test_22b2_instance_present.prose.txt`); (d) one
|
||||
`mono_symbol_compound_type_uses_hash_suffix` assertion in typeclass_22b3.rs
|
||||
that called `mono_symbol("tshow", ...)` (post my batch rename) but
|
||||
still asserted `name.starts_with("show__")`. All fixed inline per the
|
||||
precedent of mq.1 / mq.3 "Plan defects fixed inline" — fixture parse
|
||||
was the only "green" pre-iter signal the plan's Step 3/4 anchored on,
|
||||
which masked the broader downstream consumer surface. Suggested
|
||||
Boss-side reaction: future migration plans run an upfront
|
||||
`grep -rln '"<rename target>"' crates/` to enumerate the full
|
||||
consumer set before committing to a per-file enumeration.
|
||||
- **`str_clone` reachability is implicit.** Pre-flight note 3 flagged
|
||||
this as needing first-round-trip verification; verification is
|
||||
implicit in `primitive_show_mono_symbols_synthesise` passing
|
||||
(mono of `show 42 / true / "x" / 1.5` requires the four `show__T`
|
||||
bodies to typecheck, including the `str_clone` call in `show__Str`).
|
||||
No explicit isolated unit test for `str_clone`-in-lambda was added
|
||||
because the integration pin is strictly stronger; consider an
|
||||
isolated unit pin only if a future regression makes the integration
|
||||
test slow to bisect.
|
||||
- **Hash-stability pin uses a separate fixture, not the existing
|
||||
`mono_hash_pin_smoke.ail.json`.** Plan Task 6 offered both options;
|
||||
the separate-fixture path was chosen because `show_mono_pin_smoke.ail.json`
|
||||
already existed (minted in Task 4) and reusing it kept the Eq/Ord
|
||||
pin structurally isolated. Both fixtures live side-by-side; the
|
||||
second test function in `mono_hash_stability.rs` mirrors the first
|
||||
byte-for-byte modulo the fixture path and pin table.
|
||||
- **`bench/check.py` exit 1 is the documented recurring noise envelope.**
|
||||
`latency.implicit_at_rc.*` max-tail metric has been migrating
|
||||
between runs since `audit-cma` (2026-05-12) — 7th consecutive
|
||||
observation; `bench_list_sum.bump_s` is the 4th since `audit-mq`.
|
||||
Plan Task 8 Step 4 explicitly anticipates "1-3 regressed metrics
|
||||
ratify-without-attribution per conservative-call convention"; this
|
||||
iter follows that. The baseline stays pristine.
|
||||
|
||||
## Known debt
|
||||
|
||||
- **iter 24.3 still pending.** Carries `print : forall a. Show a => a -> () !IO`
|
||||
rewire to route through `show` + `io/print_str`. Spec at
|
||||
`docs/specs/2026-05-13-24-show-print.md`. 24.2 is structurally
|
||||
complete; 24.3 is operationally distinct.
|
||||
- **mq1 cross-module fixtures unmigrated by design.**
|
||||
`examples/mq1_xmod_constraint_class.ail.json` and `..._dep.ail.json`
|
||||
reference `mq1_xmod_constraint_class_dep.Show` (cross-module, fully
|
||||
qualified) and ship zero `show` call sites; no dispatch ambiguity
|
||||
arises once `prelude.Show` lands. They stay as-is per the plan's
|
||||
pre-flight ratification.
|
||||
- **mq3 fixtures deliberately retain two-Show shapes.**
|
||||
`examples/mq3_two_show_*` fixtures test the multi-class dispatch
|
||||
scenarios (ambiguity + qualifier resolution) and stay unchanged in
|
||||
24.2 by design.
|
||||
|
||||
## Files touched
|
||||
|
||||
**Created (3):**
|
||||
- `crates/ail/tests/show_mono_synthesis.rs`
|
||||
- `crates/ailang-check/tests/show_dispatch_pin.rs`
|
||||
- `examples/show_mono_pin_smoke.ail.json`
|
||||
|
||||
**Modified (29):**
|
||||
|
||||
Prelude + DESIGN:
|
||||
- `examples/prelude.ail.json` (+5 defs)
|
||||
- `docs/DESIGN.md` (§"Prelude (built-in) classes" amendment)
|
||||
|
||||
22b fixture migration (21 files):
|
||||
- `examples/test_22b1_dup_a.ail.json`
|
||||
- `examples/test_22b1_dup_b.ail.json`
|
||||
- `examples/test_22b1_dup_classmod.ail.json`
|
||||
- `examples/test_22b1_dup_same_module.ail.json`
|
||||
- `examples/test_22b1_orphan_class.ail.json`
|
||||
- `examples/test_22b1_orphan_third.ail.json`
|
||||
- `examples/test_22b1_orphan_third_classmod.ail.json`
|
||||
- `examples/test_22b2_class_method_lookup.ail.json`
|
||||
- `examples/test_22b2_constraint_declared.ail.json`
|
||||
- `examples/test_22b2_instance_present.ail.json`
|
||||
- `examples/test_22b2_missing_constraint.ail.json`
|
||||
- `examples/test_22b2_no_instance.ail.json`
|
||||
- `examples/test_22b2_two_fns_missing_constraint.ail.json`
|
||||
- `examples/test_22b2_xmod_classmod.ail.json`
|
||||
- `examples/test_22b2_xmod_classmod_noinst.ail.json`
|
||||
- `examples/test_22b2_xmod_instance_present.ail.json`
|
||||
- `examples/test_22b2_xmod_missing_constraint.ail.json`
|
||||
- `examples/test_22b2_xmod_no_instance.ail.json`
|
||||
- `examples/test_22b3_dup_call_sites.ail.json`
|
||||
- `examples/test_22b3_no_call_sites.ail.json`
|
||||
- `examples/test_22b3_shadow_class_method.ail.json`
|
||||
|
||||
22b consumer-test migration (5 source files + 1 snapshot):
|
||||
- `crates/ail/tests/typeclass_22b2.rs`
|
||||
- `crates/ail/tests/typeclass_22b3.rs`
|
||||
- `crates/ailang-core/src/hash.rs` (ct4 hash pin)
|
||||
- `crates/ailang-core/src/workspace.rs` (3 iter22b1 tests)
|
||||
- `crates/ail/tests/mono_hash_stability.rs` (new show test fn)
|
||||
- `examples/test_22b2_instance_present.prose.txt` (snapshot accept)
|
||||
|
||||
## Stats
|
||||
|
||||
`bench/orchestrator-stats/2026-05-13-iter-24.2.json`
|
||||
Reference in New Issue
Block a user