From 086cf7c406ba2d8114fe737b0e76be61d8bf420f Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Mon, 2 Nov 2026 06:26:50 -0800 Subject: [PATCH 1/3] chore(quest): claim quest/m3/ts-iter-zip.md Quest-Claim: 7c8c5a8f869af738 From fc92b8281b2b9f55bb12096889f8df9e0d2011db Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Mon, 2 Nov 2026 06:50:47 -0800 Subject: [PATCH 2/3] feat(ts): translate std::iter::zip as Iterator::zip The free zip takes each side by IntoIterator, so a &mut to a collection of values JS copies lends its places on either side, as Iterator::zip's argument does. Co-Authored-By: Claude Opus 5.5 --- quest/m3/README.md | 1 - quest/m3/ts-iter-zip.md | 14 - ts/fixtures/lang/expected/arrays.ts | 366 +++++++++++++++-------- ts/fixtures/lang/expected/core/option.ts | 7 + ts/fixtures/lang/src/arrays.rs | 21 +- ts/src/lower/iter.rs | 47 ++- ts/src/lower/mir/call.rs | 3 +- 7 files changed, 302 insertions(+), 157 deletions(-) delete mode 100644 quest/m3/ts-iter-zip.md diff --git a/quest/m3/README.md b/quest/m3/README.md index 5c3286027..7b698a47c 100644 --- a/quest/m3/README.md +++ b/quest/m3/README.md @@ -27,7 +27,6 @@ generic std gap is planned here even when moq never calls it. - [Port the workflow guard to kixelated/quest](/quest/m3/quest-workflow-guard.md) - quest's environment guard parses YAML as this repository's does - [A deque's two slices](/quest/m3/ts-deque-slices.md) - `VecDeque::as_slices` and `{:?}` of a deque's `Iter`, `IterMut`, and `Drain` translate, split where std's are - [Comparing places](/quest/m3/ts-place-compares.md) - `a.iter_mut().eq(&mut b)` and its orderings compare the values places lend -- [std::iter::zip](/quest/m3/ts-iter-zip.md) - the free `zip` translates as `Iterator::zip` does - [std's sorts call their tests in std's order](/quest/m3/ts-sort-order.md) - `slice::sort` and a B-tree's `collect` call `lt` or `cmp` as std's driftsort does past 16 elements - [A B-tree's searches call Ord as std's do](/quest/m3/ts-btree-search-order.md) - a B-tree's lookups and inserts call a key's own `Ord` in std's order and number - [Rc and Arc of a slice](/quest/m3/ts-shared-slices.md) - `Rc<[T]>` and `Arc<[T]>` from a `Vec`, a slice, or an iterator translate diff --git a/quest/m3/ts-iter-zip.md b/quest/m3/ts-iter-zip.md deleted file mode 100644 index 5a2155e09..000000000 --- a/quest/m3/ts-iter-zip.md +++ /dev/null @@ -1,14 +0,0 @@ -# [XS] std::iter::zip - -## Goal - -[rust2-ts](/ts/README.md) translates `std::iter::zip(a, b)`, including of a `&mut` to a -collection of values JS copies, as `a.into_iter().zip(b)` does, proven by a differential -test against native Rust. - -## Plan - -Found writing [places through an adaptor's argument](https://github.com/moq-dev/rust2/pull/391): -the free function is an "unsupported call", while `Iterator::zip` maps. - -Public API: the translator's output. diff --git a/ts/fixtures/lang/expected/arrays.ts b/ts/fixtures/lang/expected/arrays.ts index 93a77cdea..1a318d622 100644 --- a/ts/fixtures/lang/expected/arrays.ts +++ b/ts/fixtures/lang/expected/arrays.ts @@ -6,7 +6,7 @@ import * as Bracketed from "./arrays.Bracketed.ts"; import type * as Framed from "./arrays.Framed.ts"; import * as Listed from "./arrays.Listed.ts"; import { then$11x7xqs } from "./core/bool.ts"; -import { isSomeAnd$09tpccf, unwrapOr$1rbuegs as option_unwrapOr$1rbuegs, unwrapOr$0r2bmpr as option_unwrapOr$0r2bmpr, map$1j8xzu6 as option_map$1j8xzu6, map$1jcn6wm as option_map$1jcn6wm, map$0rbsrz6 as option_map$0rbsrz6, mapOr$1surhce as option_mapOr$1surhce } from "./core/option.ts"; +import { isSomeAnd$09tpccf, unwrapOr$1rbuegs as option_unwrapOr$1rbuegs, unwrapOr$0r2bmpr as option_unwrapOr$0r2bmpr, map$1j8xzu6 as option_map$1j8xzu6, map$0p6o7wa as option_map$0p6o7wa, map$1jcn6wm as option_map$1jcn6wm, map$0rbsrz6 as option_map$0rbsrz6, mapOr$1surhce as option_mapOr$1surhce } from "./core/option.ts"; /** Each byte an operation, its value the operand; each puts what it read. */ export function fromFns(data: rt.ByteSlice, out: rt.ByteVec): void { @@ -1182,8 +1182,8 @@ export function taken$32(data: rt.ByteSlice, out: rt.ByteVec): void { /** * Arrays of bytes reached through the iterator std makes of each item: of an `Option`, a - * nested one, a `Vec`, a slice, and an array, by `flatten`, `flat_map`, `chain`, `zip`, - * `extend`, `from_iter`, and `DebugList::entries`, read from both ends and written through. + * nested one, a `Vec`, a slice, and an array, by `flatten`, `flat_map`, `chain`, `zip` + * and the free `zip`, `extend`, `from_iter`, and `DebugList::entries`, read from both ends and written through. * Of no bytes, one, and many. */ export function flattened(kind: rt.u8, data: rt.ByteSlice, out: rt.ByteVec): void { @@ -1319,87 +1319,127 @@ export function flattenedN$0(data: rt.ByteSlice, out: rt.ByteVec): void { const iter10: rt.Iter<[rt.ByteSlice, rt.ByteSlice]> = rt.iterZip(rt.iterFlatten(rt.iterSliceMut(options), (value: rt.Place) => rt.iterLend(rt.iterOption(value.v), rt.byteSliceFrom), false, undefined, true), rt.iterLend(rt.iterOption(other), rt.byteSliceFrom)); while (iter10.next() !== rt.DONE) { } - const iter11: rt.Iter = rt.iterChain(rt.iterLend(rt.iterOption(other), rt.byteSliceFrom), rt.iterLend(rt.iterOption(options[rt.idx(options, 3)]), rt.byteSliceFrom)); + const _182: rt.Iter = rt.iterFlatten(rt.iterSlice(options), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true); + const iter11: rt.Iter<[rt.ByteSlice, rt.ByteSlice]> = rt.iterZip(rt.iterLend(rt.iterOption(other), rt.byteSliceFrom), _182); while (true) { - const _186: rt.ByteSlice | rt.Done = iter11.next(); - if (_186 === rt.DONE) { + const _187: [rt.ByteSlice, rt.ByteSlice] | rt.Done = iter11.next(); + if (_187 === rt.DONE) { break; } - rt.byteSliceFill(_186, 90); + rt.byteVecExtendFromSlice(out, _187[0]); + rt.byteVecExtendFromSlice(out, _187[1]); } - const iter12: rt.Iter = rt.iterLend(rt.iterOption(other), rt.byteSliceFrom); + const iter12: rt.Iter<[rt.ByteSlice, rt.Place]> = rt.iterZip(rt.iterLend(rt.iterOption(other), rt.byteSliceFrom), rt.iterSliceMut(options), "len"); while (true) { - const _195: rt.ByteSlice | rt.Done = iter12.next(); - if (_195 === rt.DONE) { + const _201: [rt.ByteSlice, rt.Place] | rt.Done = iter12.next(); + if (_201 === rt.DONE) { break; } - rt.byteSliceView(_195).reverse(); + rt.byteSliceRotateLeft(_201[0], rt.min(0, 1)); + _201[1].v = copy$Option_array0_u8(option_map$0p6o7wa(copy$Option_array0_u8(_201[1].v), (a: Uint8Array): Uint8Array => { + a = copy$array_u8(a); + rt.byteSliceFill(rt.byteSliceFrom(a), option_unwrapOr$0r2bmpr(rt.byteSliceFirst(_201[0]), 51)); + return copy$array_u8(a); + })); } - const iter13: rt.Iter = rt.iterLend(rt.iterOption(other), rt.byteSliceFrom); + const sums: rt.u16[] = rt.iterToArray(rt.iterMap(rt.iterSlice(rt.byteSliceView(data)), (_24: rt.u8): rt.u16 => { + return _24 as rt.u16; + }), undefined, 2, true); + const _219: rt.Iter<[rt.usize, rt.u8]> = rt.iterRev(rt.iterEnumerate(rt.iterSlice(rt.byteSliceView(data)))); + const iter13: rt.Iter<[rt.Place, [rt.usize, rt.u8]]> = rt.iterZip(rt.iterSliceMut(sums), _219, "len"); + while (true) { + const _223: [rt.Place, [rt.usize, rt.u8]] | rt.Done = iter13.next(); + if (_223 === rt.DONE) { + break; + } + const i: rt.usize = _223[1][0]; + const _229: rt.u16 = rt.u16WrappingMul(_223[0].v, 31); + _223[0].v = _229 ^ rt.u16Shl(_223[1][1] as rt.u16, rt.usizeRem(i, 8)); + } + rt.iterExtendBytes(out, rt.iterFlatMap(rt.iterSlice(sums), (x: rt.u16): Uint8Array => { + return rt.u16ToBeBytes(x).reverse(); + }, (value: Uint8Array) => rt.iterSlice(value), false, 2), undefined, true); + const iter14: rt.Iter = rt.iterChain(rt.iterLend(rt.iterOption(other), rt.byteSliceFrom), rt.iterLend(rt.iterOption(options[rt.idx(options, 3)]), rt.byteSliceFrom)); + while (true) { + const _249: rt.ByteSlice | rt.Done = iter14.next(); + if (_249 === rt.DONE) { + break; + } + rt.byteSliceFill(_249, 90); + } + const iter15: rt.Iter = rt.iterLend(rt.iterOption(other), rt.byteSliceFrom); + while (true) { + const _258: rt.ByteSlice | rt.Done = iter15.next(); + if (_258 === rt.DONE) { + break; + } + rt.byteSliceView(_258).reverse(); + } + const iter16: rt.Iter = rt.iterLend(rt.iterOption(other), rt.byteSliceFrom); while (true) { - const _204: rt.ByteSlice | rt.Done = iter13.next(); - if (_204 === rt.DONE) { + const _267: rt.ByteSlice | rt.Done = iter16.next(); + if (_267 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _204); + rt.byteVecExtendFromSlice(out, _267); } putOptions$0(out, options); putSome$0(out, other); const copied: Uint8Array[] = rt.iterToArray(rt.iterCopied(rt.iterSlice(rt.iterToArray(rt.iterLend(rt.iterOption(options[rt.idx(options, 0)]), rt.byteSliceFrom), undefined, 4, true)), rt.byteSliceToArray), undefined, 0, true); rt.iterExtend(copied, rt.iterMap(rt.iterLend(rt.iterOption(other), rt.byteSliceFrom), rt.byteSliceToArray), undefined, 0, true); - const _226: rt.Iter = rt.iterFlatten(rt.iterSlice(options), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true); - rt.iterExtend(copied, rt.iterMap(_226, rt.byteSliceToArray), "next", 0); + const _289: rt.Iter = rt.iterFlatten(rt.iterSlice(options), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true); + rt.iterExtend(copied, rt.iterMap(_289, rt.byteSliceToArray), "next", 0); put$0(out, copied); const nested: Array = copy$array_Option_Option_array0_u8([undefined, rt.None, copy$Option_array0_u8(options[rt.idx(options, 0)]), bytesAt$0(data, 3), undefined]).map(copy$Option_Option_array0_u8); - const iter14: rt.Iter = rt.iterFlatten(rt.iterFlatten(rt.iterSlice(nested), (value: Uint8Array | undefined | rt.None) => rt.iterOption(value, undefined, rt.None), false, undefined, true), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true); + const iter17: rt.Iter = rt.iterFlatten(rt.iterFlatten(rt.iterSlice(nested), (value: Uint8Array | undefined | rt.None) => rt.iterOption(value, undefined, rt.None), false, undefined, true), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true); while (true) { - const _254: rt.ByteSlice | rt.Done = iter14.next(); - if (_254 === rt.DONE) { + const _317: rt.ByteSlice | rt.Done = iter17.next(); + if (_317 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _254); + rt.byteVecExtendFromSlice(out, _317); } - const iter15: rt.Iter = rt.iterRev(rt.iterFlatten(rt.iterFlatten(rt.iterSlice(nested), (value: Uint8Array | undefined | rt.None) => rt.iterOption(value, undefined, rt.None), false, undefined, true), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true)); + const iter18: rt.Iter = rt.iterRev(rt.iterFlatten(rt.iterFlatten(rt.iterSlice(nested), (value: Uint8Array | undefined | rt.None) => rt.iterOption(value, undefined, rt.None), false, undefined, true), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true)); while (true) { - const _268: rt.ByteSlice | rt.Done = iter15.next(); - if (_268 === rt.DONE) { + const _331: rt.ByteSlice | rt.Done = iter18.next(); + if (_331 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _268); + rt.byteVecExtendFromSlice(out, _331); } - const _276: Uint8Array[] = []; - const vecs: Uint8Array[][] = [_276, copy$array_array0_u8([bytesAt$0(data, 4), bytesAt$0(data, 5)]).map(copy$array_u8)]; - const iter16: rt.Iter = rt.iterRev(rt.iterFlatten(rt.iterSlice(vecs), (value: Uint8Array[]) => rt.iterLend(rt.iterSlice(value), rt.byteSliceFrom))); + const _339: Uint8Array[] = []; + const vecs: Uint8Array[][] = [_339, copy$array_array0_u8([bytesAt$0(data, 4), bytesAt$0(data, 5)]).map(copy$array_u8)]; + const iter19: rt.Iter = rt.iterRev(rt.iterFlatten(rt.iterSlice(vecs), (value: Uint8Array[]) => rt.iterLend(rt.iterSlice(value), rt.byteSliceFrom))); while (true) { - const _288: rt.ByteSlice | rt.Done = iter16.next(); - if (_288 === rt.DONE) { + const _351: rt.ByteSlice | rt.Done = iter19.next(); + if (_351 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _288); + rt.byteVecExtendFromSlice(out, _351); } - const iter17: rt.Iter = rt.iterFlatten(rt.iterSlice(rt.iterToArray(rt.iterMap(rt.iterSlice(vecs), (v: Uint8Array[]): Uint8Array[] => { + const iter20: rt.Iter = rt.iterFlatten(rt.iterSlice(rt.iterToArray(rt.iterMap(rt.iterSlice(vecs), (v: Uint8Array[]): Uint8Array[] => { return v; }), undefined, 8, true)), (value: Uint8Array[]) => rt.iterLend(rt.iterSlice(value), rt.byteSliceFrom)); while (true) { - const _303: rt.ByteSlice | rt.Done = iter17.next(); - if (_303 === rt.DONE) { + const _366: rt.ByteSlice | rt.Done = iter20.next(); + if (_366 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _303); + rt.byteVecExtendFromSlice(out, _366); } - const _311: Uint8Array = bytesAt$0(data, 6); - const _310: Uint8Array[] = Array.from({ length: 2 }, (): Uint8Array => { - return copy$array_u8(_311); + const _374: Uint8Array = bytesAt$0(data, 6); + const _373: Uint8Array[] = Array.from({ length: 2 }, (): Uint8Array => { + return copy$array_u8(_374); }); - const iter18: rt.Iter = rt.iterFlatten(rt.iterSlice(Array.from({ length: 2 }, (): Uint8Array[] => { - return copy$array_array0_u8(_310); + const iter21: rt.Iter = rt.iterFlatten(rt.iterSlice(Array.from({ length: 2 }, (): Uint8Array[] => { + return copy$array_array0_u8(_373); })), (value: Uint8Array[]) => rt.iterLend(rt.iterSlice(value), rt.byteSliceFrom), false, 2); while (true) { - const _318: rt.ByteSlice | rt.Done = iter18.next(); - if (_318 === rt.DONE) { + const _381: rt.ByteSlice | rt.Done = iter21.next(); + if (_381 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _318); + rt.byteVecExtendFromSlice(out, _381); } } @@ -1529,87 +1569,127 @@ export function flattenedN$1(data: rt.ByteSlice, out: rt.ByteVec): void { _173[0].data.set(rt.byteSliceToArray(_173[1]), _173[0].start); _173[1].data.set(swapped, _173[1].start); } - const iter11: rt.Iter = rt.iterChain(rt.iterLend(rt.iterOption(other), rt.byteSliceFrom), rt.iterLend(rt.iterOption(options[rt.idx(options, 3)]), rt.byteSliceFrom)); + const _182: rt.Iter = rt.iterFlatten(rt.iterSlice(options), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true); + const iter11: rt.Iter<[rt.ByteSlice, rt.ByteSlice]> = rt.iterZip(rt.iterLend(rt.iterOption(other), rt.byteSliceFrom), _182); + while (true) { + const _187: [rt.ByteSlice, rt.ByteSlice] | rt.Done = iter11.next(); + if (_187 === rt.DONE) { + break; + } + rt.byteVecExtendFromSlice(out, _187[0]); + rt.byteVecExtendFromSlice(out, _187[1]); + } + const iter12: rt.Iter<[rt.ByteSlice, rt.Place]> = rt.iterZip(rt.iterLend(rt.iterOption(other), rt.byteSliceFrom), rt.iterSliceMut(options), "len"); while (true) { - const _186: rt.ByteSlice | rt.Done = iter11.next(); - if (_186 === rt.DONE) { + const _201: [rt.ByteSlice, rt.Place] | rt.Done = iter12.next(); + if (_201 === rt.DONE) { break; } - rt.byteSliceFill(_186, 90); + rt.byteSliceRotateLeft(_201[0], rt.min(1, 1)); + _201[1].v = copy$Option_array1_u8(option_map$0p6o7wa(copy$Option_array1_u8(_201[1].v), (a: Uint8Array): Uint8Array => { + a = copy$array_u8(a); + rt.byteSliceFill(rt.byteSliceFrom(a), option_unwrapOr$0r2bmpr(rt.byteSliceFirst(_201[0]), 51)); + return copy$array_u8(a); + })); } - const iter12: rt.Iter = rt.iterLend(rt.iterOption(other), rt.byteSliceFrom); + const sums: rt.u16[] = rt.iterToArray(rt.iterMap(rt.iterSlice(rt.byteSliceView(data)), (_24: rt.u8): rt.u16 => { + return _24 as rt.u16; + }), undefined, 2, true); + const _219: rt.Iter<[rt.usize, rt.u8]> = rt.iterRev(rt.iterEnumerate(rt.iterSlice(rt.byteSliceView(data)))); + const iter13: rt.Iter<[rt.Place, [rt.usize, rt.u8]]> = rt.iterZip(rt.iterSliceMut(sums), _219, "len"); while (true) { - const _195: rt.ByteSlice | rt.Done = iter12.next(); - if (_195 === rt.DONE) { + const _223: [rt.Place, [rt.usize, rt.u8]] | rt.Done = iter13.next(); + if (_223 === rt.DONE) { break; } - rt.byteSliceView(_195).reverse(); + const i: rt.usize = _223[1][0]; + const _229: rt.u16 = rt.u16WrappingMul(_223[0].v, 31); + _223[0].v = _229 ^ rt.u16Shl(_223[1][1] as rt.u16, rt.usizeRem(i, 8)); } - const iter13: rt.Iter = rt.iterLend(rt.iterOption(other), rt.byteSliceFrom); + rt.iterExtendBytes(out, rt.iterFlatMap(rt.iterSlice(sums), (x: rt.u16): Uint8Array => { + return rt.u16ToBeBytes(x).reverse(); + }, (value: Uint8Array) => rt.iterSlice(value), false, 2), undefined, true); + const iter14: rt.Iter = rt.iterChain(rt.iterLend(rt.iterOption(other), rt.byteSliceFrom), rt.iterLend(rt.iterOption(options[rt.idx(options, 3)]), rt.byteSliceFrom)); while (true) { - const _204: rt.ByteSlice | rt.Done = iter13.next(); - if (_204 === rt.DONE) { + const _249: rt.ByteSlice | rt.Done = iter14.next(); + if (_249 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _204); + rt.byteSliceFill(_249, 90); + } + const iter15: rt.Iter = rt.iterLend(rt.iterOption(other), rt.byteSliceFrom); + while (true) { + const _258: rt.ByteSlice | rt.Done = iter15.next(); + if (_258 === rt.DONE) { + break; + } + rt.byteSliceView(_258).reverse(); + } + const iter16: rt.Iter = rt.iterLend(rt.iterOption(other), rt.byteSliceFrom); + while (true) { + const _267: rt.ByteSlice | rt.Done = iter16.next(); + if (_267 === rt.DONE) { + break; + } + rt.byteVecExtendFromSlice(out, _267); } putOptions$1(out, options); putSome$1(out, other); const copied: Uint8Array[] = rt.iterToArray(rt.iterCopied(rt.iterSlice(rt.iterToArray(rt.iterLend(rt.iterOption(options[rt.idx(options, 0)]), rt.byteSliceFrom), undefined, 4, true)), rt.byteSliceToArray), undefined, 1, true); rt.iterExtend(copied, rt.iterMap(rt.iterLend(rt.iterOption(other), rt.byteSliceFrom), rt.byteSliceToArray), undefined, 1, true); - const _226: rt.Iter = rt.iterFlatten(rt.iterSlice(options), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true); - rt.iterExtend(copied, rt.iterMap(_226, rt.byteSliceToArray), "next", 1); + const _289: rt.Iter = rt.iterFlatten(rt.iterSlice(options), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true); + rt.iterExtend(copied, rt.iterMap(_289, rt.byteSliceToArray), "next", 1); put$1(out, copied); const nested: Array = copy$array_Option_Option_array1_u8([undefined, rt.None, copy$Option_array1_u8(options[rt.idx(options, 0)]), bytesAt$1(data, 3), undefined]).map(copy$Option_Option_array1_u8); - const iter14: rt.Iter = rt.iterFlatten(rt.iterFlatten(rt.iterSlice(nested), (value: Uint8Array | undefined | rt.None) => rt.iterOption(value, undefined, rt.None), false, undefined, true), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true); + const iter17: rt.Iter = rt.iterFlatten(rt.iterFlatten(rt.iterSlice(nested), (value: Uint8Array | undefined | rt.None) => rt.iterOption(value, undefined, rt.None), false, undefined, true), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true); while (true) { - const _254: rt.ByteSlice | rt.Done = iter14.next(); - if (_254 === rt.DONE) { + const _317: rt.ByteSlice | rt.Done = iter17.next(); + if (_317 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _254); + rt.byteVecExtendFromSlice(out, _317); } - const iter15: rt.Iter = rt.iterRev(rt.iterFlatten(rt.iterFlatten(rt.iterSlice(nested), (value: Uint8Array | undefined | rt.None) => rt.iterOption(value, undefined, rt.None), false, undefined, true), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true)); + const iter18: rt.Iter = rt.iterRev(rt.iterFlatten(rt.iterFlatten(rt.iterSlice(nested), (value: Uint8Array | undefined | rt.None) => rt.iterOption(value, undefined, rt.None), false, undefined, true), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true)); while (true) { - const _268: rt.ByteSlice | rt.Done = iter15.next(); - if (_268 === rt.DONE) { + const _331: rt.ByteSlice | rt.Done = iter18.next(); + if (_331 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _268); + rt.byteVecExtendFromSlice(out, _331); } - const _276: Uint8Array[] = []; - const vecs: Uint8Array[][] = [_276, copy$array_array1_u8([bytesAt$1(data, 4), bytesAt$1(data, 5)]).map(copy$array_u8)]; - const iter16: rt.Iter = rt.iterRev(rt.iterFlatten(rt.iterSlice(vecs), (value: Uint8Array[]) => rt.iterLend(rt.iterSlice(value), rt.byteSliceFrom))); + const _339: Uint8Array[] = []; + const vecs: Uint8Array[][] = [_339, copy$array_array1_u8([bytesAt$1(data, 4), bytesAt$1(data, 5)]).map(copy$array_u8)]; + const iter19: rt.Iter = rt.iterRev(rt.iterFlatten(rt.iterSlice(vecs), (value: Uint8Array[]) => rt.iterLend(rt.iterSlice(value), rt.byteSliceFrom))); while (true) { - const _288: rt.ByteSlice | rt.Done = iter16.next(); - if (_288 === rt.DONE) { + const _351: rt.ByteSlice | rt.Done = iter19.next(); + if (_351 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _288); + rt.byteVecExtendFromSlice(out, _351); } - const iter17: rt.Iter = rt.iterFlatten(rt.iterSlice(rt.iterToArray(rt.iterMap(rt.iterSlice(vecs), (v: Uint8Array[]): Uint8Array[] => { + const iter20: rt.Iter = rt.iterFlatten(rt.iterSlice(rt.iterToArray(rt.iterMap(rt.iterSlice(vecs), (v: Uint8Array[]): Uint8Array[] => { return v; }), undefined, 8, true)), (value: Uint8Array[]) => rt.iterLend(rt.iterSlice(value), rt.byteSliceFrom)); while (true) { - const _303: rt.ByteSlice | rt.Done = iter17.next(); - if (_303 === rt.DONE) { + const _366: rt.ByteSlice | rt.Done = iter20.next(); + if (_366 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _303); + rt.byteVecExtendFromSlice(out, _366); } - const _311: Uint8Array = bytesAt$1(data, 6); - const _310: Uint8Array[] = Array.from({ length: 2 }, (): Uint8Array => { - return copy$array_u8(_311); + const _374: Uint8Array = bytesAt$1(data, 6); + const _373: Uint8Array[] = Array.from({ length: 2 }, (): Uint8Array => { + return copy$array_u8(_374); }); - const iter18: rt.Iter = rt.iterFlatten(rt.iterSlice(Array.from({ length: 2 }, (): Uint8Array[] => { - return copy$array_array1_u8(_310); + const iter21: rt.Iter = rt.iterFlatten(rt.iterSlice(Array.from({ length: 2 }, (): Uint8Array[] => { + return copy$array_array1_u8(_373); })), (value: Uint8Array[]) => rt.iterLend(rt.iterSlice(value), rt.byteSliceFrom), false, 2); while (true) { - const _318: rt.ByteSlice | rt.Done = iter18.next(); - if (_318 === rt.DONE) { + const _381: rt.ByteSlice | rt.Done = iter21.next(); + if (_381 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _318); + rt.byteVecExtendFromSlice(out, _381); } } @@ -1739,87 +1819,127 @@ export function flattenedN$5(data: rt.ByteSlice, out: rt.ByteVec): void { _173[0].data.set(rt.byteSliceToArray(_173[1]), _173[0].start); _173[1].data.set(swapped, _173[1].start); } - const iter11: rt.Iter = rt.iterChain(rt.iterLend(rt.iterOption(other), rt.byteSliceFrom), rt.iterLend(rt.iterOption(options[rt.idx(options, 3)]), rt.byteSliceFrom)); + const _182: rt.Iter = rt.iterFlatten(rt.iterSlice(options), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true); + const iter11: rt.Iter<[rt.ByteSlice, rt.ByteSlice]> = rt.iterZip(rt.iterLend(rt.iterOption(other), rt.byteSliceFrom), _182); + while (true) { + const _187: [rt.ByteSlice, rt.ByteSlice] | rt.Done = iter11.next(); + if (_187 === rt.DONE) { + break; + } + rt.byteVecExtendFromSlice(out, _187[0]); + rt.byteVecExtendFromSlice(out, _187[1]); + } + const iter12: rt.Iter<[rt.ByteSlice, rt.Place]> = rt.iterZip(rt.iterLend(rt.iterOption(other), rt.byteSliceFrom), rt.iterSliceMut(options), "len"); + while (true) { + const _201: [rt.ByteSlice, rt.Place] | rt.Done = iter12.next(); + if (_201 === rt.DONE) { + break; + } + rt.byteSliceRotateLeft(_201[0], rt.min(5, 1)); + _201[1].v = copy$Option_array5_u8(option_map$0p6o7wa(copy$Option_array5_u8(_201[1].v), (a: Uint8Array): Uint8Array => { + a = copy$array_u8(a); + rt.byteSliceFill(rt.byteSliceFrom(a), option_unwrapOr$0r2bmpr(rt.byteSliceFirst(_201[0]), 51)); + return copy$array_u8(a); + })); + } + const sums: rt.u16[] = rt.iterToArray(rt.iterMap(rt.iterSlice(rt.byteSliceView(data)), (_24: rt.u8): rt.u16 => { + return _24 as rt.u16; + }), undefined, 2, true); + const _219: rt.Iter<[rt.usize, rt.u8]> = rt.iterRev(rt.iterEnumerate(rt.iterSlice(rt.byteSliceView(data)))); + const iter13: rt.Iter<[rt.Place, [rt.usize, rt.u8]]> = rt.iterZip(rt.iterSliceMut(sums), _219, "len"); + while (true) { + const _223: [rt.Place, [rt.usize, rt.u8]] | rt.Done = iter13.next(); + if (_223 === rt.DONE) { + break; + } + const i: rt.usize = _223[1][0]; + const _229: rt.u16 = rt.u16WrappingMul(_223[0].v, 31); + _223[0].v = _229 ^ rt.u16Shl(_223[1][1] as rt.u16, rt.usizeRem(i, 8)); + } + rt.iterExtendBytes(out, rt.iterFlatMap(rt.iterSlice(sums), (x: rt.u16): Uint8Array => { + return rt.u16ToBeBytes(x).reverse(); + }, (value: Uint8Array) => rt.iterSlice(value), false, 2), undefined, true); + const iter14: rt.Iter = rt.iterChain(rt.iterLend(rt.iterOption(other), rt.byteSliceFrom), rt.iterLend(rt.iterOption(options[rt.idx(options, 3)]), rt.byteSliceFrom)); while (true) { - const _186: rt.ByteSlice | rt.Done = iter11.next(); - if (_186 === rt.DONE) { + const _249: rt.ByteSlice | rt.Done = iter14.next(); + if (_249 === rt.DONE) { break; } - rt.byteSliceFill(_186, 90); + rt.byteSliceFill(_249, 90); } - const iter12: rt.Iter = rt.iterLend(rt.iterOption(other), rt.byteSliceFrom); + const iter15: rt.Iter = rt.iterLend(rt.iterOption(other), rt.byteSliceFrom); while (true) { - const _195: rt.ByteSlice | rt.Done = iter12.next(); - if (_195 === rt.DONE) { + const _258: rt.ByteSlice | rt.Done = iter15.next(); + if (_258 === rt.DONE) { break; } - rt.byteSliceView(_195).reverse(); + rt.byteSliceView(_258).reverse(); } - const iter13: rt.Iter = rt.iterLend(rt.iterOption(other), rt.byteSliceFrom); + const iter16: rt.Iter = rt.iterLend(rt.iterOption(other), rt.byteSliceFrom); while (true) { - const _204: rt.ByteSlice | rt.Done = iter13.next(); - if (_204 === rt.DONE) { + const _267: rt.ByteSlice | rt.Done = iter16.next(); + if (_267 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _204); + rt.byteVecExtendFromSlice(out, _267); } putOptions$5(out, options); putSome$5(out, other); const copied: Uint8Array[] = rt.iterToArray(rt.iterCopied(rt.iterSlice(rt.iterToArray(rt.iterLend(rt.iterOption(options[rt.idx(options, 0)]), rt.byteSliceFrom), undefined, 4, true)), rt.byteSliceToArray), undefined, 5, true); rt.iterExtend(copied, rt.iterMap(rt.iterLend(rt.iterOption(other), rt.byteSliceFrom), rt.byteSliceToArray), undefined, 5, true); - const _226: rt.Iter = rt.iterFlatten(rt.iterSlice(options), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true); - rt.iterExtend(copied, rt.iterMap(_226, rt.byteSliceToArray), "next", 5); + const _289: rt.Iter = rt.iterFlatten(rt.iterSlice(options), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true); + rt.iterExtend(copied, rt.iterMap(_289, rt.byteSliceToArray), "next", 5); put$5(out, copied); const nested: Array = copy$array_Option_Option_array5_u8([undefined, rt.None, copy$Option_array5_u8(options[rt.idx(options, 0)]), bytesAt$5(data, 3), undefined]).map(copy$Option_Option_array5_u8); - const iter14: rt.Iter = rt.iterFlatten(rt.iterFlatten(rt.iterSlice(nested), (value: Uint8Array | undefined | rt.None) => rt.iterOption(value, undefined, rt.None), false, undefined, true), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true); + const iter17: rt.Iter = rt.iterFlatten(rt.iterFlatten(rt.iterSlice(nested), (value: Uint8Array | undefined | rt.None) => rt.iterOption(value, undefined, rt.None), false, undefined, true), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true); while (true) { - const _254: rt.ByteSlice | rt.Done = iter14.next(); - if (_254 === rt.DONE) { + const _317: rt.ByteSlice | rt.Done = iter17.next(); + if (_317 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _254); + rt.byteVecExtendFromSlice(out, _317); } - const iter15: rt.Iter = rt.iterRev(rt.iterFlatten(rt.iterFlatten(rt.iterSlice(nested), (value: Uint8Array | undefined | rt.None) => rt.iterOption(value, undefined, rt.None), false, undefined, true), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true)); + const iter18: rt.Iter = rt.iterRev(rt.iterFlatten(rt.iterFlatten(rt.iterSlice(nested), (value: Uint8Array | undefined | rt.None) => rt.iterOption(value, undefined, rt.None), false, undefined, true), (value: Uint8Array | undefined) => rt.iterLend(rt.iterOption(value), rt.byteSliceFrom), false, undefined, true)); while (true) { - const _268: rt.ByteSlice | rt.Done = iter15.next(); - if (_268 === rt.DONE) { + const _331: rt.ByteSlice | rt.Done = iter18.next(); + if (_331 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _268); + rt.byteVecExtendFromSlice(out, _331); } - const _276: Uint8Array[] = []; - const vecs: Uint8Array[][] = [_276, copy$array_array5_u8([bytesAt$5(data, 4), bytesAt$5(data, 5)]).map(copy$array_u8)]; - const iter16: rt.Iter = rt.iterRev(rt.iterFlatten(rt.iterSlice(vecs), (value: Uint8Array[]) => rt.iterLend(rt.iterSlice(value), rt.byteSliceFrom))); + const _339: Uint8Array[] = []; + const vecs: Uint8Array[][] = [_339, copy$array_array5_u8([bytesAt$5(data, 4), bytesAt$5(data, 5)]).map(copy$array_u8)]; + const iter19: rt.Iter = rt.iterRev(rt.iterFlatten(rt.iterSlice(vecs), (value: Uint8Array[]) => rt.iterLend(rt.iterSlice(value), rt.byteSliceFrom))); while (true) { - const _288: rt.ByteSlice | rt.Done = iter16.next(); - if (_288 === rt.DONE) { + const _351: rt.ByteSlice | rt.Done = iter19.next(); + if (_351 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _288); + rt.byteVecExtendFromSlice(out, _351); } - const iter17: rt.Iter = rt.iterFlatten(rt.iterSlice(rt.iterToArray(rt.iterMap(rt.iterSlice(vecs), (v: Uint8Array[]): Uint8Array[] => { + const iter20: rt.Iter = rt.iterFlatten(rt.iterSlice(rt.iterToArray(rt.iterMap(rt.iterSlice(vecs), (v: Uint8Array[]): Uint8Array[] => { return v; }), undefined, 8, true)), (value: Uint8Array[]) => rt.iterLend(rt.iterSlice(value), rt.byteSliceFrom)); while (true) { - const _303: rt.ByteSlice | rt.Done = iter17.next(); - if (_303 === rt.DONE) { + const _366: rt.ByteSlice | rt.Done = iter20.next(); + if (_366 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _303); + rt.byteVecExtendFromSlice(out, _366); } - const _311: Uint8Array = bytesAt$5(data, 6); - const _310: Uint8Array[] = Array.from({ length: 2 }, (): Uint8Array => { - return copy$array_u8(_311); + const _374: Uint8Array = bytesAt$5(data, 6); + const _373: Uint8Array[] = Array.from({ length: 2 }, (): Uint8Array => { + return copy$array_u8(_374); }); - const iter18: rt.Iter = rt.iterFlatten(rt.iterSlice(Array.from({ length: 2 }, (): Uint8Array[] => { - return copy$array_array5_u8(_310); + const iter21: rt.Iter = rt.iterFlatten(rt.iterSlice(Array.from({ length: 2 }, (): Uint8Array[] => { + return copy$array_array5_u8(_373); })), (value: Uint8Array[]) => rt.iterLend(rt.iterSlice(value), rt.byteSliceFrom), false, 2); while (true) { - const _318: rt.ByteSlice | rt.Done = iter18.next(); - if (_318 === rt.DONE) { + const _381: rt.ByteSlice | rt.Done = iter21.next(); + if (_381 === rt.DONE) { break; } - rt.byteVecExtendFromSlice(out, _318); + rt.byteVecExtendFromSlice(out, _381); } } diff --git a/ts/fixtures/lang/expected/core/option.ts b/ts/fixtures/lang/expected/core/option.ts index d560b69e0..253343235 100644 --- a/ts/fixtures/lang/expected/core/option.ts +++ b/ts/fixtures/lang/expected/core/option.ts @@ -313,6 +313,13 @@ export function map$0po44cb(self: undefined[] | undefined, f: (a0: undefined[]) return f(self); } +export function map$0p6o7wa(self: Uint8Array | undefined, f: (a0: Uint8Array) => Uint8Array): Uint8Array | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + export function map$1iekgsb(self: bounds_Item.Item | undefined, f: (a0: bounds_Item.Item) => rt.u8): rt.u8 | undefined { if (self === undefined) { return undefined; diff --git a/ts/fixtures/lang/src/arrays.rs b/ts/fixtures/lang/src/arrays.rs index 1958a768b..7f2d9a312 100644 --- a/ts/fixtures/lang/src/arrays.rs +++ b/ts/fixtures/lang/src/arrays.rs @@ -429,8 +429,8 @@ where } /// Arrays of bytes reached through the iterator std makes of each item: of an `Option`, a -/// nested one, a `Vec`, a slice, and an array, by `flatten`, `flat_map`, `chain`, `zip`, -/// `extend`, `from_iter`, and `DebugList::entries`, read from both ends and written through. +/// nested one, a `Vec`, a slice, and an array, by `flatten`, `flat_map`, `chain`, `zip` +/// and the free `zip`, `extend`, `from_iter`, and `DebugList::entries`, read from both ends and written through. /// Of no bytes, one, and many. pub fn flattened(kind: u8, data: &[u8], out: &mut Vec) { match kind % 3 { @@ -497,6 +497,23 @@ fn flattened_n(data: &[u8], out: &mut Vec) { for (a, b) in options.iter_mut().flatten().zip(&mut other) { std::mem::swap(a, b); } + // The free `zip` takes each side as `IntoIterator`, a `&mut` to a collection lending its places. + for (b, a) in std::iter::zip(&other, options.iter().flatten()) { + out.extend_from_slice(b); + out.extend_from_slice(a); + } + for (b, a) in std::iter::zip(&mut other, &mut options) { + b.rotate_left(N.min(1)); + *a = a.map(|mut a| { + a.fill(b.first().copied().unwrap_or(0x33)); + a + }); + } + let mut sums: Vec = data.iter().map(|&b| u16::from(b)).collect(); + for (x, (i, y)) in std::iter::zip(&mut sums, data.iter().enumerate().rev()) { + *x = x.wrapping_mul(31) ^ u16::from(*y) << (i % 8); + } + out.extend(sums.iter().flat_map(|x| x.to_le_bytes())); for a in other.iter_mut().chain(&mut options[3]) { a.fill(0x5a); } diff --git a/ts/src/lower/iter.rs b/ts/src/lower/iter.rs index 73205ac10..009619de5 100644 --- a/ts/src/lower/iter.rs +++ b/ts/src/lower/iter.rs @@ -364,6 +364,12 @@ pub fn call<'tcx>( return Some(Expr::rt("iterOnce", tail(args, vec![dropper]))); } ["iter", "sources", "empty", "empty"] => return Some(Expr::rt("iterEmpty", Vec::new())), + // `a.into_iter().zip(b)`, as std's is. + ["iter", "adapters", "zip", "zip"] => { + let [a, other] = <[Expr; 2]>::try_from(args).ok()?; + let a = into_iter(b, targ(0)?, a, span)?; + return zip(b, a, targ(1)?, other, b.t.sig(call.def_id, gargs).output(), span); + } // A closure that owns a value that drops is refused as any std mapping refuses one // it calls but never drops. // Each takes its closure's `None` last, where that is `rt.None`. @@ -657,22 +663,7 @@ pub fn call<'tcx>( let other = into_iter(b, targ(1)?, rest.into_iter().next()?, span)?; method(name, vec![other]) } - "zip" => { - let other_ty = targ(1)?; - let other = into_iter(b, other_ty, rest.into_iter().next()?, span)?; - let zip = b.t.sig(call.def_id, gargs).output(); - let ty::Adt(_, sides) = zip.kind() else { - return None; - }; - let (a, other_iter) = (sides.type_at(0), sides.type_at(1)); - let other_item = b.t.iter_item(other_iter)?; - let droppers = vec![ - zip_trusted(b, a, other_iter, span), - b.t.dropper(item, span), - b.t.dropper(other_item, span), - ]; - method(name, tail(vec![other], droppers)) - } + "zip" => zip(b, recv, targ(1)?, rest.into_iter().next()?, b.t.sig(call.def_id, gargs).output(), span), // `flat_map::`, of the source mapped by `F`, which drops as the source does. "flat_map" => { let inner = iter_of(b.t, targ(1)?)?; @@ -1128,6 +1119,30 @@ fn flattens<'tcx>(b: &mut Body<'_, '_, 'tcx>, inner: Ty<'tcx>, span: Span) { } } +/// `rt.iterZip` of `a`, an iterator, and `other`, of type `other_ty`, into `zip`, the `Zip` +/// of their iterators. +fn zip<'tcx>( + b: &mut Body<'_, '_, 'tcx>, + a: Expr, + other_ty: Ty<'tcx>, + other: Expr, + zip: Ty<'tcx>, + span: Span, +) -> Option { + let other = into_iter(b, other_ty, other, span)?; + let ty::Adt(_, sides) = zip.kind() else { + return None; + }; + let (a_iter, other_iter) = (sides.type_at(0), sides.type_at(1)); + let (item, other_item) = (b.t.iter_item(a_iter)?, b.t.iter_item(other_iter)?); + let droppers = vec![ + zip_trusted(b, a_iter, other_iter, span), + b.t.dropper(item, span), + b.t.dropper(other_item, span), + ]; + Some(Expr::rt("iterZip", tail(vec![a, other], droppers))) +} + /// `rt.Trusted`, how std's `Zip` of `a` and `b` reads them, by the traits it specializes /// on: by index if both are `TrustedRandomAccess`, as whether each may have side effects, /// and folded by its size hint if both are `TrustedLen`, or `TrustedRandomAccessNoCoerce`, diff --git a/ts/src/lower/mir/call.rs b/ts/src/lower/mir/call.rs index 0b8443030..2a8009e3d 100644 --- a/ts/src/lower/mir/call.rs +++ b/ts/src/lower/mir/call.rs @@ -364,7 +364,7 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { // item a `Peekable` peeked, the place a `&mut dyn Any` wraps, a `RefCell` key's value, // a `Result`'s payload, the value of an `Arc`, a lock, or a cell, what a write guard // lends its map or its leak, or what `zip` makes of the collection it is given by - // `into_iter`. + // `into_iter`, as the free `zip` does of either. let lends = match library::key(tcx, def_id) { Some((owner, name)) => match (owner.as_str(), name.as_str()) { ("slice", "get_mut" | "first_mut" | "last_mut" | "iter_mut" | "split_first_mut" | "split_last_mut") @@ -383,6 +383,7 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { ) => true, ("IntoIterator", "into_iter") => gargs.types().next().is_some_and(into_places), ("Iterator", "zip") => gargs.types().nth(1).is_some_and(into_places), + ("zip", "zip") => gargs.types().take(2).any(into_places), _ => false, }, None => false, From ea89fafdbf3622e56ed10b25f73e4db22b438c62 Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Mon, 2 Nov 2026 07:06:18 -0800 Subject: [PATCH 3/3] style(ts): format the zip mapping Co-Authored-By: Claude Opus 5.5 --- ts/src/lower/iter.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ts/src/lower/iter.rs b/ts/src/lower/iter.rs index 009619de5..61835c66c 100644 --- a/ts/src/lower/iter.rs +++ b/ts/src/lower/iter.rs @@ -663,7 +663,14 @@ pub fn call<'tcx>( let other = into_iter(b, targ(1)?, rest.into_iter().next()?, span)?; method(name, vec![other]) } - "zip" => zip(b, recv, targ(1)?, rest.into_iter().next()?, b.t.sig(call.def_id, gargs).output(), span), + "zip" => zip( + b, + recv, + targ(1)?, + rest.into_iter().next()?, + b.t.sig(call.def_id, gargs).output(), + span, + ), // `flat_map::`, of the source mapped by `F`, which drops as the source does. "flat_map" => { let inner = iter_of(b.t, targ(1)?)?;