iter rpe.1: retire per-type print effect-ops
Single iter shipping the post-milestone-24 follow-up named in
docs/specs/2026-05-14-retire-per-type-print-effects.md. After this
iter the only surviving direct-output effect-op is `io/print_str`;
all per-type print primitives are replaced by the polymorphic
`print` helper (prelude, iter 24.3).
Components:
- 92 examples/*.ail fixtures migrated (do io/print_<T> x) →
(app print x); 6 .prose.txt snapshots regenerated via `ail prose`.
- Four-site lockstep compiler deletion: crates/ailang-check/src/builtins.rs
(3 effect_ops.insert blocks + 3 list() rows + the
install_io_print_float_signature test + module + EffectOpSig
doc-comments); crates/ailang-codegen/src/lib.rs lower_app
(3 arms + lowers_io_print_float test); crates/ailang-codegen/src/synth.rs
builtin_effect_op_ret match-arm pattern. Dead `intern_string`
helper removed as a follow-up.
- Five incidental test-body migrations (ailang-check x2, ailang-core
spec_drift + design_schema_drift, ailang-surface/src/lex.rs,
ailang-prose/src/lib.rs round-trip test).
- Cat B test-harness patch: six IR-shape tests in
crates/ail/tests/e2e.rs gained a monomorphise_workspace call
before lower_workspace_with_alloc so they follow the same
pipeline as `ail build` (the home-rolled desugar+lift loop
stayed because mono's precondition is "already lifted"; mono
inserts after lift).
- Six doc-comment touch-ups (lex.rs module doc, parse.rs
diagnostic example, ail/src/main.rs x2, runtime/str.c %g anchor,
crates/ailang-core/specs/form_a.md surface-spec example).
- DESIGN.md seven-site sweep (Decision 11 example, Polymorphic
print past-tense, Heap-Str output sentence, effect-op
invocation comment, Float NaN paragraph re-anchored on
float_to_str, two "What is supported" lists).
- Three E2E test-comment polish + four IR-snapshot refresh + one
canonical-hash pin update (plan-unanticipated downstream
consequences of the corpus migration).
- bench/{check,compile_check,cross_lang}.py: all exit 0; no
ratification needed.
- Roadmap entry struck through; per-iter journal at
docs/journals/2026-05-14-iter-rpe.1.md.
Tests 564/0/3. cargo clippy and cargo doc: zero warnings.
Two upstream codegen bugs surfaced during the first BLOCKED
attempt and were fixed in separate iters before this retry:
- 1fb225e bugfix: mono cursor misalignment at poly-free-fn Var
with class-constrained Forall.
- feb9413 bugfix: print leak — propagate ret_mode through rigid
substitution + prelude Show.show ret_mode.
Known debt (carried forward for next /audit):
- Emitter.strings field is functionally dead post-iter (orphan
after intern_string removal); cycles over empty map harmlessly.
This commit is contained in:
+31
-22
@@ -328,7 +328,7 @@ Every other maximal token is classified post-hoc:
|
||||
- Otherwise → ident.
|
||||
|
||||
Consequence: operators like `+`, `==`, `<=`, `**`, qualified
|
||||
names like `io/print_int`, and cross-module references like
|
||||
names like `io/print_str`, and cross-module references like
|
||||
`std_list.map` are all single ident tokens with no special lex
|
||||
rule. The only reserved tokens are `(`, `)`, and whitespace.
|
||||
Bool literals (`true`, `false`) and unit (`(lit-unit)`) are
|
||||
@@ -1987,9 +1987,10 @@ a => a -> () !IO` shipped in iter 24.3 with body
|
||||
`\x -> let s = show x in do io/print_str s` (explicit let-binder for
|
||||
heap-Str RC discipline per eob.1 Str carve-out). The let-binder is
|
||||
structurally pinned by `crates/ail/tests/print_mono_body_shape.rs`.
|
||||
Routing through `print` replaces the ad-hoc `io/print_int|bool|float`
|
||||
idiom for new code; retiring the per-type effect-ops is queued as a
|
||||
P2 follow-up.
|
||||
Routing through `print` replaces the ad-hoc per-type print
|
||||
effect-ops; the `io/print_int`, `io/print_bool`, `io/print_float`
|
||||
primitives were retired 2026-05-14 in iter rpe.1, leaving
|
||||
`io/print_str` as the only surviving direct-output effect-op.
|
||||
|
||||
### Heap-Str primitives
|
||||
|
||||
@@ -2021,8 +2022,12 @@ bodies dispatch into them. `str_concat` IS directly observable
|
||||
because the LLM-author calls it explicitly when authoring an
|
||||
instance body that wants to combine fragments.
|
||||
|
||||
Primitive output goes through `io/print_int` / `io/print_bool` /
|
||||
`io/print_str` directly.
|
||||
Primitive output for `Str` values goes through `io/print_str`
|
||||
directly; values of other primitive types route through the
|
||||
polymorphic `print` helper (§"Polymorphic print"), which feeds
|
||||
the heap-Str result of `show x` into `io/print_str`. The per-type
|
||||
effect-ops `io/print_int`, `io/print_bool`, `io/print_float` were
|
||||
retired in iter rpe.1 (2026-05-14).
|
||||
|
||||
`==`, `<`, `<=`, `>`, `>=` REMAIN primitive operators (unchanged
|
||||
from the original draft). Class methods are accessed by name (`eq x y`,
|
||||
@@ -2328,7 +2333,7 @@ are real surface forms.
|
||||
|
||||
{ "t": "if", "cond": Term, "then": Term, "else": Term }
|
||||
|
||||
// Effect-op invocation. `op` is "<eff>/<op>" (e.g. "io/print_int").
|
||||
// Effect-op invocation. `op` is "<eff>/<op>" (e.g. "io/print_str").
|
||||
// `tail` triggers musttail (omitted when false).
|
||||
{ "t": "do", "op": "<eff>/<op>", "args": [Term...], "tail": false }
|
||||
|
||||
@@ -2562,23 +2567,24 @@ no `f32` variant. The runtime / codegen contract:
|
||||
pattern is conformant; `0.0 / 0.0` may produce
|
||||
`0x7ff8000000000000` on one target and a different qNaN on
|
||||
another.
|
||||
- The textual rendering of NaN by `io/print_float`. The libc
|
||||
`printf("%g", nan)` glue used by the runtime is permitted to
|
||||
emit `nan` / `-nan` / `NaN` etc. depending on libc version and
|
||||
the NaN's sign bit; AILang does not normalise this, since the
|
||||
prose / surface-print paths render NaN as the explicit `"NaN"`
|
||||
spelling and `io/print_float` is for human-readable output, not
|
||||
round-trip.
|
||||
- The textual rendering of NaN through `float_to_str` (the runtime
|
||||
C helper that backs `instance Show Float` and, post-iter-rpe.1,
|
||||
every Float-typed `print` call). The libc `printf("%g", nan)`
|
||||
glue used by `float_to_str` is permitted to emit `nan` / `-nan`
|
||||
/ `NaN` etc. depending on libc version and the NaN's sign bit;
|
||||
AILang does not normalise this, since the prose / surface-print
|
||||
paths render NaN as the explicit `"NaN"` spelling and Float
|
||||
rendering is for human-readable output, not round-trip.
|
||||
|
||||
The same libc-`%g` rendering applies to `show 1.5` / `show nan` /
|
||||
`show inf` via `instance Show Float` (which calls `float_to_str`
|
||||
internally — see §"Prelude (built-in) classes" for the Show ship).
|
||||
The NaN-spelling caveat above is observable via both
|
||||
`do io/print_float x` and `do print x` at the same `x`; the rendering
|
||||
is libc-version-dependent and target-libc-specific. AILang does NOT
|
||||
canonicalise Float textual representation; the LLM-author who needs
|
||||
deterministic Float rendering for cross-platform test fixtures should
|
||||
bypass `show` / `print` and emit a custom formatter.
|
||||
The NaN-spelling caveat above is observable via `do print x` for
|
||||
Float-typed `x`; the rendering is libc-version-dependent and
|
||||
target-libc-specific. AILang does NOT canonicalise Float textual
|
||||
representation; the LLM-author who needs deterministic Float
|
||||
rendering for cross-platform test fixtures should bypass `show` /
|
||||
`print` and emit a custom formatter.
|
||||
|
||||
These are the Rust / Swift / standard-LLVM defaults — not
|
||||
research-grade reproducibility guarantees. The stronger guarantee
|
||||
@@ -2676,7 +2682,10 @@ What **is** supported (and used as the smoke test for the pipeline):
|
||||
- Int, Bool, Unit, **Str**, **Float** as primitive types.
|
||||
- `if`, `let`, function calls, recursion.
|
||||
- Effects on function signatures, with `do op(args)` for direct effect
|
||||
ops (`io/print_int`, `io/print_bool`, `io/print_str`).
|
||||
ops (`io/print_str`). The per-type print ops
|
||||
`io/print_int`, `io/print_bool`, `io/print_float` were retired in
|
||||
iter rpe.1; the polymorphic `print` (§"Polymorphic print") is the
|
||||
canonical output path for non-Str values.
|
||||
- **Builtins.** Arithmetic operators (`+`, `-`, `*`, `/`) of type
|
||||
`forall a. (a, a) -> a` (codegen-restricted to `{Int, Float}`);
|
||||
`%` of type `(Int, Int) -> Int` (Int-only — `fmod` semantics for
|
||||
@@ -2696,7 +2705,7 @@ What **is** supported (and used as the smoke test for the pipeline):
|
||||
`fcmp uno`); Float bit-pattern constants `nan : Float`,
|
||||
`inf : Float`, `neg_inf : Float` (resolved as bare values, lower
|
||||
to direct hex-float `double` SSA constants at use site); the IO
|
||||
effect ops (`io/print_int|bool|str|float`); **`==` : forall a.
|
||||
effect op `io/print_str`; **`==` : forall a.
|
||||
(a, a) -> Bool**; and **`__unreachable__ : forall a. a`**.
|
||||
- **`==` is polymorphic.** The typechecker accepts
|
||||
`==` at any type whose two sides agree (the rigid `a` of the
|
||||
|
||||
Reference in New Issue
Block a user