# iter bugfix-mono-cursor-print-with-class-method-arg — `(app print (app eq …))` no longer rewrites the inner class-method to a stale `Show T` symbol

**Date:** 2026-05-14
**Started from:** 05e4c04e3ba74f3382216ff3ea285e3fb1e3a45d
**Status:** DONE
**Tasks completed:** 1 of 1

## Summary

The iter 24.3 `synth` Var-arm pushes BOTH a class `ResidualConstraint`
for each declared constraint AND a `FreeFnCall` observation at the
same poly-free-fn `Var` site (`crates/ailang-check/src/lib.rs` ≈ 2908–
2966). The two mono walkers in `crates/ailang-check/src/mono.rs`,
however, were each consuming exactly one slot per `Var`: at a
poly-free-fn `Var` they popped one `free_fn_slot` and zero
`class_slot`s. Every constraint on a poly-free-fn-with-constraints
left a leftover class slot, so the next class-method `Var` in the
same body consumed the wrong slot — the residual that belonged to
`print`'s `Show T` constraint got cursor-aligned with the inner `eq`
`Var`, and codegen reported `call prelude.show__Bool arg type
mismatch: expected i1, got i64`.

The fix advances both walkers' cursors by `1 + N` at a poly-free-fn
`Var` whose source `Type::Forall` carries `N` class constraints. A
new sibling helper `poly_free_fn_constraint_counts_for_module`
mirrors `poly_free_fn_names_for_module`'s three-source spelling
contract (same-module / implicit-import bare / dot-qualified
`alias.name`) and produces a `BTreeMap<String, usize>` from synth-
visible name to declared-constraint count. The map is threaded into
the rewrite-phase loop alongside `poly_free_fns` and passed to both
`rewrite_mono_calls` and `interleave_slots`.

In `interleave_slots`, a poly-free-fn `Var` now pushes the `FreeFn`
slot first (this is what the rewrite walker reads for the rename),
then `N` filler entries drawn in order from `class_slots` (consumed
only to keep `class_cur` aligned). In `rewrite_mono_calls`, the
`Var`-arm captures `n_filler` from the count map BEFORE the rename
mutates `name` (lookup keys are the synth-visible spelling), reads
the slot at `*cursor` as before, then advances by `1 + n_filler`.
Class-method `Var`s stay at advance-by-one (synth pushes exactly one
residual and no `FreeFnCall`).

## Per-task notes

- task 1: write/verify the cursor-alignment fix.
  - Reproduced RED at `print_with_class_method_arg_does_not_misalign_mono_cursor`
    with the exact failure mode stated in the carrier:
    `call prelude.show__Bool arg type mismatch: expected i1, got i64`.
  - Added `poly_free_fn_constraint_counts_for_module` helper
    immediately after `poly_free_fn_names_for_module`; identical
    name-source contract, returning constraint counts instead of a
    presence set.
  - Threaded `poly_free_fn_ccounts: &BTreeMap<String, usize>` into
    `collect_residuals_ordered`, `interleave_slots`, and
    `rewrite_mono_calls` (signatures + every recursive call site).
  - `interleave_slots::Term::Var` poly-free-fn branch: after pushing
    the `FreeFn` slot, drain `N` entries from `class_slots` and push
    them as fillers in `out`, advancing `class_cur` by `N`.
  - `rewrite_mono_calls::Term::Var`: compute `n_filler` from the
    count map before the rename mutation, then `*cursor += 1 +
    n_filler`. Class-method `Var`s are guarded with `if
    is_poly_free_fn { … } else { 0 }`.
  - RED `print_with_class_method_arg_does_not_misalign_mono_cursor`
    flips to GREEN with stdout `false` as predicted by the fixture
    docstring.
  - Full `cargo test --workspace` passes 564 / 564 (= 563 baseline
    from `clippy-sweep` + the 1 new mini-mode RED). Zero
    regressions across any of the existing show / mono / typeclass
    test suites.

## Concerns

(none)

## Known debt

(none — the constraint set is a single new sibling helper plus a
new threaded argument; the two-walker symmetry remains the invariant
the existing comments already document.)

## Files touched

- `crates/ailang-check/src/mono.rs` — the fix (helper + two walker
  signatures + Var-arm cursor advancement + recursive-call
  threading).
- `crates/ail/tests/show_print_e2e.rs` — RED pin
  `print_with_class_method_arg_does_not_misalign_mono_cursor`
  (committed by `/debug` upstream of this iter; flips RED → GREEN
  here).
- `examples/print_eq_arg_repro.ail` — RED fixture (committed by
  `/debug` upstream; consumed by the pin).

## Stats

bench/orchestrator-stats/2026-05-14-iter-bugfix-mono-cursor-print-with-class-method-arg.json
