Ships fn print : forall a. Show a => (a borrow) -> () !IO in the
prelude with explicit-let body \\x -> let s = show x in do
io/print_str s. Three new E2E fixtures + tests verify the full
path:
- show_print_smoke: 4 primitives smoke (print 42 / true / 'hello' /
3.14) — compile, run, expected stdout
- show_user_adt: data IntBox + instance prelude.Show IntBox +
print (MkIntBox 7) — stdout '7'
- show_no_instance: let f : Int -> Int = \\x -> x in do print f —
fires Show-aware NoInstance with DESIGN.md §Prelude(built-in)
classes cross-reference
IR-shape pin in print_mono_body_shape.rs asserts post-mono
print__Int.body is structurally Term::Let → App(show__Int) →
Do(io/print_str). Protects the explicit let-binder for the heap-Str
RC discipline per eob.1 Str carve-out.
Three plan-defects-fixed-inline surfaced during user-ADT E2E,
necessary repairs to make the spec's stated user-ADT trajectory
work end-to-end:
(a) mono.rs (2 sites): MonoTarget::FreeFn::type_args were carrying
bare type-cons references; normalised to canonical
<owner>.<bare> form via workspace_registry.normalize_type_for_lookup
so synthesised cross-module bodies' post-mono walks reach the
registry-keyed instance entries. Symmetric to the existing
class-method-arm normalisation.
(b) codegen/lib.rs (3 sites: resolve_top_level_fn, lower_app
cross-module arm, synth_with_extras Var arm): post-mono
synthesised bodies may carry cross-module references to modules
their source template didn't import (prelude.print__<UserType>
references show_user_adt.show__<UserType> even though prelude
does not import user modules). Fall back to direct
module_user_fns lookup when prefix not in import_map. Both
ends were independently typechecked before mono ran; the
cross-module ref is created by mono not by source.
(c) lib.rs synth FreeFnCall arm: walked Type::Forall.constraints,
substituted rigid vars with fresh metavars, pushed one
ResidualConstraint per declared constraint. Without this,
print f at Int -> Int would silently typecheck and fail with
a confusing 'unknown variable: show' at codegen rather than
fire the right typecheck-time NoInstance diagnostic.
NoInstance Float-aware arm in check/lib.rs:770-779 extended with
a parallel class == 'prelude.Show' branch that cross-references
DESIGN.md §Prelude(built-in) classes verbatim. Negative-fixture
test asserts code 'no-instance' + Show substring + Prelude-(built-in)-
classes substring.
DESIGN.md §Prelude(built-in) classes milestone-24 paragraph flips
fn print from 'ships in 24.3' to 'shipped in iter 24.3' with body
shape + pin file reference. §Float semantics gains a Show-Float
NaN-spelling cross-reference paragraph linking show 1.5 / show nan /
show inf to instance Show Float via float_to_str.
Roadmap P1 'Post-22 Prelude — Show + print rewire' flipped to [x]
with closing summary naming all three shipped iters (24.1 / 24.2 /
24.3). New P2 entry 'Retire io/print_int|bool|float effect-ops +
migrate example corpus to print' inserted at top of P2.
Tests: 556 passed (was 552 + 4 new). bench/cross_lang exit 0;
bench/compile_check + bench/check exit 1 on documented noise-class
metrics per the audit-cma lineage envelope (8th consecutive
audit-grade observation, baseline pristine per conservative-call).
Milestone 24 closes structurally with this iter. Standard audit
pipeline next.
15 KiB
AILang Roadmap
Priority-ordered list of upcoming work — milestones, features, todos, and ideas. The orchestrator maintains this file. The user can request additions; the orchestrator chooses what to remove or reprioritise as work progresses.
Conventions
- One checkbox per entry.
- [ ]is open;- [~]is in progress (work has started — a plan exists, a branch is open, or commits are landing);- [x]is done. A finished entry may stay briefly for context, then is removed (with a one-line mirror indocs/journals/). - Each entry is tagged by kind and lives under a priority
bucket:
- [milestone] — big chunk that will get a
docs/specs/<milestone>.md. - [feature] — smaller addition inside a milestone, no full spec.
- [todo] — concrete task that can run without a brainstorm (cleanup, doc fix, mechanical refactor, test backfill).
- [idea] — not yet decision-ready, no commitment.
- [milestone] — big chunk that will get a
- Optional
depends on:line names another entry that has to land first. - Optional
context:line points to the journal entry (per-iter file underdocs/journals/or, for pre-2026-05-11 entries, the archiveddocs/journal-archive.md) where the rationale lives. The roadmap is intentionally terse; rationale stays in the journals. - Priority buckets:
- P0 — in flight. Spec or plan already exists.
- P1 — next up. Decision made; not yet started.
- P2 — medium-term. Decided in principle, scheduled later.
- P3 — ideas. No commitment; may be cut.
P0 — In flight
(empty — canonical-type-names milestone closed 2026-05-11; Floats closed 2026-05-10 and was removed once it stopped being load-bearing context. Pick the next milestone from P1.)
P1 — Next
-
[milestone] Heap-
StrABI — runtime infrastructure for malloc-backed, refcountedStrvalues alongside the existing static@.str_*globals. Today theStrpath is static-only (DESIGN.md §"Float semantics" notes this explicitly), so any primitive that needs to produce aStrat runtime —int_to_str,float_to_str(currently type-installed butCodegenError::Internalon call), eventualShow.show, future++on strings — cannot ship. Scope: pick the representation (likely a{rc_header, len, bytes…}slab consistent with the rest of the RC runtime), teach codegen to accept both static and heapStrat the same ABI slot, wire RCinc/drop/clone/compare/eqon the heap form, and shipint_to_str+float_to_stras the first two callers so the ABI gets exercised end-to-end. Unblocks Show + print rewire below.- context: DESIGN.md §"Float semantics" (
float_to_stris type- installed, codegen-deferred); spec 2026-05-11-23-eq-ord-prelude §"Show. Defers behind a heap-Str-ABI milestone"; spec 2026-05-10-fieldtest-floats §F4 ("dynamic Str allocation in the runtime"); spec 2026-05-09-22-typeclasses §22b.4b ("Show#Int needs anint_to_strprimitive returning heap-allocated Str").
- context: DESIGN.md §"Float semantics" (
-
[milestone] Post-22 Prelude — Show + print rewire — shipped 2026-05-13 as iters 24.1 (heap-Str runtime + codegen for
bool_to_strstr_clone,f38bad8), 24.2 (preludeclass Show+ four primitive instances Int/Bool/Str/Float + 22b TShow/tshow migration), and 24.3 (polymorphicfn print : forall a. Show a => (a borrow) -> () !IO- positive 4-prim E2E + user-ADT E2E + Show-aware NoInstance
diagnostic + DESIGN.md amendments to §"Prelude (built-in) classes"
and §"Float semantics"). The
MethodNameCollisionworkaround that blocked the original spec retired in mq.3 (2026-05-13); specdocs/specs/2026-05-13-24-show-print.mdre-derived 24.2 + 24.3 against the post-mq architecture.
- context: spec
docs/specs/2026-05-13-24-show-print.md; per-iter journals 2026-05-12-iter-24.1, 2026-05-13-iter-24.2, 2026-05-13-iter-24.3.
P2 — Medium-term
-
[milestone] Retire
io/print_int/io/print_bool/io/print_floateffect-ops + migrate example corpus toprint. Bulk text substitutiondo io/print_<T> x→do print xacrossexamples/*.ail.json(~86 fixtures affected). Per-type effect-ops are deleted fromcrates/ailang-check/src/builtins.rs,crates/ailang-codegen/src/lib.rs::lower_apparms, and the corresponding runtime C glue.- context: post-milestone-24 mechanical follow-up; the architecture-
shipping milestone (24) and corpus-migration milestone (this) are
separate so migration runs against a frozen architecture. Same
call milestone 23 made for
==/eq.
- context: post-milestone-24 mechanical follow-up; the architecture-
shipping milestone (24) and corpus-migration milestone (this) are
separate so migration runs against a frozen architecture. Same
call milestone 23 made for
-
[feature] Operator routing through
Eq/Ord—==,<etc. resolved via the typeclass instead of the built-in primitive comparators. No commitment; gated on bench re-baselining to make sure the indirection doesn't tank latency.- context: JOURNAL 2026-05-09
- depends on: Post-22 Prelude — Eq/Ord (shipped 23.5)
-
[todo]
types/ctor_indexoverlay shape question — decide whether the env's two parallel ctor maps should collapse into one overlay, or stay split. Surfaced during the env-construction unify audit.- context: JOURNAL 2026-05-10 ("Audit close: env-construction unify"); closed by iter ctt.1 — DESIGN.md §"Env construction" anchors the split decision.
-
[todo] CLI human-mode diagnostic surface for
WorkspaceLoadError— non-JSONail checkroutes ct.1 errors viaanyhow/thiserrorDisplay (Error: <message>) instead of going throughworkspace_error_to_diagnostic, so the bracketed[code]prefix the JSON path carries is missing. Plausibly applies to every CLI subcommand that callsload_workspace(&path)?directly.- context: JOURNAL 2026-05-11 ("Iteration ct.1") — surfaced by ct.1.8 tester.
-
[todo] Retire dead
KindMismatcharm —validate_classdefs'swalk_kind_mismatchpath is structurally unreachable through well-formed schema post-ct.1 (the canonical-form validator catches the malformedType::Con { name: param }shape earlier). The enum variant +walk_kind_mismatchhelper stay as dead-but-defensive code; a future tidy can delete both.- context: JOURNAL 2026-05-11 ("Iteration ct.1"); closed by iter ctt.3 — variant + helper + dispatch + Display arm all deleted; canonical-form-rejection test stays green asserting
BareCrossModuleTypeRef.
- context: JOURNAL 2026-05-11 ("Iteration ct.1"); closed by iter ctt.3 — variant + helper + dispatch + Display arm all deleted; canonical-form-rejection test stays green asserting
-
[todo] Re-key
Registry.type_def_moduleto handle bare-name-collision-across-modules —BTreeMap<String, String>keyed by bare type name silently overwrites when two modules each definetype Foo;normalize_type_for_registrywould then collapseM.FooandN.Footo whichever insert won. Acceptable for current corpus (distinct bare type names across modules), but the proper fix is to key by(owning_module, bare_name) → defining_module.- context: JOURNAL 2026-05-11 ("Iteration ct.1") — flagged by ct.1.5a quality reviewer.
-
[feature] 22c — typeclass corpus expansion. User-defined classes beyond the prelude four; multi-parameter classes; superclass chains; richer instance bodies. Deferred from milestone 22.
- context: JOURNAL 2026-05-09
-
[milestone] Module-qualified class names + type-driven method dispatch — retired the
MethodNameCollisionworkaround; shipped 2026-05-13 as iters mq.1 (canonical-form extension for class-ref fields + workspace-internal qualification), mq.2 (type- driven dispatch mechanism installed:method_to_candidate_classesinverse index, multi-candidateResidualConstraint,resolve_method_dispatch5-step rule,AmbiguousMethodResolution+UnknownClassdiagnostics), and mq.3 (retirement + multi-class E2Eclass-method-shadowed-by-fnwarning + DESIGN.md sync). Two libraries can now each declareclass Eqwith their owneq; cross-class method ambiguity is resolved at the call site via type-driven dispatch with<module>.<Class>.<method>as the disambiguation form.
- context:
docs/specs/2026-05-10-canonical-type-names.md"Out of scope: Class names" — the workaround was named there so it stayed visible until this milestone retired it.
-
[todo] Boehm full retirement — remove the transitional Boehm GC path now that RC + uniqueness is the canonical memory story.
- context: JOURNAL pre-22, "Boehm transitional"
-
[feature] Closure-pair slab / pool — codegen tweak to pool the env+code closure pairs instead of one-shot heap allocs. Bench-gated.
-
[todo]
FnDef::syntheticflag — formalise the monomorphiser-emitted FnDefs so downstream passes can tell user-authored from synthesised at a glance. Currently inferred from symbol naming. -
[todo] 21'h iteration — final 21' carry-over (latency methodology pass). Numbering kept for continuity with the 21' arc.
-
[todo]
io/print_floatalways-emit-.0— surface printer always emits.ore/Eso re-lex routes to Float; the runtime printer (printf("%g\n", v)) doesn't, so2.0prints as2(Int-shaped). Asymmetric. Either switch the runtime path to a.0-fallback printer (matching surface) or document the%gcontract in DESIGN.md §"Float semantics" so the LLM-author knowsio/print_float's output is for-humans not round-trip.- context:
docs/specs/2026-05-10-fieldtest-floats.mdfinding F1.
- context:
-
[todo] Rustdoc warning sweep —
cargo doc --no-depsreports 16 pre-existing warnings (15 inailang-check, 1 inailang-core: private-item links from public doc, unresolved intra-crate links). All predate the design-md-consolidation milestone; treat as a one-off sweep.- context: JOURNAL 2026-05-10 ("Audit close: design-md-consolidation").
-
[todo]
design_schema_drift.rsfidelity widening — current test checks anchor presence anywhere in DESIGN.md; the audit found that[high]schema gaps in §"Data model" are invisible because anchors live in Decision 11 instead. Constrain the test to scan only §"Data model" + ParamMode block, or extract JSON-schema blocks into a machine-readable file the test consumes.- context: JOURNAL 2026-05-10 ("Audit close").
-
[todo] Split
BadCrossModuleTypeRefinto two diagnostics — the current single shape collapses unknown-owner and known-owner / unknown-type-in-owner into one message. The two cases suggest different fixes (add(import <owner>)vs. fix the type name). In the known-owner branch, list the owner's available type defs as candidates the waybare-cross-module-type-reflists candidates from imports.- context: fieldtest 2026-05-11 —
examples/ct_3*.ailexhibits both branches with identical-shape diagnostics.
- context: fieldtest 2026-05-11 —
-
[todo] Workspace search beyond entry-module's directory —
load_workspaceonly finds sibling.ail.jsonfiles in the same directory as the entry module, so any consumer of prelude/std in a subdirectory has no way to resolve cross-module imports. Add either a--workspace-rootflag onail check/ail build/ail run, or upward-search from the entry module's directory. Alternatively ratify the flat-workspace assumption in DESIGN.md if intentional.- context: fieldtest 2026-05-11 — fieldtest fixtures could not be
placed under
examples/fieldtest/because of this; predates the canonical-type-names milestone but surfaces every time.
- context: fieldtest 2026-05-11 — fieldtest fixtures could not be
placed under
-
[todo]
check_in_workspaceper-module overlay narrowing —crates/ailang-check/src/lib.rs:1234still clears+rebuildsenv.ctor_indexper-module; ct.3.2 narrowed the analogous mono overlay to types-only. The typecheck-side overlay'senv.ctor_indexhalf serves the duplicate-detection diagnostic at workspace-build time, not the runtime ctor lookup (which is type-driven post-ct.2.2). Narrowing is mechanical but needs a careful read to confirm no other consumer survives.- context: JOURNAL 2026-05-11 ("Iteration ct.4") — milestone close
follow-up; closed by iter ctt.1 — recon confirmed the rebuild is the load-bearing consumer of in-band DuplicateCtor (pinned by
crates/ailang-check/tests/duplicate_ctor_pin.rs); the asymmetry with the mono side is intentional.
- context: JOURNAL 2026-05-11 ("Iteration ct.4") — milestone close
follow-up; closed by iter ctt.1 — recon confirmed the rebuild is the load-bearing consumer of in-band DuplicateCtor (pinned by
P3 — Ideas
-
[todo]
compare_primitives_smoke.ailcounterpart — the canonical happy-path exhibit for canonical-type-names ships only as JSON. Per Decision 6, Surface is the LLM-author surface; the milestone should have a.ailcounterpart. Two paths: authorexamples/compare_primitives_smoke.ailto round-trip into the existing JSON, OR retire the JSON fixture in favour ofexamples/ct_1_ordering_signum.{ail,ail.json}as the new canonical happy-path exhibit.- context: fieldtest 2026-05-11 (spec_gap).
-
[todo] Codegen
lookup_ctor_in_patterntype-anchoring —crates/ailang-codegen/src/lib.rs:1790still walks every module's ctor_index by bare ctor name. Plumbing the scrutinee's qualifiedType::Conthrough pattern lowering would type-anchor it symmetric to the ct.2.2 typecheck-side fix. Not load-bearing (uniqueness is enforced at typecheck), but cleaner.- context: JOURNAL 2026-05-11 ("Iteration ct.3" + ct.4 close).
-
[todo]
compare_primitives_smokeIR-shape assertion — observecompare__Int/compare__Bool/compare__Strsymbols in the emitted IR. Blocked onemit-irCLI not running mono; resolution paths include extending the CLI to run mono, using library APIs directly in e2e.rs, or adding--dump-irtoail build. The E2E stdout assertion already covers correctness; the IR-shape test would catch refactor regressions that rename mono symbols.- context: JOURNAL 2026-05-11 ("Iteration ct.4") — dropped from ct.4.4 when the BLOCKED condition surfaced.
-
[idea] Latency methodology rework — switch from per-run timing to a histogram-based approach so tail-latency regressions are visible without re-running. Queued from 21'g.
-
[idea] Parser-test backfill for 22b.4a-era duplicate-clause sites (class × 3, class method × 2, instance × 3, instance method × 1). No regression pin today; only worth it if a 22b.4a-era diagnostic needs to change.
- context: JOURNAL 2026-05-10 ("Iteration 22-tidy.7")
-
[idea]
write_typeType::Forallarm incrates/ailang-prose/src/lib.rssilently drops constraints in inline-type rendering. Dormant — surface forms today only carry forall at fn-signature top level. Fix only if a future feature carries forall + constraints inline.- context: JOURNAL 2026-05-10 ("Iteration 22-tidy.6")
-
[idea] Richer integration paths between RC and uniqueness — deferred from the 21' arc; revisit once the uniqueness inference covers more program shapes.