Skip to content

feat(ts): translate Debug of std's iterator adaptors and a str's escapes - #515

Merged
kixelated merged 20 commits into
mainfrom
quest/m3/ts-iter-adaptor-debug
Nov 3, 2026
Merged

kixelated merged 20 commits into
mainfrom
quest/m3/ts-iter-adaptor-debug

Conversation

@kixelated

@kixelated kixelated commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Debug of std's iterator adaptors (Map, Filter, Enumerate, Zip, Chain, Peekable, Skip, Take, StepBy, Flatten, FlatMap, DecodeUtf16, and the rest) failed as "unsupported call", and so did Debug of a str's escapes, which #514 added to this quest. Closes the quest quest/m3/ts-iter-adaptor-debug.md.

Approach

  • Lowering (adaptor_debug in ts/src/lower/fmt.rs): each adaptor maps to one runtime function, given the Debug of each iterator it wraps, built by the same fmt_fn path for the type iter::peel_iter holds it as, so an adaptor over an unmapped iterator is refused at its span. Zip writes bare Zip where both sides are TrustedRandomAccessNoCoerce, as std's specialization does. Flatten/FlatMap read their FlattenCompat's types from rustc's field types. A str's escapes write Name { inner: FlatMap { .. } }, matching nightly's std.
  • Runtime (rt/iter.ts, rt/char.ts): tree-shakable fmtAdaptor, fmtEnumerate, fmtCounted, fmtFlagged, fmtScan, fmtPeekable, fmtStepBy, fmtChain, fmtZip, fmtCycle, fmtFuse, fmtFlatten, fmtAround, and fmtDecodeUtf16 read the state each class already keeps (Skip's and Take's n, Peekable's peeked item, Chain's dropped halves, and so on). rt.iterHeld reads an adaptor's field as Rust holds it, through the Box/&mut forwarding wrappers and an own iterator's iterFrom source.
  • State fidelity fixes, since Debug exposes them:
    • fused is now exactly FusedIterator, as std's Fuse keeps such an iterator (Some(..)) rather than dropping it. This is most of the snapshot churn (false becomes true in iterFlatten/iterFlatMap/iterFuse calls).
    • std specializes StepBy<Range<u8 | u16 | u32 | usize>> on wasm32 to count down the range's end. The new RangeStepBy class mirrors that, so StepBy { iter: 6..47, .. } matches.
  • Tests: a new fmt::adaptors case in the shapes fixture covers each adaptor plain and {:#?}, after partial reads from either end. It also covers nested adaptors, {:x?}, both Zip forms, both Fuse forms, the specialized range steps with wraparound, adaptors over by_ref(), Box, and crate-own iterators (a fieldless enum through &mut, &mut &mut, &mut Box, Box<&mut>, and Box<&mut Box>, and a struct through Box<Box> and &mut &mut Box<Box>), and the three str escapes. All run differentially against native wasm32.

Impact

  • Translator output: Debug of the adaptors above and of a str's escapes now translates. iterFlatten, iterFlatMap, and iterFuse get fused = true for every FusedIterator. step_by of a small unsigned Range passes the integer's greatest to rt.iterStepBy.
  • Runtime (additive): the fmt* functions above, rt.iterHeld, and rt.iterStepBy's optional max. The no-into overloads of rt.iterFlatMap and rt.iterFlatten also accept fused, size, and oneShot. Nothing breaking, so no MIGRATE.md entry.

Alternatives

  • Generic lowering that reads rustc's field list and the runtime classes' fields by name. Dropped: it couples generated code to runtime internals, and it can't express Peekable's or Chain's Options in the runtime's representation.
  • debug methods on each iterator class, like clone. Dropped for tree-shaking: free functions cost nothing in bundles that never format an adaptor.

Follow-ups

  • quest/m3/ts-iter-source-debug.md: Debug of Once, Repeat, FromFn, an array's IntoIter, Option's iterators, and std's other iterators (an adaptor over one is refused at its span today).
  • quest/m3/ts-own-iter-value.md: toggle.map(f), a fieldless enum iterator of the crate's own taken by value, fails to type-check whether or not anything formats it.

Decision

The maintainer approved taking the Debug type of each wrapped iterator from iter::peel_iter, the function that decides how the adaptor holds it. Review rounds 2 to 4 had each found a case where a separate hand-written walk in the Debug lowering disagreed with it (an own value-typed iterator under &mut, &mut &mut, and &mut Box). That walk is deleted, so the two cannot drift. Pin and Rc are not iterators in std, so no adaptor can wrap them. The rejected alternatives were to merge with the boxed case recorded as a follow-up quest, or to refuse adaptors over the crate's own iterator behind a reference.

Review

  • Reviewer: Codex gpt-6.1-sol, medium effort, via quest review. Round 5 reviewed head b504eb170278cf8a66bcdb84db15bd87952a5c57.
  • Round 1: two findings, both fixed. Boxed and nested wrappers now unwrap through rt.iterHeld. The identity Copied over by_ref() now goes through rt.fmtAround.
  • Round 2: an own fieldless-enum iterator under &mut was read as its value instead of its Place. Fixed.
  • Round 3: the same under &mut &mut. Fixed.
  • Round 4: the same under &mut Box<_>. Fixed at its source: see Decision.
  • Round 5: clean.
  • After round 5, origin/main was merged five times. The only conflict was a generated snapshot (lengths.ts), regenerated; it and main's new clones snapshot differ from main only by the exact fused flag. No further round was needed.

Checks

just ci passed on a0a2d515. The pushed head e230f3f9 adds only main's quest-plan commits (#530, #531), and its quest tree lints clean.

🤖 Generated with Claude Code

kixelated and others added 12 commits November 3, 2026 02:01
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nts at

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Debug of a str's escapes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…h the place of a value

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…fused flag

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title Debug of std's iterator adaptors feat(ts): translate Debug of std's iterator adaptors and a str's escapes Nov 3, 2026
kixelated and others added 4 commits November 3, 2026 06:16
The Debug lowering kept its own copy of how references and boxes peel to the
iterator, which dropped the place of a `&mut Box` to the crate's own iterator.
It now reads the type `peel_iter` gives, and the fixture covers the boxed and
borrowed orders std forwards through.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated marked this pull request as ready for review November 3, 2026 14:52
@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 39 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 84acbada-372b-4a13-be13-7984a46b8cf6
Commits

Reviewing files that changed from the base of the PR and between 404992c and e230f3f.

Files selected for processing: 45
  • quest/m3/README.md
  • quest/m3/ts-iter-adaptor-debug.md
  • quest/m3/ts-iter-source-debug.md
  • quest/m3/ts-own-iter-value.md
  • ts/README.md
  • ts/fixtures/lang/arrays/expected/arrays.ts
  • ts/fixtures/lang/boxes/expected/boxes.ts
  • ts/fixtures/lang/cells/expected/cells.ts
  • ts/fixtures/lang/chars/expected/chars.ts
  • ts/fixtures/lang/clones/expected/clones.ts
  • ts/fixtures/lang/collections/expected/collections.ts
  • ts/fixtures/lang/cycles/expected/cycles.ts
  • ts/fixtures/lang/edits/expected/edits.ts
  • ts/fixtures/lang/elements/expected/elements.ts
  • ts/fixtures/lang/ends/expected/ends.ts
  • ts/fixtures/lang/folds/expected/folds.ts
  • ts/fixtures/lang/heap/expected/heap.ts
  • ts/fixtures/lang/hints/expected/hints.ts
  • ts/fixtures/lang/holds/expected/holds.ts
  • ts/fixtures/lang/iters/expected/iters.ts
  • ts/fixtures/lang/keys/expected/keys.ts
  • ts/fixtures/lang/lengths/expected/lengths.ts
  • ts/fixtures/lang/orders/expected/orders.ts
  • ts/fixtures/lang/refs/expected/refs.ts
  • ts/fixtures/lang/results/expected/results.ts
  • ts/fixtures/lang/searches/expected/searches.ts
  • ts/fixtures/lang/shapes/expected/core/bool.ts
  • ts/fixtures/lang/shapes/expected/fmt.Countdown.ts
  • ts/fixtures/lang/shapes/expected/fmt.Toggle.ts
  • ts/fixtures/lang/shapes/expected/fmt.ts
  • ts/fixtures/lang/shapes/expected/lib.ts
  • ts/fixtures/lang/shapes/src/fmt.rs
  • ts/fixtures/lang/shapes/src/lib.rs
  • ts/fixtures/lang/slices/expected/slices.ts
  • ts/fixtures/lang/sorts/expected/sorts.ts
  • ts/fixtures/lang/strs/expected/strs.ts
  • ts/fixtures/lang/tuples/expected/tuples.ts
  • ts/fixtures/lang/zeros/expected/zeros.ts
  • ts/fixtures/share/expected/harness.ts
  • ts/fixtures/task/expected/drops.ts
  • ts/fixtures/task/expected/drops/indexed.ts
  • ts/runtime/rt/char.ts
  • ts/runtime/rt/iter.ts
  • ts/src/lower/fmt.rs
  • ts/src/lower/iter.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.

@kixelated
kixelated enabled auto-merge November 3, 2026 15:03
@kixelated
kixelated added this pull request to the merge queue Nov 3, 2026
Merged via the queue into main with commit 2283c19 Nov 3, 2026
5 checks passed
@kixelated
kixelated deleted the quest/m3/ts-iter-adaptor-debug branch November 3, 2026 15:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant