All 176 files in the four accumulating directories now use a zero-padded 4-digit counter prefix that reflects creation order (`NNNN-slug.md`). The counter is assigned per directory in strict git-log creation order; ties broken alphabetically by original name. The old `YYYY-MM-DD-` prefix on docs/specs/ and docs/plans/ files is dropped — the date is recoverable from git log and the counter carries the ordering. A file's counter is stable for the life of the file: never reassigned, never reused, never compacted. Deleted files retire their counter; subsequent files do not fill the gap. This is the property that lets cross-references stay literal — refs use the full filename including the counter (`design/contracts/0007-honesty-rule.md`) so they grep cleanly and resolve directly without a glob step. 313 cross-references updated across .md/.rs/.toml/.c/.json files (test pins, include_str! paths, design-INDEX entries, baseline notes, runtime C comments, inter-contract markdown links incl. bare basename and `../models/foo.md` forms). CLAUDE.md gets a new "File-naming convention" section spelling out the rule and rationale. skills/brainstorm/SKILL.md and skills/planner/SKILL.md updated so new spec/plan creation produces counter-prefixed names from the start. The full test suite (cargo test --workspace) passes.
28 KiB
24 — Show + print rewire (post-mq re-derive) — Design Spec
Date: 2026-05-13
Status: Draft — awaiting user spec review
Authors: Brummel (orchestrator) + Claude
Supersedes: docs/specs/0022-24-show-print.md for iters 24.2 +
24.3 only. The earlier spec stays as historical context for the
deferral rationale; iter 24.1 shipped against the earlier spec at
f38bad8 and is unchanged. This document re-derives 24.2 + 24.3 from
scratch against the post-mq architecture (commits 0eb3323 mq.1 →
2e6a4ca mq.2 → 99d3968 mq.3 → 1b6cbcb mq.tidy).
Goal
Close the prelude story opened by milestone 23 (Eq/Ord) by shipping:
- The
Showtypeclass with single methodshow : (a borrow) -> Strin the prelude module. - Four primitive instances:
prelude.Show Int,prelude.Show Bool,prelude.Show Str,prelude.Show Float. - A polymorphic free fn
print : forall a. Show a => (a borrow) -> () !IOin the prelude module that routes throughshowandio/print_str, replacing the ad-hoc per-type print idiom for new code.
The runtime + codegen primitives bool_to_str and str_clone already
shipped in iter 24.1 at f38bad8. No runtime work in this re-derive.
Existing per-type effect-ops io/print_int|bool|float STAY. Retiring
them and migrating the example corpus (~86 fixtures) is queued as a
separate P2 follow-up, unchanged from the original spec.
The post-mq architecture changes two things compared to the original spec:
-
Dispatch routing. mq.2 / mq.3 installed type-driven method dispatch with a 5-step rule (qualifier → singleton → type-driven filter → constraint-driven filter → Multi). The original spec predicated routing on a workspace-global
MethodNameCollisionpre-pass that has been retired. The new dispatch routesshowcalls insideprint's body via the constraint-driven filter (Step 4 of the dispatch rule) —Show ainprint's declared constraints pins the candidate class toprelude.Show. -
Existing fixture corpus collides at the class name "Show". Pre-mq, user-side
class Showdeclarations in 14 test fixtures (examples/test_22b{1,2,3}_*.ail.json) were the onlyShowin their workspaces. Post-mq, shippingprelude.Showmakes those user-Show classes coexist with the prelude one — and because the user-Show methods carry the same method name (show), the same arg-type shape ((a) -> Str), AND the same instance head-type forInt, the type-driven filter (Step 3) cannot discriminate at bare call sites. Everyshow xin those fixtures would become Multi-ambiguous and require an explicit qualifier. Migration is part of iter 24.2; the strategy is "rename toTShow/tshow", analogous to the existingTEq/teq,TOrd/tlttest-internal class-name convention that pre-empts identical collisions withprelude.Eq/prelude.Ord.
Architecture
Three artefacts, in dependency order; iter 24.1 already shipped the two runtime primitives.
1. class Show + four primitive instances in prelude.ail.json
The prelude module name is literally "prelude". Per the mq.1
canonical-form rule, intra-prelude class refs are bare; cross-module
refs (from user instance / constraint defs) carry the
"prelude.Show" qualifier.
examples/prelude.ail.json gains five new top-level defs (one class +
four instances):
// class — same-module, bare name
{ "kind": "class",
"name": "Show",
"param": "a",
"methods": [
{ "name": "show",
"type": {
"k": "fn",
"params": [{ "k": "var", "name": "a" }],
"param_modes": ["borrow"],
"ret": { "k": "con", "name": "Str" },
"effects": []
}
}
]
}
// instance — same-module, bare class ref per mq.1 canonical-form
{ "kind": "instance",
"class": "Show", // bare per mq.1
"type": { "k": "con", "name": "Int" },
"methods": [
{ "name": "show",
"body": { "t": "lam",
"params": ["x"],
"body": { "t": "app",
"fn": { "t": "var", "name": "int_to_str" },
"args": [{ "t": "var", "name": "x" }] } } }
]
}
// instance Show Bool — body invokes bool_to_str
// instance Show Str — body invokes str_clone
// instance Show Float — body invokes float_to_str
Each instance body is a single-application lambda
\x -> <primitive_to_str> x. No codegen intercept (no
try_emit_primitive_instance_body-style hook) is needed because the
four primitives are themselves first-class lowered functions. The mono
pass synthesises show__Int, show__Bool, show__Str, show__Float;
each body is a direct call to the corresponding primitive.
Float is included in Show — unlike Eq/Ord (which exclude Float
because IEEE-754 makes structural equality and total ordering
semantically dubious). Producing a textual representation of a Float
is well-defined modulo the NaN-spelling caveat in DESIGN.md §"Float
semantics" (printf("%g", nan) may emit nan / -nan / NaN);
acceptable for a human-readable Show.
2. print polymorphic free fn
examples/prelude.ail.json gains a sixth new top-level def:
{ "kind": "fn",
"name": "print",
"type": {
"k": "forall",
"vars": ["a"],
"constraints": [
{ "class": "Show", // bare per mq.1
"type": { "k": "var", "name": "a" } }
],
"body": {
"k": "fn",
"params": [{ "k": "var", "name": "a" }],
"param_modes": ["borrow"],
"ret": { "k": "con", "name": "Unit" },
"effects": ["IO"]
}
},
"params": ["x"],
"body": {
"t": "let",
"name": "s",
"value": { "t": "app",
"fn": { "t": "var", "name": "show" },
"args": [{ "t": "var", "name": "x" }] },
"body": { "t": "do",
"op": "io/print_str",
"args": [{ "t": "var", "name": "s" }] }
}
}
The let-binder for show x is explicit. Load-bearing for the
heap-Str RC discipline: the Own heap-Str returned by show x (every
instance allocates) needs a let-binder so drop_symbol_for_binder
fires the heap-Str drop at scope close via the Str carve-out
introduced in eob.1. The original spec marked implicit-vs-explicit
as an open commitment for the 24.3 implementer; this re-derive keeps
the same open commitment — if the desugarer auto-introduces a
let-binder for Term::App in effect-op-arg position, the source form
may be \x -> do io/print_str (show x) with identical post-checker
semantics.
print is a free fn, not a class method. Two reasons (unchanged from
the original spec):
- The body is identical for every
a : Show a— no per-instance variation. A class method with an identical body for every instance would be redundant. - It matches Haskell's Prelude convention (
print :: Show a => a -> IO ()is a free fn) and milestone 23's free-fn pattern (ne/lt/le/gt/ge).
3. Dispatch routing through the mq mechanism
Inside print's body the call is show x. Bare method name; the
post-mq dispatcher (resolve_method_dispatch at synth time,
refine_multi_candidate_residual at discharge time) applies the
5-step rule:
- Qualifier — none (bare).
- Singleton —
Env.method_to_candidate_classes["show"]is a workspace-global index. Post-24.2-migration, no user class ships ashowmethod (the 22b corpus is renamed totshow); the only class withshowisprelude.Show. So the candidate set forshowreduces to{prelude.Show}workspace-globally and Step-2 singleton resolves directly — Steps 3-4 are not exercised for the bareshowinsideprint's body. The constraint-driven filter (below) becomes the load-bearing narrower only if a downstream user later re-introduces their ownclass Showwith a separateshowmethod. - Type-driven filter — narrows by which candidate classes have a
registry entry for the residual type (
Show Intinstance check forprint 42). - Constraint-driven filter —
print's declared constraintShow ais the load-bearing narrower. At the call siteshow xinsideprint's body,x : arigid, and the rigid-var filter installed by mq.tidy's T1 checksdc.class == c && constraint_type_matches(dc.type_, residual.type_). The residual isShow a(the rigid type-var),print's declared constraint isShow a; both match →prelude.Showis the unique resolved class. - Multi — not reached.
At the outer user call site do print 42, the dispatch on print
itself is by name (free fn, single global symbol) and the constraint
Show Int is discharged against the workspace registry which contains
prelude.Show Int. The dispatcher's behaviour mirrors milestone 23's
ne/lt/le/gt/ge at the same level.
4. Migration of 22b-Show user-class fixtures
Pre-mq, 14 test fixtures under examples/test_22b{1,2,3}_*.ail.json
declare a user-side class Show {methods: ["show"]} with arg-type
shape (a) -> Str. Pre-mq, these were the only Show in their
workspaces. Post-prelude.Show shipping, the prelude is auto-loaded
into every workspace per 23.1's check_workspace extension, so every
22b fixture now has TWO classes named Show: prelude.Show and (e.g.)
test_22b1_dup_classmod.Show. Both ship (Int) -> Str instances; the
type-driven filter cannot discriminate at bare show x call sites.
Strategy: rename user-Show → TShow, user-show → tshow, analogous
to the existing TEq/teq (vs. prelude.Eq/eq) and TOrd/tlt
(vs. prelude.Ord/lt) convention. The fixtures' intent is
unchanged (they test class-mechanism: orphan detection, dup detection,
xmod instances, missing-constraint diagnostics) — only the literal
class and method name change.
Mechanical scope:
- ~14 fixture
.ail.jsonfiles:"name": "Show"→"name": "TShow","name": "show"→"name": "tshow","class": "Show"→"class": "TShow","class": "<modname>.Show"→"class": "<modname>.TShow", fn-body"name": "show"→"name": "tshow". BothShow-the-class andshow-the-method get renamed. - 2 Rust test files:
crates/ail/tests/typeclass_22b2.rs(30 Show/show occurrences) +crates/ail/tests/typeclass_22b3.rs(49). Replace"Show"→"TShow"and"show"→"tshow"in expected diagnostic strings.
The migration is a single mechanical pass within iter 24.2. Aborted- attempt risk is low because the change is purely string substitution (no semantic shift).
mq3_two_show_* and mq3_class_eq_vs_fn_eq* fixtures (created during
mq.3) intentionally do NOT migrate. They simulate the
two-Show-coexisting and class-vs-fn-collision shapes that are now
fully supported by the post-mq dispatcher; renaming them away would
defeat their purpose. These fixtures' Show classes are
mq3_two_show_ambiguous_a.Show and mq3_two_show_ambiguous_b.Show,
not user-Show analogues of prelude.Show.
After 24.2 lands, the workspace fixture corpus has zero ambiguous
bare-show call sites: every show x resolves either to prelude.Show
(via constraint-driven filter at user call sites with Show Int-style
constraints OR via instance singleton when only prelude.Show ships
Show-T for the residual T) or to prelude.show / tshow /
mq3_*.Show.show per their explicit qualifiers.
Components (iterations)
| Iter | Status | Scope |
|---|---|---|
| 24.1 | shipped (f38bad8) |
Runtime + codegen for bool_to_str + str_clone. Unchanged from original spec. |
| 24.2 | upcoming | class Show + 4 primitive instances in prelude. Plus the 22b-Show → TShow/tshow migration. examples/prelude.ail.json gains class Show a where show : (a borrow) -> Str and four instance Show <T> defs (Int/Bool/Str/Float). ~14 examples/test_22b*_*.ail.json fixtures and 2 crates/ail/tests/typeclass_22b{2,3}.rs files migrate. DESIGN.md §"Prelude (built-in) classes" amended. Round-trip + mono-synthesis + hash-stability tests; full cargo test --workspace green. |
| 24.3 | upcoming | print polymorphic free fn + E2E + DESIGN.md sync. examples/prelude.ail.json gains fn print : forall a. Show a => (a borrow) -> () !IO. Three new E2E fixtures (positive 4-prim, user-ADT, negative NoInstance). DESIGN.md §"Prelude (built-in) classes" amended to include print; §"Float semantics" gains the Show-Float NaN-spelling cross-reference paragraph. Roadmap P1 "Post-22 Prelude" entry flips to [x]; new P2 entry: "retire `io/print_int |
The milestone closes with the standard audit pipeline.
Data flow
Two trajectories show the routing at work.
print 42 at type Int (user workspace)
- Typecheck of user call site.
printresolves to the polymorphic free fn atprelude.printvia the existing free-fn global-lookup path (prep1 from 23.4). ConstraintShow Intdischarged againstprelude.Show Int(singleton registry hit). - Mono of
print__Int. Body taken fromDef::Fn.body, rigid-var substa → Int. The body walker detects the nestedshow xcall at concreteIntand schedulesshow__Intin the same fixpoint round.show__Intsynthesises frominstance prelude.Show Int's body (\x -> int_to_str x). The synthesisedprint__Intbody is\x -> let s = show__Int x in do io/print_str s. - Codegen.
print__Intlowers as any monomorphic fn. The nestedshow__Int xis a direct call returning Own heap-Str; the let-bindersis RC-tracked at scope close per eob.1's Str carve-out.do io/print_str swalkssasPosition::Borrow; the let-binder's drop fires after the effect-op call returns, emitting@ailang_rc_dec(s_ptr). Stdout:"42\n".
print x at user type IntBox with instance prelude.Show IntBox
- Typecheck. User declares
data IntBox = MkIntBox Intandinstance prelude.Show IntBox(cross-module class ref per mq.1 — the instance lives in the user-type's defining module per Decision 11 coherence). Constraintprelude.Show IntBoxdischarged against the user-module registry entry. - Mono.
print__IntBoxsynthesises with body\x -> let s = show__IntBox x in do io/print_str s.show__IntBoxsynthesises from the user instance body (e.g.\x -> match x with MkIntBox n -> int_to_str n). - Codegen. Lowers normally; ADT-pattern-match plus inner
int_to_strcall produce a heap-Str; outer let-binder drops at scope close.
Error handling
-
NoInstance Show <T>— fired at typecheck whenprintis called on a type without aShowinstance (most commonly a function type, or a user type the author forgot to give an instance for). The diagnostic must cross-reference DESIGN.md §"Prelude (built-in) classes" so the LLM-author immediately learns which types ship with built-in Show. Re-uses the existing 22-era diagnostic infrastructure; only content edit. -
Class qualifier ambiguity at a user call site — does NOT fire in this milestone because the 22b-migration eliminates all current ambiguous
showcall sites. Post-milestone, if a downstream user declares their ownclass ShowAND ships an instance whose head-type collides with a prelude.Show instance head-type, the existing mq.3MultiClassUnresolveddiagnostic fires (already pinned byexamples/mq3_two_show_ambiguous*.ail.json). No new diagnostic shape. -
OrphanInstance Show <UserType>— Decision 11 coherence rule unchanged. User-sideinstance prelude.Show <UserType>MUST live in the user-type's defining module (the prelude is read-only). -
CheckError::Internalfrom mono — if Show-specialisation fails internally, this is a caller-contract violation per the existingmono.rs::synthesise_mono_fnconvention. Mirrors 23.4's free-fn error handling.
Testing strategy
24.2 — class Show + 4 instances + 22b migration
-
Round-trip:
examples/prelude.ail.jsonparses + canonicalises bit-stable after the five new defs land. The existing prelude hash-stability test from milestone 23 stays green (pre-existing Ordering/Eq/Ord/instances/ne/lt/le/gt/geunaffected). -
Mono synthesis (unit test in
crates/ailang-check/src/mono.rs::tests): for a fixture callingshow 1,show True,show "x",show 1.5, assert the post-mono workspace containsshow__Int,show__Bool,show__Str,show__FloatasDef::Fnentries. Bodies are direct calls to the corresponding primitives. -
Dispatch via constraint-driven filter pin (unit test in
crates/ailang-check/src/lib.rs::tests, building on the existingmethod_dispatch_pin.rsstyle): for a workspace withprelude.Showloaded and a userclass TShow {tshow}declared in a user module, assert thatshow x(bare) routes toprelude.Showandtshow x(bare) routes to userTShow. Each method name has exactly one candidate class globally, so Step-2 singleton resolves without needing Steps 3-4. The pin covers the post-22b-migration steady state where user fixtures pick non-Showclass names. -
Hash stability of existing mono symbols:
eq__Int,compare__Str, and the other class-method mono symbols from milestone 23 must produce identical bodies (and identical hashes) under the unified pass after Show defs are added. Pin in the style ofcrates/ailang-core/src/hash.rs's milestone-23 fixtures. -
22b-migration regression check —
cargo test -p ail --test typeclass_22b2 --test typeclass_22b3passes after the rename. Each migrated fixture parses + canonicalises bit-stable.
24.3 — print polymorphic free fn + E2E
-
Positive E2E (
examples/show_print_smoke.ail.json): single fixture exercises all four primitives:fn main = do print 42 -- "42\n" print true -- "true\n" print "hello" -- "hello\n" print 3.14 -- "3.14\n" (libc-dependent)Asserts compile, run, expected stdout. The Float line uses
3.14whose%grendering is stable across all targeted libc versions. -
User-ADT E2E (
examples/show_user_adt.ail.json):data IntBox = MkIntBox Int instance prelude.Show IntBox where show = \x -> match x with MkIntBox n -> int_to_str n fn main = do print (MkIntBox 7)Stdout
"7\n". Confirms mono handles user-definedprelude.Showinstances and thatprintcomposes with them. The qualifierprelude.Showis canonical-form per mq.1 (cross-module class ref from a user-defining module). -
Negative E2E (
examples/show_no_instance.ail.json):fn main = do print id -- id : forall a. a -> a, no Show instanceTypecheck rejects with
NoInstance Show <fn-type>. Diagnostic wording finalised by the implementer; gold-standard test pins the message verbatim post-draft (open commitment carries forward from original spec). -
Mono symbol IR-shape pin: asserts
print__Intbody desugars to\x -> let s = show__Int x in do io/print_str spost-mono. Confirms the let-binder is preserved (not optimised away — load-bearing for the heap-Str RC discipline). -
Round-trip of new fixtures — every E2E fixture parses + canonicalises bit-stable.
-
Bench regression check at milestone close: the three bench scripts exit 0 or audit-ratified per audit-skill convention.
Acceptance criteria
The milestone closes when:
-
24.2 has landed:
examples/prelude.ail.jsoncontainsclass Show a where show : (a borrow) -> Str(bare class name, bare method name, intra-prelude canonical form) and four primitive instances Int/Bool/Str/Float. The mono pass synthesisesshow__Int|Bool|Str|Float. The 22b-Show fixture corpus is migrated toTShow/tshow;cargo test --workspacegreen. DESIGN.md §"Prelude (built-in) classes" amended to include Show with the four instances. -
24.3 has landed:
examples/prelude.ail.jsoncontainsfn print : forall a. Show a => (a borrow) -> () !IOwith the explicit-let body (or implicit-let if the implementer ratifies the surface-form simplification per Open Commitment carryforward). The mono pass synthesisesprint__Int|Bool|Str|Floatfor each call site at a primitive type, plusprint__<UserType>for each user-instance call site. Positive / user-ADT / negative E2E green. DESIGN.md §"Prelude (built-in) classes" listsprintas the polymorphic helper; §"Float semantics" gains the Show Float NaN-spelling cross-reference paragraph. -
Tests pass:
cargo test --workspacegreen; existing milestone 23 prelude fixtures (ne/lt/le/gt/geE2E) unchanged; mq.3 E2E fixtures (mq3_two_show_*,mq3_class_eq_vs_fn_eq*) unchanged. -
Bench regression ratified:
bench/check.py && bench/compile_check.py && bench/cross_lang.pyexit 0 or audit-ratified with journal entry. -
Roadmap update: P1 "Post-22 Prelude — Show + print rewire" entry flips to
[x]. New P2 entry: "Retireio/print_int|bool|floateffect-ops + migrate example corpus toprint".
Out of scope (deferred, with substantive rationale)
Unchanged from the original spec; condensed summary:
- Retiring
io/print_int|bool|float. Queued P2; same call as milestone 23 made for==/eq. io/print_strretirement. Stays — load-bearing insideprint, plus useful as a bypass when an Str is already in hand.bool_to_stras schema-if. Stays as runtime primitive; phi-of-static-Str through drop-elision is not ratified.str_cloneas rc_header bump. Stays as always-copy; runtime static-Str/heap-Str tagging is deliberately not supported post-hs.2.Show Orderinginstance. No demand; user can declare.Showfor ADTs viaderiving. No auto-derivation; substantive feature in its own right.- Higher-kinded Show (
Show [a]). Decision 11 axis 5 excludes higher-kinded class params; LLM-natural pattern is per-type instances. printnewline-free variant. Deferred until a concrete LLM-author pattern demands it.- Operator routing through
Show. No commitment; AILang has no Haskell-style monadic operator surface.
Open commitments (24.2 / 24.3 implementer)
-
printimplicit-let vs. explicit-let — implementer verifies the desugarer's behaviour during 24.3 Task 1; if implicit-let is the realised semantics forTerm::Appin effect-op-arg position, the prelude source form may use the more compact\x -> do io/print_str (show x). Load-bearing property: "the heap-Str returned byshow xhas a tracked let-binder when entering the effect-op call site"; sourcing is surface-level. -
Negative-test diagnostic wording. Implementer drafts the Show-aware
NoInstance Show <T>message; orchestrator reviews in spec-compliance phase. -
22b-migration mechanical-pass scope. Implementer verifies during 24.2 Task 1 that the rename target set is exactly the 14 fixtures surfaced by
grep -l '"name": "Show"' examples/test_22b*_*.ail.jsonplus the twotypeclass_22b{2,3}.rsfiles. If a 22b fixture turns out to useShowas part of a substring (e.g. inside an ADT constructor name like"ShowValue"), the implementer flags and spot-checks rather than blindly sed-ing. (Quick visual scan above shows only class names + method names + cross-module class refs; no constructor-name false positives.) -
mq3 fixture preservation. The 7
mq3_*fixtures created in mq.3 INTENTIONALLY do NOT migrate. Implementer confirms they stay unchanged and continue to pin two-Show-coexisting and class-vs-fn-collision behaviour.
Known costs
-
24.2 prelude additions:
examples/prelude.ail.json+40–50 lines (one class + four instances, JSON shape parallel to existing Eq Int/Bool/Str instances). DESIGN.md amendment ~10 lines. -
24.2 22b-migration: ~14
.ail.jsonfiles (~3-5 string subs each), 2 Rust test files (~80 string subs total). Net LOC change zero (pure rename); review-burden non-trivial because of fixture count. -
24.3 prelude additions + tests:
examples/prelude.ail.json+30 lines (one polymorphic free fn). Three new E2E.ail.jsonfixtures, ~40 lines each. Diagnostic test ~20 lines Rust. DESIGN.md amendments ~20 lines. -
Net code reduction: none. Additive milestone. Reduction comes in the P2 follow-up (~−150 LOC retiring the three per-type effect-ops).
-
Compile-time shift: mono pass gains four instance-method synthesis targets plus one free-fn target per call site. Bounded, expected within bench tolerance; audit-ratified post-24.3.
-
Runtime cost on
print x:x : Int— oneint_to_stralloc (~3-20 bytes) + rc_dec.x : Bool— onebool_to_stralloc (5-6 bytes) + rc_dec.x : Str— onestr_clonealloc + memcpy + rc_dec. Strictly worse thando io/print_str x; redundancy acknowledged.x : Float— onefloat_to_stralloc + rc_dec.
Load-bearing assumptions about current behaviour
Each assumption is something this spec relies on as currently-true.
-
mq.2/.3 dispatcher.
crates/ailang-check/src/lib.rs::resolve_method_dispatchimplements the 5-step rule (qualifier → singleton → type-driven filter → constraint-driven filter → Multi).refine_multi_candidate_residualapplies the discharge-time refinement with the rigid-var type-unification leg added by mq.tidy T1. Bare method names route correctly through both call sites. Pinned bycrates/ailang-check/tests/method_dispatch_pin.rs. -
Inverse method index.
Env.method_to_candidate_classesis populated workspace-globally and is the authoritative source for "which classes declare method M". Pinned bycrates/ailang-check/tests/method_collision_pin.rs. -
class_methodstuple-keyed.class_methodsis keyed by(QualifiedClass, MethodName)post-mq.3 retirement of the global pre-pass; two classes can declare the same method name without collision. Pinned bymq3_class_method_shadowed_by_fn_warning_firesandcrates/ail/tests/mq3_multi_class_e2e.rs. -
mq.1 canonical-form for class refs. Class refs in
InstanceDef.class,Constraint.class,SuperclassRef.superclass, andType::Con.namefollow: bare for same-module,<module>.<Class>for cross-module. Pinned by the in-cratebare_cross_module_class_ref_firesandbad_cross_module_class_ref_firestests incrates/ailang-core/src/workspace.rs(the#[cfg(test)] mod testsblock around lines 2783-2860) plus the on-disk mq.1 fixture corpus (examples/mq1_xmod_constraint_class{,_dep}.ail.json). -
int_to_str,float_to_str,bool_to_str,str_clone— installed inbuiltins.rswithret_mode: Own, lowered inEmitter::lower_appvia direct extern calls, RC-disciplined end-to-end. The latter two shipped in 24.1 atf38bad8. Pinned bycrates/ail/tests/e2e.rs::{int,bool,str_clone}_*_drop_balances_rc_statsplus the builtins-side signature-install tests incrates/ailang-check/src/builtins.rs's#[cfg(test)] mod tests. -
io/print_strlowers to@puts(ptr)and accepts any Str realisation via the heap-Str-compatible consumer ABI per DESIGN.md §"Str ABI". Effect-op args walk inPosition::Borrowper eob.1. -
drop_symbol_for_binderStr carve-out. Emits the correct rc-dec for Str let-binders regardless of static-Str / heap-Str underlying realisation; codegen-time elision ensures static-Str pointers do not reachailang_rc_dec. -
Type::Forallround-trip. Form-A parser + canonicaliser + printer round-tripType::Forallwithconstraintsbit-stable. Pinned by milestone 23'sne/lt/le/gt/geprelude entries. -
Mono pass body walker.
mono.rs::collect_mono_targetsschedules targets for both class-method residuals and polymorphic free-fn calls in one fixpoint pass; pinned by 23.4'scmp_max_smokeproof. -
Auto-loaded prelude.
examples/prelude.ail.jsonis auto-loaded per 23.1'scheck_workspaceextension; new prelude defs are visible to every workspace without explicitimport. The pre-existing"prelude" is reservedloader-side error confirms auto-injection. -
22b user-Show fixtures structurally identical. All 14 target fixtures declare
class Show {methods: ["show"]}with(a) -> Strsignature, and any instance declarations use type-shape that collides with prelude.Show's at the type-driven filter level. Empirical grep above ratifies the structural-identity assumption. -
mq3 fixtures intentionally exercise multi-Show.
mq3_two_show_*andmq3_class_eq_vs_fn_eq*fixtures use Show class names in their own modules deliberately to exercise post-mq dispatch; they do NOT migrate in 24.2.