Repository navigation
feat(ts): collect into and iterate a crate's own collections through std's adaptors - #592
Conversation
Quest-Claim: d89718ab643757e7
…std's adaptors std's `collect` into the crate's own `FromIterator` type, and into a `Result` or `Option` of one, calls its `from_iter`; `flat_map`, `flatten`, `chain`, `zip`, `extend`, and the rest that take an `IntoIterator` iterate the crate's own collection by its `into_iter`. Drops moq-net model's census from 78 to 71. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…'s does std's `GenericShunt::next` reads on after a residual and replaces it, dropping the old one. The runtime's shunts stopped for good at the first, which a crate's own `FromIterator` that reads again can observe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…shot Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…m-iterator # Conflicts: # quest/m2/ts-model/README.md
…m-iterator # Conflicts: # quest/m2/ts-model/README.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
|
quest land watch: the merge queue removed this pull request at 89f73a2 because its The land fixer works on it in the background, and the watcher re-enqueues it at the back of the queue once it is fixed or judged flaky, or hands it back here with what it needs.
…guard(21)));
430 + let _ = counts.entry(counted(20)).or_insert(guard(21));
|
warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing
--> fixtures/task/src/drops.rs:431:2
|
431 | drop(counts.entry(counted(22)).or_insert_with(|| guard(22)));
| ^^^^^------------------------------------------------------^
| |
| argument has type `&mut Guard`
|
help: use `let _ = ...` to ignore the expression or result
|
431 - drop(counts.entry(counted(22)).or_insert_with(|| guard(22)));
431 + let _ = counts.entry(counted(22)).or_insert_with(|| guard(22));
|
warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing
--> fixtures/task/src/drops.rs:432:2
|
432 | drop(counts.entry(counted(20)).and_modify(|_| ()).or_insert(guard(23)));
| ^^^^^-----------------------------------------------------------------^
| |
| argument has type `&mut Guard`
|
help: use `let _ = ...` to ignore the expression or result
|
432 - drop(counts.entry(counted(20)).and_modify(|_| ()).or_insert(guard(23)));
432 + let _ = counts.entry(counted(20)).and_modify(|_| ()).or_insert(guard(23));
|
warning: for loop over an `Option`. This is more readably written as an `if let` statement
--> fixtures/task/src/drops/iters.rs:22:11
|
22 | for g in Some(guard(7)) {
| ^^^^^^^^^^^^^^
|
= note: `#[warn(for_loops_over_fallibles)]` on by default
help: to check pattern in a loop use `while let`
|
22 - for g in Some(guard(7)) {
22 + while let Some(g) = Some(guard(7)) {
|
help: consider using `if let` to clear intent
|
22 - for g in Some(guard(7)) {
22 + if let Some(g) = Some(guard(7)) {
|
warning: `task-fixture` (lib) generated 12 warnings (run `cargo fix --lib -p task-fixture` to apply 1 suggestion)
Finished `differential` profile [optimized + debuginfo] target(s) in 14.33s
Compiling share-fixture v0.0.0 (/var/cache/github-runner-work/rust2/rust2/ts/fixtures/share)
Finished `differential` profile [optimized + debuginfo] target(s) in 13.99s
test stock ... ok
Compiling share-fixture v0.0.0 (/var/cache/github-runner-work/rust2/rust2/ts/fixtures/share)
Finished `differential` profile [optimized + debuginfo] target(s) in 0.26s
Compiling share-fixture v0.0.0 (/var/cache/github-runner-work/rust2/rust2/ts/fixtures/share)
Finished `differential` profile [optimized + debuginfo] target(s) in 0.25s
test share ... ok
test task ... ok
failures:
---- lang::collects stdout ----
thread 'lang::collects' (3006420) panicked at tests/fixtures.rs:135:9:
lang/collects: collects.Bag.ts differs from its snapshot; rerun with UPDATE_EXPECT=1
- const args2: rs.Fmt[] = [(f: rs.Formatter) => rs.usizeDisplay(part, f)];
- const _26: string = rs.fmtFormat(["bag of ", args2[0]]);
- _25.value.items.push(_26);
- rs.refMutRelease(_25);
- }
- return new Bag(items);
- }
-
+ const _26: string = rs.fmtFormat(["bag of ", (f: rs.Formatter) => rs.usizeDisplay(part, f)]);
+ _25.value.items.push(_26);
+ rs.refMutRelease(_25);
+ }
+ return new Bag(items);
+ }
+
+ export function fromIter$iter_FromIterator_collects_Item_iter_Map_iter_Rev_slice_Iter_u8_collects_chains_closure2(iter: rs.Iter<Item.Item>): Bag {
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
lang::collects
test result: FAILED. 87 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 333.27s
error: test failed, to rerun pass `--test fixtures`
error: recipe `test` failed on line 39 with exit code 101
error: recipe `ci` failed on line 28 with exit code 101
##[error]Process completed with exit code 101.
Post job cleanup.
[command]/nix/store/lg46w7hrjx7kylsh6645c9l975i8h43b-git-2.55.0/bin/git version
git version 2.55.0
Temporarily overriding HOME='/var/cache/github-runner-work/_temp/f840b248-666e-4858-85ce-d6ed96331ae3' before making global git config changes
Adding repository directory to the temporary git global config as a safe directory
[command]/nix/store/lg46w7hrjx7kylsh6645c9l975i8h43b-git-2.55.0/bin/git config --global --add safe.directory /var/cache/github-runner-work/rust2/rust2
Removing SSH command configuration
[command]/nix/store/lg46w7hrjx7kylsh6645c9l975i8h43b-git-2.55.0/bin/git config --local --name-only --get-regexp core\.sshCommand
[command]/nix/store/lg46w7hrjx7kylsh6645c9l975i8h43b-git-2.55.0/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :"
Removing HTTP extra header
[command]/nix/store/lg46w7hrjx7kylsh6645c9l975i8h43b-git-2.55.0/bin/git config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader
[command]/nix/store/lg46w7hrjx7kylsh6645c9l975i8h43b-git-2.55.0/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :"
Removing includeIf entries pointing to credentials config files
[command]/nix/store/lg46w7hrjx7kylsh6645c9l975i8h43b-git-2.55.0/bin/git config --local --name-only --get-regexp ^includeIf\.gitdir:
[command]/nix/store/lg46w7hrjx7kylsh6645c9l975i8h43b-git-2.55.0/bin/git submodule foreach --recursive git config --local --show-origin --name-only --get-regexp remote.origin.url
A job completed hook has been configured by the self-hosted runner administrator
##[group]Run '/nix/store/gx2v6q84b0w43bafm0whkdx93qyxbpps-ci-cache-gc.sh/bin/ci-cache-gc.sh'
shell: /nix/store/1mv3qz005gkbalxfghk4y3s8ayv4d2dl-bash-interactive-5.3p15/bin/bash --noprofile --norc -e -o pipefail {0}
##[endgroup]
evicted 18 objects and 0 action results (20.3 MiB logical); 50.0 GiB logical remain
dropped 1 stale checkout records
dropped 1 session event streams
Cleaning up orphan processes
Current runner version: '2.338.2'
##[group]Runner Image Provisioner
Hosted Compute Agent
Version: 20261021.618
Commit: 21505ad2541d5be6135ed84fc33697146cf75b8e
Build Date: 2026-10-21T00:45:21Z
Worker ID: {e8cee5d3-91fa-4e23-85ee-37eef4e2b128}
Region: westcentralus
Cloud: Azure
##[endgroup]
##[group]Operating System
Ubuntu
24.04.5
LTS
##[endgroup]
##[group]Runner Image
Image: ubuntu-24.04
Version: 20261025.353.1
Included Software: https://github.com/actions/runner-images/blob/ubuntu24/20261025.353/images/ubuntu/Ubuntu2404-Readme.md
Image Release: https://github.com/actions/runner-images/releases/tag/ubuntu24%2F20261025.353
##[endgroup]
##[group]GITHUB_TOKEN Permissions
Contents: read
Metadata: read
##[endgroup]
Secret source: Actions
Cache mode: write
Prepare workflow directory
Prepare all required actions
Complete job name: Queue
##[group]Run [[ "$RESULT" == success ]] || { echo "::error::the queue build ended $RESULT" >&2; exit 1; }
�[36;1m[[ "$RESULT" == success ]] || { echo "::error::the queue build ended $RESULT" >&2; exit 1; }�[0m
shell: /usr/bin/bash -e {0}
env:
RESULT: failure
##[endgroup]
##[error]the queue build ended failure
##[error]Process completed with exit code 1.
Cleaning up orphan processes
(written by quest land watch) |
|
codex / Codex land fixer note:
(written by codex / Codex) |
|
quest land watch: armed auto-merge on this pull request at ae2e09f, so it joins the back of the merge queue once its required checks pass, with the land fixer's fix ( (written by quest land watch) |
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — this run reviewed commit range 8cd50cef..89f73a2d (23 files, +1486 -28): the translator stops refusing collect/flat_map/flatten through a crate's own FromIterator/IntoIterator, and makes the runtime's Result/Option shunts read on like std's GenericShunt.
- New
own_implresolution gate (ts/src/lower/iter.rs:520): resolves std'sFromIterator/IntoIteratordiagnostic fns viaInstance::try_resolve, refuses overhas_param() || has_aliases()(an established idiom indrop.rs/glue.rs), and requiresb.t.ownof the resolved impl'sdef_id, called throughb.fn_value. The three call sites wire it intocollect(raw receiver passed, as std'scollectpassesself), MIRFromIterator::from_iter, andpeeled_into_iter, and instance args[Self, A, T]are in the right order at each. - Shunt parity with std (
ts/runtime/rs/iter.ts):ResultShunt/OptionShuntdrop their after-error latch, so a consumer reading again reads on, and a later error replaces the earlier one (dropped by the newdropErrorparameter ofiterCollectResult). This matches upstream std exactly, verified againstlibrary/core/src/iter/adapters/mod.rs:GenericShuntstoresresidual: &'a mut Option<R>so replacing drops the earlier residual, has no latch, and reportssize_hint(0, Some(0))once a residual is seen. - Differential fixture
lang/collectscovers theflat_mapdrop of a crate iterator,collectthat stops early and drops its residual source,Result/Optioncollects including one whose collection reads past the residual (the round-1GenericShuntfix), the genericStack, the crate's own iterator by value andby_ref, andchain/zip/extendof the crate's collections. The generated expected snapshots (committed in the diff) place theGenericShuntinstantiations and thedropErrorargument where std would. - Quest docs:
quest/m2/ts-model/README.md's census moves 69 → 82 refusals at the pin, and thefrom-iteratorquest deletes.
What I verified on head 89f73a2, beyond reading:
GenericShuntparity above against rust-lang/rust master sources (fetched and quoted locally, not from memory).lang::collectspasses locally:cargo test --locked --test fixtures lang::collects(translates, typechecks, and differential-matches native Rust).- Both census claims, reproduced at pin
ffcb7cdagainst the branch and againstorigin/main(a392514): model 93 → 82, and the normalized refusal-site sets differ by exactly the 11collect/flat_map/flattenrefusals (inmodel/origin.rs,model/subscription/runs.rs,auth.rs,moq-pattern'spatterns.rs, and kio'sSmallVeccollect) with no new ones; moq-net as a whole 434 → 409. Both counts are what the PR body and the quest README state. - A
reviewfrogpass hunting for other std-generic paths that instantiate a crate's ownFromIterator/IntoIteratorfound none left unsound after this PR:sum/product,partition,unzip,String/Cowcollects, and box/ref/&mutreceivers of the newcollectbranch either resolve to the crate's impl through the same gate or refuse loudly atbody.rs's error path. Its one latent note (an own type that is both an ownIteratorand has a customIntoIterator) is a Rust coherence impossibility, so unreachable. cargo clippy --locked --all-targetsints/is clean. CI (merge queue) had not started at review time.
(Written by glm-5.3-flash)
glm-5.3-flash | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — this run reviewed only the two commits since the last pullfrog review of 89f73a2d: 3a87d2fb merges base (main, fc56c13d) into the branch, and ae2e09fd regenerates the six lang/collects snapshots against it.
- Merge of
base:lang::collects's generated snapshots now reflect main's newer fmt-args lowering (formatters inlined straight intofmtFormat/panicFmtcalls; plain objects instead of a labeled field for part-of-tuple uses). Pure generated output; the diff carries no source or runtime change. test(ts): regenerate collects snapshots against base: exactly the mechanicalUPDATE_EXPECT=1regen the merge requires, six files (+46 -86).
Verified on head ae2e09fd: cargo test --locked --test fixtures lang::collects passes (translate + tsc + differential against native Rust), which is both the snapshot check and the semantic check for anything the merged base could have disturbed. The GenericShunt/collect/flat_map lowering reviewed last round is untouched (ts/src/lower/iter.rs and ts/runtime/rs/iter.ts are unchanged in the delta), and the census in the quest README was counted at the old head only for the changes this delta does not touch, so it still describes the branch's lowering.
(Written by glm-5.3-flash)
glm-5.3-flash | 𝕏

Problem
std's iterator adaptors refused a crate's own collection:
collectinto a type with its ownFromIterator, andflat_map/flattenover a type with its ownIntoIterator. moq-net's model reaches these through moq-pattern'sPatterns(auth.rs,model/origin.rs,Patterns::rebase), rangemap'sRangeInclusiveSet(model/subscription/runs.rs), and smallvec'sSmallVec(kio'slog.rs).Approach
rs.Itermappings already exist for every adaptor; what was missing is std's generic code calling the crate's impl.collectinto the crate's own collection calls itsfrom_iter, instantiated for the receiver's type, with the receiver itself, as std'scollectdoes. Acollectinto aResultorOptionof one hands it theGenericShuntstd'stry_processdoes, which is anrs.Iter.into_iterof a crate's own collection calls itsinto_iterand iterates what that returns. That one place covers every adaptor taking anIntoIterator:flat_map,flatten,chain,zip,Vec::extend, andFromIteratorof std's collections.fn_value, so a binding or#[track_caller]impl is handled as anywhere else.Result/Optionshunts now read on past anErrorNone, as std'sGenericShunt::nextdoes, and a laterErrreplaces the earlier one, which then drops. Before this PR only std's collections read a shunt, and they stop at the firstNone. A crate'sfrom_itercan read again. That is whyiterCollectResultnow takes the error's dropper, and thetasksnapshot shows the extra argument.New fixture
lang/collectsruns against native Rust (505 cases, 0 differences). Its items log as they are made, read, and dropped, so the log shows laziness and drop order. It covers:collectthat stops early, leaving the rest of its source to drop;ResultandOptioncollects, including a collection that reads past the residual; a generic collection; a crate iterator by value and byby_ref;flat_mapread part way and thennext_back;flattenby value and by reference;flat_mapinto a type whose iterator is the crate's own and drops; andchain,zip, andextend.I mutation-tested it by editing the translated output and runtime by hand. Each mutation failed the run:
flat_mapResult's collection after anErrcollectsource&BagiteratorErrErrNoneCensus of
ts/moq/model.tomlat the current moq pin (ffcb7cd, bumped by #390): origin/main's driver counts 93 refusals and this branch counts 82, with exactly the 11 collect/flat_map/flatten refusals gone and no new ones. moq-net as a whole goes from 434 to 409. The epic now says 82; its old 69 was counted at the previous pin. Programs that don't use this translate as before: every other snapshot is unchanged buttask's extra argument, andjust ts moqpasses.Impact
FromIterator/IntoIteratortype, which translation used to refuse.rs.iterCollectResulttakes an optional error dropper.Alternatives
Iterator::collect/FlatMapMIR instead of thers.Itermappings: every other adaptor is mapped, and std's bodies here go through specialization andGenericShuntinternals.Follow-ups
util::idle::Idle'sOption<K>field asOption<()>(16), arrayvec'sArrayString(const generics,begin_panic,str::as_ptr),Weak::as_ptr,thread::yield_now, andBox::new_uninit_slice. The epic's breakdown of what remains predates the bump. Worth a/quest-planpass.Review
mechanical fix by codex / Codex:
Merged base and regenerated six stale collects snapshots; passed in ts/ on pinned nightly: UPDATE_EXPECT=1 cargo test --locked --test fixtures lang::collects -- --exact; cargo build --locked; cargo test --locked; tsc -p runtime.(head ae2e09f)Codex (
quest review), gpt-6.1-sol, medium effort:Triescollection inlang/collectsand verified by mutation.🤖 Generated with Claude Code