diff --git a/quest/m3/README.md b/quest/m3/README.md index 0d3bef401..512d0faa4 100644 --- a/quest/m3/README.md +++ b/quest/m3/README.md @@ -36,7 +36,8 @@ generic std gap is planned here even when moq never calls it. - [The rest of a vector's methods](/quest/m3/ts-vec-rest.md) - `try_reserve`, a deque's rotations and searches, and `Vec::splice` translate - [A reversed zip's per-pair cost](/quest/m3/ts-zip-rev-overhead.md) - a reversed by-index zip costs per pair what a forward one does, or the gap is explained - [Type errors at the Rust that made them](/quest/m3/ts-span-precision.md) - a `tsc` error on output names the tail expression or call argument that made it -- [Fresh writes through a zip, a copy, and a repeat](/quest/m3/ts-fresh-shapes.md) - zipping a `Vec<[T; N]>`, reading a `T` out of `Zip::next`, and `copied` or `vec![x; n]` over a `Copy` type translate +- [Fresh writes beside a zipped iterator that points at a part](/quest/m3/ts-fresh-shapes.md) - zipping slots with a `Vec<[T; N]>`, `vec![row; n]`, or `copied` of what the slot holds translates +- [Fresh writes through a vector's own accessors](/quest/m3/ts-fresh-vec-access.md) - a whole write into a vector's element stays fresh through a shared borrow, `first_mut`, a by-value array `for`, and a byte-holding collect - [Python's wake on the loop's own thread](/quest/m3/ffi-python-wake.md) - a wake on the event loop's thread resumes the future with no socket pair - [Python's call cost](/quest/m3/ffi-python-calls.md) - a call on an object costs what BoltFFI's does, or the gap is explained - [A std map with a crate's own BuildHasher](/quest/m3/ts-map-own-hasher.md) - std's and hashbrown's maps built with a crate's own hasher translate for keys that are JS objects diff --git a/quest/m3/ts-fresh-shapes.md b/quest/m3/ts-fresh-shapes.md index fad32f9f8..6c0d6df9f 100644 --- a/quest/m3/ts-fresh-shapes.md +++ b/quest/m3/ts-fresh-shapes.md @@ -1,30 +1,40 @@ -# [M] Fresh writes through a zip, a copy, and a repeat +# [M] Fresh writes beside a zipped iterator that points at a part ## Goal -[rust2-ts](/ts/README.md) translates three shapes it refuses for concrete types and type +[rust2-ts](/ts/README.md) translates a whole write into a slot zipped with an iterator +whose pointers point at a type the slot holds in place, for concrete types and type parameters alike, proven by differential tests against native Rust: -- zipping a slot with a `Vec<[T; N]>`, as `[u8; N]`; -- reading a `T` back out of `Zip::next`'s result; -- `iter().copied()` and `vec![x; n]` over a `Copy` type, a crate's own or a `T: Copy`. +- `slots.iter_mut().zip(rows)` of a `Vec<[T; N]>` or `vec![row; n]`, writing `[T; N]` + rows into `([T; N], (u8, u8))` slots, as `[u8; N]` too; +- `slots.iter_mut().zip(fill.iter().copied())` where the slot holds `fill`'s element type. ## Plan -Found by [#394](https://github.com/moq-dev/rust2/pull/394), which made a whole write into -fresh memory count as fresh in a function generic over a type. These three stay refused for -reasons that have nothing to do with type parameters: +Found by [#516](https://github.com/moq-dev/rust2/pull/516), which made a value of a type +parameter read out of `Zip::next`'s result, `copied`, and `vec![x; n]` judged fresh. The +one cause left: `Trace::fresh`'s check of std-made pointers reads a live `Zip`'s whole +type, so the `IntoIter<[T; N]>` or `Iter` half, which no pointer into the slot made, +counts as pointing at the slot's `[T; N]` part. `origins` also adds each std call in the +chain, the `zip` itself among them, as memory it may have allocated. -- `vec::IntoIter` points at a type the slot holds in place, so zipping with it refuses. -- Reading a `T` out of `Zip::next`'s result makes it a holder. A concrete control - (`Vec>`) is refused as well. -- `Copy`'s supertrait `Clone` selects a parameter candidate, so `copied` and `vec![x; n]` - count as running the crate's `Clone`. The two differ: `copied` copies and calls no - `clone`, while `vec![x; n]` calls `clone` `n - 1` times, and a `Copy` type's hand-written - `Clone` may have effects or panic. Treat `copied` as running no crate code; keep - `vec![x; n]` calling the crate's `clone`, judged fresh only where that `clone` writes - nothing the slot holds. Cover both with differential tests whose `Clone` logs and panics. +Neither the type of a pointer nor what a type holds in place tells the halves apart: +std's code can make a pointer to a tuple's field, as `RangeBounds` for +`(Bound, Bound)` does. Options: -Reproduce each first and fix the one that is a single cause before the others. +- Std's code generic over a type parameter keeps what it was given under that parameter: + match a std call's generic signature against which arguments hold pointers, and mask the + result's parts under parameters none of them bind. In-place `collect` and other + specializations relate parameters through bounds, so a bound naming both must taint. +- A table of std's iterator adaptors and what each part of their result is made of, as + `pointer::derives` is for pointer functions. + +Recommend the first if it stays sound under specialization; it covers every adaptor at +once. Public API: the translator's output. + +## Related + +- [Fresh writes through a vector's own accessors](/quest/m3/ts-fresh-vec-access.md) - the other refusals found beside this one diff --git a/quest/m3/ts-fresh-vec-access.md b/quest/m3/ts-fresh-vec-access.md new file mode 100644 index 000000000..f1e5444e7 --- /dev/null +++ b/quest/m3/ts-fresh-vec-access.md @@ -0,0 +1,32 @@ +# [M] Fresh writes through a vector's own accessors + +## Goal + +[rust2-ts](/ts/README.md) translates a whole write into a vector's element, then a raw +pointer into a part of it, where the vector is reached through std's own accessors, proven +by differential tests against native Rust. Each is refused today with "a raw pointer to +`(u8, u8)` in ..., which the crate may put another object in place of", for concrete types +too: + +- a shared borrow of the vector, or of the one it was collected from, such as `v.len()` or + `other.iter().copied().collect()`: `Trace::origins` gives up on a local any shared borrow + takes, as if one could change it; +- `v.first_mut()` and `v.get_mut(i)`: a std call given a `&mut [T]` counts as replacing + `T`'s parts, as a slice is no object `fills_fresh` judges; +- a `for` over an array by value: `array::IntoIter::next` is given the `&mut` to an + iterator holding the elements in place, which counts as replacing them; +- a vector collected from a std iterator, of a type that holds a byte in place: a `Vec`'s + buffer pointer is `Unique`, so it reads as pointing at that byte. + +## Plan + +Found by [#516](https://github.com/moq-dev/rust2/pull/516), whose tests step around each. +They are separate causes; reproduce each and fix the one that is a single cause first. A +`Vec`'s buffer typed by its element would make `points_to` exact, but a heap buffer is no +part of another value, so check it refuses nothing new. + +Public API: the translator's output. + +## Related + +- [Fresh writes beside a zipped iterator that points at a part](/quest/m3/ts-fresh-shapes.md) - the zip half of #516's leftovers diff --git a/ts/fixtures/lang/lengths/caller.ts b/ts/fixtures/lang/lengths/caller.ts new file mode 100644 index 000000000..cbfda2d78 --- /dev/null +++ b/ts/fixtures/lang/lengths/caller.ts @@ -0,0 +1,15 @@ +// The inputs `lengths`' cases name, which run with the generated ones. + +import { op } from "./lang.ts"; + +export { ops, run } from "./lang.ts"; + +/** + * `lengths::lengths` at each length, with `0xff` among the rows `copied` copies, which + * clones none, and as the value each `vec![x; n]` clones, which panics, in a body generic + * over a type and in one over none. + */ +const lengthsOp = op("lengths::lengths"); +export const cases: Uint8Array[] = [0, 1, 2, 3].flatMap((kind) => + [[0xff, 0, 0, 0xff], [0, 0xff, 0], [0, 0, 0xff]].map((data) => Uint8Array.of(...lengthsOp, kind, ...data)), +); diff --git a/ts/fixtures/lang/lengths/expected/lengths.Loud.ts b/ts/fixtures/lang/lengths/expected/lengths.Loud.ts new file mode 100644 index 000000000..7e8fbbd1d --- /dev/null +++ b/ts/fixtures/lang/lengths/expected/lengths.Loud.ts @@ -0,0 +1,29 @@ +// Generated by rust2-ts. Do not edit. + +import * as rt from "./rt.ts"; +import { CLONES } from "./lengths.ts"; + +/** + * A `Copy` type whose `Clone`, written by hand, logs its value, panics on `0xff`, and + * counts up, so a clone tells from a copy: `copied` never calls it, and `vec![x; n]` calls + * it `n - 1` times. + */ +export interface Loud { + _0: rt.u16; +} + +export function clone$Clone(self: Loud): Loud { + rt.localKeyWithBorrowMut(CLONES, (log: rt.ByteVec): undefined => { + rt.iterExtendBytes(log, rt.iterSlice(rt.u16ToBeBytes(self._0).reverse()), undefined, true); + }); + if (!(self._0 === 255)) { + return { _0: rt.u16WrappingAdd(self._0, 1) }; + } + rt.assertFailed("!=", (f: rt.Formatter) => rt.u16Debug(self._0, f), (f: rt.Formatter) => rt.u16Debug(255, f), ["a clone of 0xff"]); +} + +export function put$lengths_Put(self: Loud, out: rt.ByteVec): void { + rt.iterExtendBytes(out, rt.iterSlice(rt.u16ToBeBytes(self._0).reverse()), undefined, true); +} + +//# sourceMappingURL=lengths.Loud.ts.map diff --git a/ts/fixtures/lang/lengths/expected/lengths.Row.ts b/ts/fixtures/lang/lengths/expected/lengths.Row.ts new file mode 100644 index 000000000..2d206a852 --- /dev/null +++ b/ts/fixtures/lang/lengths/expected/lengths.Row.ts @@ -0,0 +1,22 @@ +// Generated by rust2-ts. Do not edit. + +import * as rt from "./rt.ts"; +import { copy$tuple2_u16_u16 } from "./lib.ts"; +import * as Loud from "./lengths.Loud.ts"; + +export function clone$Clone_lengths_Loud(self: Row): Row { + return new Row(Loud.clone$Clone(self._0), copy$tuple2_u16_u16(self._1)); +} + +/** A value and a pair of tags kept as an object, of no byte held in place. */ +export class Row { + _0: T; + _1: [rt.u16, rt.u16]; + + constructor(_0: T, _1: [rt.u16, rt.u16]) { + this._0 = _0; + this._1 = _1; + } +} + +//# sourceMappingURL=lengths.Row.ts.map diff --git a/ts/fixtures/lang/lengths/expected/lengths.ts b/ts/fixtures/lang/lengths/expected/lengths.ts index c09db3302..9f61daeae 100644 --- a/ts/fixtures/lang/lengths/expected/lengths.ts +++ b/ts/fixtures/lang/lengths/expected/lengths.ts @@ -1,22 +1,36 @@ // Generated by rust2-ts. Do not edit. import * as rt from "./rt.ts"; -import { copy$Option_lengths_Tagged_array0_u32, copy$Option_lengths_Tagged_array0_u8, copy$Option_lengths_Tagged_array17_u32, copy$Option_lengths_Tagged_array17_u8, copy$Option_lengths_Tagged_array1_u32, copy$Option_lengths_Tagged_array1_u8, copy$Option_lengths_Tagged_array3_u32, copy$Option_lengths_Tagged_array3_u8, copy$array_array0_u8, copy$array_array17_u8, copy$array_array1_u8, copy$array_array3_u8, copy$array_lengths_Tagged_u32, copy$array_u32, copy$array_u8, copy$mem_MaybeUninit_tuple2_array0_array0_u8_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array0_lengths_Tagged_u32_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array0_u32_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array0_u8_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array17_array17_u8_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array17_lengths_Tagged_u32_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array17_u32_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array17_u8_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array1_array1_u8_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array1_lengths_Tagged_u32_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array1_u32_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array1_u8_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array3_array3_u8_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array3_lengths_Tagged_u32_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array3_u32_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array3_u8_tuple2_u8_u8 } from "./lib.ts"; +import { copy$Option_lengths_Tagged_array0_u32, copy$Option_lengths_Tagged_array0_u8, copy$Option_lengths_Tagged_array17_u32, copy$Option_lengths_Tagged_array17_u8, copy$Option_lengths_Tagged_array1_u32, copy$Option_lengths_Tagged_array1_u8, copy$Option_lengths_Tagged_array3_u32, copy$Option_lengths_Tagged_array3_u8, copy$array_array0_u8, copy$array_array17_u8, copy$array_array1_u8, copy$array_array3_u8, copy$array_lengths_Tagged_u32, copy$array_u32, copy$array_u8, copy$lengths_Row_lengths_Loud, copy$lengths_Row_u8, copy$mem_MaybeUninit_tuple2_array0_array0_u8_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array0_lengths_Tagged_u32_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array0_u32_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array0_u8_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array17_array17_u8_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array17_lengths_Tagged_u32_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array17_u32_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array17_u8_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array1_array1_u8_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array1_lengths_Tagged_u32_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array1_u32_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array1_u8_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array3_array3_u8_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array3_lengths_Tagged_u32_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array3_u32_tuple2_u8_u8, copy$mem_MaybeUninit_tuple2_array3_u8_tuple2_u8_u8 } from "./lib.ts"; import { unwrapOr$0r2bmpr as option_unwrapOr$0r2bmpr } from "./core/option.ts"; +import * as Loud from "./lengths.Loud.ts"; +import * as Row from "./lengths.Row.ts"; import * as Tagged from "./lengths.Tagged.ts"; /** Each case at the length `kind` picks. */ export function lengths(kind: rt.u8, data: rt.ByteSlice, out: rt.ByteVec): void { - const _4: rt.u8 = rt.u8Rem(kind, 4); - if (_4 === 0) { + rt.localKeyWithBorrowMut(CLONES, (a0: rt.ByteVec): undefined => { + rt.byteVecClear(a0); + }); + const _7: rt.u8 = rt.u8Rem(kind, 4); + if (_7 === 0) { each$0(data, out); - } else if (_4 === 1) { + } else if (_7 === 1) { each$1(data, out); - } else if (_4 === 2) { + } else if (_7 === 2) { each$3(data, out); } else { each$17(data, out); } + const byte: (a0: rt.usize) => rt.u16 = (at: rt.usize): rt.u16 => { + return option_unwrapOr$0r2bmpr(rt.byteSliceGet(data, at), 0) as rt.u16; + }; + repeated$u8(data.data, data.start, data.length, 65, 66, out); + repeated$lengths_Loud(data.data, data.start, data.length, { _0: byte(1) }, { _0: byte(0) }, out); + loud(data, out); + rt.localKeyWithBorrowMut(CLONES, (log: rt.ByteVec): undefined => { + rt.iterExtendBytes(out, rt.byteVecDrain(log, undefined), "fold", true); + }); } export function each$0(data: rt.ByteSlice, out: rt.ByteVec): void { @@ -409,10 +423,12 @@ export function recloned$u32_3(rows: rt.u32[][], out: rt.ByteVec): void { /** * Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while - * nothing points into them, the last two again beside a vector's iterator, which std - * drops, then changed in place, a pair of tags through a pointer to it, and read back. + * nothing points into them, the last two again from the values a vector's iterator gives + * beside them, which std drops, then changed in place, a pair of tags through a pointer to + * it, and read back. */ export function filled$array0_u8_0(data: rt.ByteSlice, fill: Uint8Array[], out: rt.ByteVec): void { + let row!: Uint8Array[]; const item = ([Array.from({ length: 0 }, (): Uint8Array => { return (new Uint8Array(0) as unknown) as Uint8Array; }), [undefined, undefined]] as unknown) as [Uint8Array[], [rt.u8, rt.u8]]; @@ -445,37 +461,48 @@ export function filled$array0_u8_0(data: rt.ByteSlice, fill: Uint8Array[], out: if (_41 === rt.DONE) { break; } + const pick: Uint8Array | undefined = _41[1]; + if (pick === undefined) { + row = fill; + } else { + const v2: Uint8Array = pick; + row = Array.from({ length: 0 }, (): Uint8Array => { + return copy$array_u8(v2); + }); + } const uninit2 = _41[0]; - rt.ptrWrite(uninit2, [copy$array_array0_u8(fill), [0, 90] as [rt.u8, rt.u8]] as [Uint8Array[], [rt.u8, rt.u8]]); + rt.ptrWrite(uninit2, [copy$array_array0_u8(row), [0, 90] as [rt.u8, rt.u8]] as [Uint8Array[], [rt.u8, rt.u8]]); uninit2; } for (const byte of rt.byteSliceView(data)) { - const _58: rt.usize = rt.usizeRem(byte as rt.usize, 3); - if (!(_58 < 3)) { - rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _58); + const _62: rt.usize = rt.usizeRem(byte as rt.usize, 3); + if (!(_62 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _62); } - const slot: [Uint8Array[], [rt.u8, rt.u8]] = slots[_58]; + const slot: [Uint8Array[], [rt.u8, rt.u8]] = slots[_62]; rt.sliceRotateLeft(slot[0], rt.usizeRem(byte as rt.usize, rt.max(0, 1))); const tags: [rt.u8, rt.u8] = slot[1]; tags[0] = tags[0] ^ byte; tags[1] = rt.u8WrappingAdd(tags[1], byte); rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(tags[0], tags[1])), undefined, true); } - for (const _79 of slots) { - const _86: [Uint8Array[], [rt.u8, rt.u8]] = _79; - rt.iterForEach(rt.iterLend(rt.iterSlice(_86[0]), rt.byteSliceFrom), (v2: rt.ByteSlice): undefined => { - put$lengths_Put_array0_u8(v2, out); + for (const _83 of slots) { + const _90: [Uint8Array[], [rt.u8, rt.u8]] = _83; + rt.iterForEach(rt.iterLend(rt.iterSlice(_90[0]), rt.byteSliceFrom), (v3: rt.ByteSlice): undefined => { + put$lengths_Put_array0_u8(v3, out); }); - rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_86[1][0], _86[1][1])), undefined, true); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_90[1][0], _90[1][1])), undefined, true); } } /** * Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while - * nothing points into them, the last two again beside a vector's iterator, which std - * drops, then changed in place, a pair of tags through a pointer to it, and read back. + * nothing points into them, the last two again from the values a vector's iterator gives + * beside them, which std drops, then changed in place, a pair of tags through a pointer to + * it, and read back. */ export function filled$array17_u8_17(data: rt.ByteSlice, fill: Uint8Array[], out: rt.ByteVec): void { + let row!: Uint8Array[]; const item = ([Array.from({ length: 17 }, (): Uint8Array => { return (new Uint8Array(17) as unknown) as Uint8Array; }), [undefined, undefined]] as unknown) as [Uint8Array[], [rt.u8, rt.u8]]; @@ -508,37 +535,48 @@ export function filled$array17_u8_17(data: rt.ByteSlice, fill: Uint8Array[], out if (_41 === rt.DONE) { break; } + const pick: Uint8Array | undefined = _41[1]; + if (pick === undefined) { + row = fill; + } else { + const v2: Uint8Array = pick; + row = Array.from({ length: 17 }, (): Uint8Array => { + return copy$array_u8(v2); + }); + } const uninit2 = _41[0]; - rt.ptrWrite(uninit2, [copy$array_array17_u8(fill), [17, 90] as [rt.u8, rt.u8]] as [Uint8Array[], [rt.u8, rt.u8]]); + rt.ptrWrite(uninit2, [copy$array_array17_u8(row), [17, 90] as [rt.u8, rt.u8]] as [Uint8Array[], [rt.u8, rt.u8]]); uninit2; } for (const byte of rt.byteSliceView(data)) { - const _58: rt.usize = rt.usizeRem(byte as rt.usize, 3); - if (!(_58 < 3)) { - rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _58); + const _62: rt.usize = rt.usizeRem(byte as rt.usize, 3); + if (!(_62 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _62); } - const slot: [Uint8Array[], [rt.u8, rt.u8]] = slots[_58]; + const slot: [Uint8Array[], [rt.u8, rt.u8]] = slots[_62]; rt.sliceRotateLeft(slot[0], rt.usizeRem(byte as rt.usize, rt.max(17, 1))); const tags: [rt.u8, rt.u8] = slot[1]; tags[0] = tags[0] ^ byte; tags[1] = rt.u8WrappingAdd(tags[1], byte); rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(tags[0], tags[1])), undefined, true); } - for (const _79 of slots) { - const _86: [Uint8Array[], [rt.u8, rt.u8]] = _79; - rt.iterForEach(rt.iterLend(rt.iterSlice(_86[0]), rt.byteSliceFrom), (v2: rt.ByteSlice): undefined => { - put$lengths_Put_array17_u8(v2, out); + for (const _83 of slots) { + const _90: [Uint8Array[], [rt.u8, rt.u8]] = _83; + rt.iterForEach(rt.iterLend(rt.iterSlice(_90[0]), rt.byteSliceFrom), (v3: rt.ByteSlice): undefined => { + put$lengths_Put_array17_u8(v3, out); }); - rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_86[1][0], _86[1][1])), undefined, true); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_90[1][0], _90[1][1])), undefined, true); } } /** * Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while - * nothing points into them, the last two again beside a vector's iterator, which std - * drops, then changed in place, a pair of tags through a pointer to it, and read back. + * nothing points into them, the last two again from the values a vector's iterator gives + * beside them, which std drops, then changed in place, a pair of tags through a pointer to + * it, and read back. */ export function filled$array1_u8_1(data: rt.ByteSlice, fill: Uint8Array[], out: rt.ByteVec): void { + let row!: Uint8Array[]; const item = ([Array.from({ length: 1 }, (): Uint8Array => { return (new Uint8Array(1) as unknown) as Uint8Array; }), [undefined, undefined]] as unknown) as [Uint8Array[], [rt.u8, rt.u8]]; @@ -571,37 +609,48 @@ export function filled$array1_u8_1(data: rt.ByteSlice, fill: Uint8Array[], out: if (_41 === rt.DONE) { break; } + const pick: Uint8Array | undefined = _41[1]; + if (pick === undefined) { + row = fill; + } else { + const v2: Uint8Array = pick; + row = Array.from({ length: 1 }, (): Uint8Array => { + return copy$array_u8(v2); + }); + } const uninit2 = _41[0]; - rt.ptrWrite(uninit2, [copy$array_array1_u8(fill), [1, 90] as [rt.u8, rt.u8]] as [Uint8Array[], [rt.u8, rt.u8]]); + rt.ptrWrite(uninit2, [copy$array_array1_u8(row), [1, 90] as [rt.u8, rt.u8]] as [Uint8Array[], [rt.u8, rt.u8]]); uninit2; } for (const byte of rt.byteSliceView(data)) { - const _58: rt.usize = rt.usizeRem(byte as rt.usize, 3); - if (!(_58 < 3)) { - rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _58); + const _62: rt.usize = rt.usizeRem(byte as rt.usize, 3); + if (!(_62 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _62); } - const slot: [Uint8Array[], [rt.u8, rt.u8]] = slots[_58]; + const slot: [Uint8Array[], [rt.u8, rt.u8]] = slots[_62]; rt.sliceRotateLeft(slot[0], rt.usizeRem(byte as rt.usize, rt.max(1, 1))); const tags: [rt.u8, rt.u8] = slot[1]; tags[0] = tags[0] ^ byte; tags[1] = rt.u8WrappingAdd(tags[1], byte); rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(tags[0], tags[1])), undefined, true); } - for (const _79 of slots) { - const _86: [Uint8Array[], [rt.u8, rt.u8]] = _79; - rt.iterForEach(rt.iterLend(rt.iterSlice(_86[0]), rt.byteSliceFrom), (v2: rt.ByteSlice): undefined => { - put$lengths_Put_array1_u8(v2, out); + for (const _83 of slots) { + const _90: [Uint8Array[], [rt.u8, rt.u8]] = _83; + rt.iterForEach(rt.iterLend(rt.iterSlice(_90[0]), rt.byteSliceFrom), (v3: rt.ByteSlice): undefined => { + put$lengths_Put_array1_u8(v3, out); }); - rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_86[1][0], _86[1][1])), undefined, true); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_90[1][0], _90[1][1])), undefined, true); } } /** * Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while - * nothing points into them, the last two again beside a vector's iterator, which std - * drops, then changed in place, a pair of tags through a pointer to it, and read back. + * nothing points into them, the last two again from the values a vector's iterator gives + * beside them, which std drops, then changed in place, a pair of tags through a pointer to + * it, and read back. */ export function filled$array3_u8_3(data: rt.ByteSlice, fill: Uint8Array[], out: rt.ByteVec): void { + let row!: Uint8Array[]; const item = ([Array.from({ length: 3 }, (): Uint8Array => { return (new Uint8Array(3) as unknown) as Uint8Array; }), [undefined, undefined]] as unknown) as [Uint8Array[], [rt.u8, rt.u8]]; @@ -634,37 +683,48 @@ export function filled$array3_u8_3(data: rt.ByteSlice, fill: Uint8Array[], out: if (_41 === rt.DONE) { break; } + const pick: Uint8Array | undefined = _41[1]; + if (pick === undefined) { + row = fill; + } else { + const v2: Uint8Array = pick; + row = Array.from({ length: 3 }, (): Uint8Array => { + return copy$array_u8(v2); + }); + } const uninit2 = _41[0]; - rt.ptrWrite(uninit2, [copy$array_array3_u8(fill), [3, 90] as [rt.u8, rt.u8]] as [Uint8Array[], [rt.u8, rt.u8]]); + rt.ptrWrite(uninit2, [copy$array_array3_u8(row), [3, 90] as [rt.u8, rt.u8]] as [Uint8Array[], [rt.u8, rt.u8]]); uninit2; } for (const byte of rt.byteSliceView(data)) { - const _58: rt.usize = rt.usizeRem(byte as rt.usize, 3); - if (!(_58 < 3)) { - rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _58); + const _62: rt.usize = rt.usizeRem(byte as rt.usize, 3); + if (!(_62 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _62); } - const slot: [Uint8Array[], [rt.u8, rt.u8]] = slots[_58]; + const slot: [Uint8Array[], [rt.u8, rt.u8]] = slots[_62]; rt.sliceRotateLeft(slot[0], rt.usizeRem(byte as rt.usize, rt.max(3, 1))); const tags: [rt.u8, rt.u8] = slot[1]; tags[0] = tags[0] ^ byte; tags[1] = rt.u8WrappingAdd(tags[1], byte); rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(tags[0], tags[1])), undefined, true); } - for (const _79 of slots) { - const _86: [Uint8Array[], [rt.u8, rt.u8]] = _79; - rt.iterForEach(rt.iterLend(rt.iterSlice(_86[0]), rt.byteSliceFrom), (v2: rt.ByteSlice): undefined => { - put$lengths_Put_array3_u8(v2, out); + for (const _83 of slots) { + const _90: [Uint8Array[], [rt.u8, rt.u8]] = _83; + rt.iterForEach(rt.iterLend(rt.iterSlice(_90[0]), rt.byteSliceFrom), (v3: rt.ByteSlice): undefined => { + put$lengths_Put_array3_u8(v3, out); }); - rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_86[1][0], _86[1][1])), undefined, true); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_90[1][0], _90[1][1])), undefined, true); } } /** * Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while - * nothing points into them, the last two again beside a vector's iterator, which std - * drops, then changed in place, a pair of tags through a pointer to it, and read back. + * nothing points into them, the last two again from the values a vector's iterator gives + * beside them, which std drops, then changed in place, a pair of tags through a pointer to + * it, and read back. */ export function filled$lengths_Tagged_u32_0(data: rt.ByteSlice, fill: Tagged.Tagged[], out: rt.ByteVec): void { + let row!: Tagged.Tagged[]; const item = ([Array.from({ length: 0 }, (): Tagged.Tagged => { return (new Tagged.Tagged((undefined as unknown) as rt.u32, (undefined as unknown) as rt.u8) as unknown) as Tagged.Tagged; }), [undefined, undefined]] as unknown) as [Tagged.Tagged[], [rt.u8, rt.u8]]; @@ -692,37 +752,48 @@ export function filled$lengths_Tagged_u32_0(data: rt.ByteSlice, fill: Tagged.Tag if (_41 === rt.DONE) { break; } + const pick: Tagged.Tagged | undefined = _41[1]; + if (pick === undefined) { + row = fill; + } else { + const v2: Tagged.Tagged = pick; + row = Array.from({ length: 0 }, (): Tagged.Tagged => { + return v2; + }); + } const uninit2 = _41[0]; - rt.ptrWrite(uninit2, [copy$array_lengths_Tagged_u32(fill), [0, 90] as [rt.u8, rt.u8]] as [Tagged.Tagged[], [rt.u8, rt.u8]]); + rt.ptrWrite(uninit2, [copy$array_lengths_Tagged_u32(row), [0, 90] as [rt.u8, rt.u8]] as [Tagged.Tagged[], [rt.u8, rt.u8]]); uninit2; } for (const byte of rt.byteSliceView(data)) { - const _58: rt.usize = rt.usizeRem(byte as rt.usize, 3); - if (!(_58 < 3)) { - rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _58); + const _62: rt.usize = rt.usizeRem(byte as rt.usize, 3); + if (!(_62 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _62); } - const slot: [Tagged.Tagged[], [rt.u8, rt.u8]] = slots[_58]; + const slot: [Tagged.Tagged[], [rt.u8, rt.u8]] = slots[_62]; rt.sliceRotateLeft(slot[0], rt.usizeRem(byte as rt.usize, rt.max(0, 1))); const tags: [rt.u8, rt.u8] = slot[1]; tags[0] = tags[0] ^ byte; tags[1] = rt.u8WrappingAdd(tags[1], byte); rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(tags[0], tags[1])), undefined, true); } - for (const _79 of slots) { - const _86: [Tagged.Tagged[], [rt.u8, rt.u8]] = _79; - rt.iterForEach(rt.iterSlice(_86[0]), (v2: Tagged.Tagged): undefined => { - Tagged.put$lengths_Put_u32(v2, out); + for (const _83 of slots) { + const _90: [Tagged.Tagged[], [rt.u8, rt.u8]] = _83; + rt.iterForEach(rt.iterSlice(_90[0]), (v3: Tagged.Tagged): undefined => { + Tagged.put$lengths_Put_u32(v3, out); }); - rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_86[1][0], _86[1][1])), undefined, true); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_90[1][0], _90[1][1])), undefined, true); } } /** * Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while - * nothing points into them, the last two again beside a vector's iterator, which std - * drops, then changed in place, a pair of tags through a pointer to it, and read back. + * nothing points into them, the last two again from the values a vector's iterator gives + * beside them, which std drops, then changed in place, a pair of tags through a pointer to + * it, and read back. */ export function filled$lengths_Tagged_u32_1(data: rt.ByteSlice, fill: Tagged.Tagged[], out: rt.ByteVec): void { + let row!: Tagged.Tagged[]; const item = ([Array.from({ length: 1 }, (): Tagged.Tagged => { return (new Tagged.Tagged((undefined as unknown) as rt.u32, (undefined as unknown) as rt.u8) as unknown) as Tagged.Tagged; }), [undefined, undefined]] as unknown) as [Tagged.Tagged[], [rt.u8, rt.u8]]; @@ -750,37 +821,48 @@ export function filled$lengths_Tagged_u32_1(data: rt.ByteSlice, fill: Tagged.Tag if (_41 === rt.DONE) { break; } + const pick: Tagged.Tagged | undefined = _41[1]; + if (pick === undefined) { + row = fill; + } else { + const v2: Tagged.Tagged = pick; + row = Array.from({ length: 1 }, (): Tagged.Tagged => { + return v2; + }); + } const uninit2 = _41[0]; - rt.ptrWrite(uninit2, [copy$array_lengths_Tagged_u32(fill), [1, 90] as [rt.u8, rt.u8]] as [Tagged.Tagged[], [rt.u8, rt.u8]]); + rt.ptrWrite(uninit2, [copy$array_lengths_Tagged_u32(row), [1, 90] as [rt.u8, rt.u8]] as [Tagged.Tagged[], [rt.u8, rt.u8]]); uninit2; } for (const byte of rt.byteSliceView(data)) { - const _58: rt.usize = rt.usizeRem(byte as rt.usize, 3); - if (!(_58 < 3)) { - rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _58); + const _62: rt.usize = rt.usizeRem(byte as rt.usize, 3); + if (!(_62 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _62); } - const slot: [Tagged.Tagged[], [rt.u8, rt.u8]] = slots[_58]; + const slot: [Tagged.Tagged[], [rt.u8, rt.u8]] = slots[_62]; rt.sliceRotateLeft(slot[0], rt.usizeRem(byte as rt.usize, rt.max(1, 1))); const tags: [rt.u8, rt.u8] = slot[1]; tags[0] = tags[0] ^ byte; tags[1] = rt.u8WrappingAdd(tags[1], byte); rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(tags[0], tags[1])), undefined, true); } - for (const _79 of slots) { - const _86: [Tagged.Tagged[], [rt.u8, rt.u8]] = _79; - rt.iterForEach(rt.iterSlice(_86[0]), (v2: Tagged.Tagged): undefined => { - Tagged.put$lengths_Put_u32(v2, out); + for (const _83 of slots) { + const _90: [Tagged.Tagged[], [rt.u8, rt.u8]] = _83; + rt.iterForEach(rt.iterSlice(_90[0]), (v3: Tagged.Tagged): undefined => { + Tagged.put$lengths_Put_u32(v3, out); }); - rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_86[1][0], _86[1][1])), undefined, true); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_90[1][0], _90[1][1])), undefined, true); } } /** * Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while - * nothing points into them, the last two again beside a vector's iterator, which std - * drops, then changed in place, a pair of tags through a pointer to it, and read back. + * nothing points into them, the last two again from the values a vector's iterator gives + * beside them, which std drops, then changed in place, a pair of tags through a pointer to + * it, and read back. */ export function filled$lengths_Tagged_u32_17(data: rt.ByteSlice, fill: Tagged.Tagged[], out: rt.ByteVec): void { + let row!: Tagged.Tagged[]; const item = ([Array.from({ length: 17 }, (): Tagged.Tagged => { return (new Tagged.Tagged((undefined as unknown) as rt.u32, (undefined as unknown) as rt.u8) as unknown) as Tagged.Tagged; }), [undefined, undefined]] as unknown) as [Tagged.Tagged[], [rt.u8, rt.u8]]; @@ -808,37 +890,48 @@ export function filled$lengths_Tagged_u32_17(data: rt.ByteSlice, fill: Tagged.Ta if (_41 === rt.DONE) { break; } + const pick: Tagged.Tagged | undefined = _41[1]; + if (pick === undefined) { + row = fill; + } else { + const v2: Tagged.Tagged = pick; + row = Array.from({ length: 17 }, (): Tagged.Tagged => { + return v2; + }); + } const uninit2 = _41[0]; - rt.ptrWrite(uninit2, [copy$array_lengths_Tagged_u32(fill), [17, 90] as [rt.u8, rt.u8]] as [Tagged.Tagged[], [rt.u8, rt.u8]]); + rt.ptrWrite(uninit2, [copy$array_lengths_Tagged_u32(row), [17, 90] as [rt.u8, rt.u8]] as [Tagged.Tagged[], [rt.u8, rt.u8]]); uninit2; } for (const byte of rt.byteSliceView(data)) { - const _58: rt.usize = rt.usizeRem(byte as rt.usize, 3); - if (!(_58 < 3)) { - rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _58); + const _62: rt.usize = rt.usizeRem(byte as rt.usize, 3); + if (!(_62 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _62); } - const slot: [Tagged.Tagged[], [rt.u8, rt.u8]] = slots[_58]; + const slot: [Tagged.Tagged[], [rt.u8, rt.u8]] = slots[_62]; rt.sliceRotateLeft(slot[0], rt.usizeRem(byte as rt.usize, rt.max(17, 1))); const tags: [rt.u8, rt.u8] = slot[1]; tags[0] = tags[0] ^ byte; tags[1] = rt.u8WrappingAdd(tags[1], byte); rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(tags[0], tags[1])), undefined, true); } - for (const _79 of slots) { - const _86: [Tagged.Tagged[], [rt.u8, rt.u8]] = _79; - rt.iterForEach(rt.iterSlice(_86[0]), (v2: Tagged.Tagged): undefined => { - Tagged.put$lengths_Put_u32(v2, out); + for (const _83 of slots) { + const _90: [Tagged.Tagged[], [rt.u8, rt.u8]] = _83; + rt.iterForEach(rt.iterSlice(_90[0]), (v3: Tagged.Tagged): undefined => { + Tagged.put$lengths_Put_u32(v3, out); }); - rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_86[1][0], _86[1][1])), undefined, true); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_90[1][0], _90[1][1])), undefined, true); } } /** * Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while - * nothing points into them, the last two again beside a vector's iterator, which std - * drops, then changed in place, a pair of tags through a pointer to it, and read back. + * nothing points into them, the last two again from the values a vector's iterator gives + * beside them, which std drops, then changed in place, a pair of tags through a pointer to + * it, and read back. */ export function filled$lengths_Tagged_u32_3(data: rt.ByteSlice, fill: Tagged.Tagged[], out: rt.ByteVec): void { + let row!: Tagged.Tagged[]; const item = ([Array.from({ length: 3 }, (): Tagged.Tagged => { return (new Tagged.Tagged((undefined as unknown) as rt.u32, (undefined as unknown) as rt.u8) as unknown) as Tagged.Tagged; }), [undefined, undefined]] as unknown) as [Tagged.Tagged[], [rt.u8, rt.u8]]; @@ -866,37 +959,48 @@ export function filled$lengths_Tagged_u32_3(data: rt.ByteSlice, fill: Tagged.Tag if (_41 === rt.DONE) { break; } + const pick: Tagged.Tagged | undefined = _41[1]; + if (pick === undefined) { + row = fill; + } else { + const v2: Tagged.Tagged = pick; + row = Array.from({ length: 3 }, (): Tagged.Tagged => { + return v2; + }); + } const uninit2 = _41[0]; - rt.ptrWrite(uninit2, [copy$array_lengths_Tagged_u32(fill), [3, 90] as [rt.u8, rt.u8]] as [Tagged.Tagged[], [rt.u8, rt.u8]]); + rt.ptrWrite(uninit2, [copy$array_lengths_Tagged_u32(row), [3, 90] as [rt.u8, rt.u8]] as [Tagged.Tagged[], [rt.u8, rt.u8]]); uninit2; } for (const byte of rt.byteSliceView(data)) { - const _58: rt.usize = rt.usizeRem(byte as rt.usize, 3); - if (!(_58 < 3)) { - rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _58); + const _62: rt.usize = rt.usizeRem(byte as rt.usize, 3); + if (!(_62 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _62); } - const slot: [Tagged.Tagged[], [rt.u8, rt.u8]] = slots[_58]; + const slot: [Tagged.Tagged[], [rt.u8, rt.u8]] = slots[_62]; rt.sliceRotateLeft(slot[0], rt.usizeRem(byte as rt.usize, rt.max(3, 1))); const tags: [rt.u8, rt.u8] = slot[1]; tags[0] = tags[0] ^ byte; tags[1] = rt.u8WrappingAdd(tags[1], byte); rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(tags[0], tags[1])), undefined, true); } - for (const _79 of slots) { - const _86: [Tagged.Tagged[], [rt.u8, rt.u8]] = _79; - rt.iterForEach(rt.iterSlice(_86[0]), (v2: Tagged.Tagged): undefined => { - Tagged.put$lengths_Put_u32(v2, out); + for (const _83 of slots) { + const _90: [Tagged.Tagged[], [rt.u8, rt.u8]] = _83; + rt.iterForEach(rt.iterSlice(_90[0]), (v3: Tagged.Tagged): undefined => { + Tagged.put$lengths_Put_u32(v3, out); }); - rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_86[1][0], _86[1][1])), undefined, true); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_90[1][0], _90[1][1])), undefined, true); } } /** * Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while - * nothing points into them, the last two again beside a vector's iterator, which std - * drops, then changed in place, a pair of tags through a pointer to it, and read back. + * nothing points into them, the last two again from the values a vector's iterator gives + * beside them, which std drops, then changed in place, a pair of tags through a pointer to + * it, and read back. */ export function filled$u32_0(data: rt.ByteSlice, fill: rt.u32[], out: rt.ByteVec): void { + let row!: rt.u32[]; const item = ([new Array(0), [undefined, undefined]] as unknown) as [rt.u32[], [rt.u8, rt.u8]]; const slots: [rt.u32[], [rt.u8, rt.u8]][] = Array.from({ length: 3 }, (): [rt.u32[], [rt.u8, rt.u8]] => { return copy$mem_MaybeUninit_tuple2_array0_u32_tuple2_u8_u8(item); @@ -922,37 +1026,48 @@ export function filled$u32_0(data: rt.ByteSlice, fill: rt.u32[], out: rt.ByteVec if (_41 === rt.DONE) { break; } + const pick: rt.u32 | undefined = _41[1]; + if (pick === undefined) { + row = fill; + } else { + const v2: rt.u32 = pick; + row = Array.from({ length: 0 }, (): rt.u32 => { + return v2; + }); + } const uninit2 = _41[0]; - rt.ptrWrite(uninit2, [copy$array_u32(fill), [0, 90] as [rt.u8, rt.u8]] as [rt.u32[], [rt.u8, rt.u8]]); + rt.ptrWrite(uninit2, [copy$array_u32(row), [0, 90] as [rt.u8, rt.u8]] as [rt.u32[], [rt.u8, rt.u8]]); uninit2; } for (const byte of rt.byteSliceView(data)) { - const _58: rt.usize = rt.usizeRem(byte as rt.usize, 3); - if (!(_58 < 3)) { - rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _58); + const _62: rt.usize = rt.usizeRem(byte as rt.usize, 3); + if (!(_62 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _62); } - const slot: [rt.u32[], [rt.u8, rt.u8]] = slots[_58]; + const slot: [rt.u32[], [rt.u8, rt.u8]] = slots[_62]; rt.sliceRotateLeft(slot[0], rt.usizeRem(byte as rt.usize, rt.max(0, 1))); const tags: [rt.u8, rt.u8] = slot[1]; tags[0] = tags[0] ^ byte; tags[1] = rt.u8WrappingAdd(tags[1], byte); rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(tags[0], tags[1])), undefined, true); } - for (const _79 of slots) { - const _86: [rt.u32[], [rt.u8, rt.u8]] = _79; - rt.iterForEach(rt.iterSlice(_86[0]), (v2: rt.u32): undefined => { - put$lengths_Put_u32(v2, out); + for (const _83 of slots) { + const _90: [rt.u32[], [rt.u8, rt.u8]] = _83; + rt.iterForEach(rt.iterSlice(_90[0]), (v3: rt.u32): undefined => { + put$lengths_Put_u32(v3, out); }); - rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_86[1][0], _86[1][1])), undefined, true); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_90[1][0], _90[1][1])), undefined, true); } } /** * Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while - * nothing points into them, the last two again beside a vector's iterator, which std - * drops, then changed in place, a pair of tags through a pointer to it, and read back. + * nothing points into them, the last two again from the values a vector's iterator gives + * beside them, which std drops, then changed in place, a pair of tags through a pointer to + * it, and read back. */ export function filled$u32_1(data: rt.ByteSlice, fill: rt.u32[], out: rt.ByteVec): void { + let row!: rt.u32[]; const item = ([new Array(1), [undefined, undefined]] as unknown) as [rt.u32[], [rt.u8, rt.u8]]; const slots: [rt.u32[], [rt.u8, rt.u8]][] = Array.from({ length: 3 }, (): [rt.u32[], [rt.u8, rt.u8]] => { return copy$mem_MaybeUninit_tuple2_array1_u32_tuple2_u8_u8(item); @@ -978,37 +1093,48 @@ export function filled$u32_1(data: rt.ByteSlice, fill: rt.u32[], out: rt.ByteVec if (_41 === rt.DONE) { break; } + const pick: rt.u32 | undefined = _41[1]; + if (pick === undefined) { + row = fill; + } else { + const v2: rt.u32 = pick; + row = Array.from({ length: 1 }, (): rt.u32 => { + return v2; + }); + } const uninit2 = _41[0]; - rt.ptrWrite(uninit2, [copy$array_u32(fill), [1, 90] as [rt.u8, rt.u8]] as [rt.u32[], [rt.u8, rt.u8]]); + rt.ptrWrite(uninit2, [copy$array_u32(row), [1, 90] as [rt.u8, rt.u8]] as [rt.u32[], [rt.u8, rt.u8]]); uninit2; } for (const byte of rt.byteSliceView(data)) { - const _58: rt.usize = rt.usizeRem(byte as rt.usize, 3); - if (!(_58 < 3)) { - rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _58); + const _62: rt.usize = rt.usizeRem(byte as rt.usize, 3); + if (!(_62 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _62); } - const slot: [rt.u32[], [rt.u8, rt.u8]] = slots[_58]; + const slot: [rt.u32[], [rt.u8, rt.u8]] = slots[_62]; rt.sliceRotateLeft(slot[0], rt.usizeRem(byte as rt.usize, rt.max(1, 1))); const tags: [rt.u8, rt.u8] = slot[1]; tags[0] = tags[0] ^ byte; tags[1] = rt.u8WrappingAdd(tags[1], byte); rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(tags[0], tags[1])), undefined, true); } - for (const _79 of slots) { - const _86: [rt.u32[], [rt.u8, rt.u8]] = _79; - rt.iterForEach(rt.iterSlice(_86[0]), (v2: rt.u32): undefined => { - put$lengths_Put_u32(v2, out); + for (const _83 of slots) { + const _90: [rt.u32[], [rt.u8, rt.u8]] = _83; + rt.iterForEach(rt.iterSlice(_90[0]), (v3: rt.u32): undefined => { + put$lengths_Put_u32(v3, out); }); - rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_86[1][0], _86[1][1])), undefined, true); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_90[1][0], _90[1][1])), undefined, true); } } /** * Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while - * nothing points into them, the last two again beside a vector's iterator, which std - * drops, then changed in place, a pair of tags through a pointer to it, and read back. + * nothing points into them, the last two again from the values a vector's iterator gives + * beside them, which std drops, then changed in place, a pair of tags through a pointer to + * it, and read back. */ export function filled$u32_17(data: rt.ByteSlice, fill: rt.u32[], out: rt.ByteVec): void { + let row!: rt.u32[]; const item = ([new Array(17), [undefined, undefined]] as unknown) as [rt.u32[], [rt.u8, rt.u8]]; const slots: [rt.u32[], [rt.u8, rt.u8]][] = Array.from({ length: 3 }, (): [rt.u32[], [rt.u8, rt.u8]] => { return copy$mem_MaybeUninit_tuple2_array17_u32_tuple2_u8_u8(item); @@ -1034,37 +1160,48 @@ export function filled$u32_17(data: rt.ByteSlice, fill: rt.u32[], out: rt.ByteVe if (_41 === rt.DONE) { break; } + const pick: rt.u32 | undefined = _41[1]; + if (pick === undefined) { + row = fill; + } else { + const v2: rt.u32 = pick; + row = Array.from({ length: 17 }, (): rt.u32 => { + return v2; + }); + } const uninit2 = _41[0]; - rt.ptrWrite(uninit2, [copy$array_u32(fill), [17, 90] as [rt.u8, rt.u8]] as [rt.u32[], [rt.u8, rt.u8]]); + rt.ptrWrite(uninit2, [copy$array_u32(row), [17, 90] as [rt.u8, rt.u8]] as [rt.u32[], [rt.u8, rt.u8]]); uninit2; } for (const byte of rt.byteSliceView(data)) { - const _58: rt.usize = rt.usizeRem(byte as rt.usize, 3); - if (!(_58 < 3)) { - rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _58); + const _62: rt.usize = rt.usizeRem(byte as rt.usize, 3); + if (!(_62 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _62); } - const slot: [rt.u32[], [rt.u8, rt.u8]] = slots[_58]; + const slot: [rt.u32[], [rt.u8, rt.u8]] = slots[_62]; rt.sliceRotateLeft(slot[0], rt.usizeRem(byte as rt.usize, rt.max(17, 1))); const tags: [rt.u8, rt.u8] = slot[1]; tags[0] = tags[0] ^ byte; tags[1] = rt.u8WrappingAdd(tags[1], byte); rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(tags[0], tags[1])), undefined, true); } - for (const _79 of slots) { - const _86: [rt.u32[], [rt.u8, rt.u8]] = _79; - rt.iterForEach(rt.iterSlice(_86[0]), (v2: rt.u32): undefined => { - put$lengths_Put_u32(v2, out); + for (const _83 of slots) { + const _90: [rt.u32[], [rt.u8, rt.u8]] = _83; + rt.iterForEach(rt.iterSlice(_90[0]), (v3: rt.u32): undefined => { + put$lengths_Put_u32(v3, out); }); - rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_86[1][0], _86[1][1])), undefined, true); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_90[1][0], _90[1][1])), undefined, true); } } /** * Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while - * nothing points into them, the last two again beside a vector's iterator, which std - * drops, then changed in place, a pair of tags through a pointer to it, and read back. + * nothing points into them, the last two again from the values a vector's iterator gives + * beside them, which std drops, then changed in place, a pair of tags through a pointer to + * it, and read back. */ export function filled$u32_3(data: rt.ByteSlice, fill: rt.u32[], out: rt.ByteVec): void { + let row!: rt.u32[]; const item = ([new Array(3), [undefined, undefined]] as unknown) as [rt.u32[], [rt.u8, rt.u8]]; const slots: [rt.u32[], [rt.u8, rt.u8]][] = Array.from({ length: 3 }, (): [rt.u32[], [rt.u8, rt.u8]] => { return copy$mem_MaybeUninit_tuple2_array3_u32_tuple2_u8_u8(item); @@ -1090,37 +1227,48 @@ export function filled$u32_3(data: rt.ByteSlice, fill: rt.u32[], out: rt.ByteVec if (_41 === rt.DONE) { break; } + const pick: rt.u32 | undefined = _41[1]; + if (pick === undefined) { + row = fill; + } else { + const v2: rt.u32 = pick; + row = Array.from({ length: 3 }, (): rt.u32 => { + return v2; + }); + } const uninit2 = _41[0]; - rt.ptrWrite(uninit2, [copy$array_u32(fill), [3, 90] as [rt.u8, rt.u8]] as [rt.u32[], [rt.u8, rt.u8]]); + rt.ptrWrite(uninit2, [copy$array_u32(row), [3, 90] as [rt.u8, rt.u8]] as [rt.u32[], [rt.u8, rt.u8]]); uninit2; } for (const byte of rt.byteSliceView(data)) { - const _58: rt.usize = rt.usizeRem(byte as rt.usize, 3); - if (!(_58 < 3)) { - rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _58); + const _62: rt.usize = rt.usizeRem(byte as rt.usize, 3); + if (!(_62 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _62); } - const slot: [rt.u32[], [rt.u8, rt.u8]] = slots[_58]; + const slot: [rt.u32[], [rt.u8, rt.u8]] = slots[_62]; rt.sliceRotateLeft(slot[0], rt.usizeRem(byte as rt.usize, rt.max(3, 1))); const tags: [rt.u8, rt.u8] = slot[1]; tags[0] = tags[0] ^ byte; tags[1] = rt.u8WrappingAdd(tags[1], byte); rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(tags[0], tags[1])), undefined, true); } - for (const _79 of slots) { - const _86: [rt.u32[], [rt.u8, rt.u8]] = _79; - rt.iterForEach(rt.iterSlice(_86[0]), (v2: rt.u32): undefined => { - put$lengths_Put_u32(v2, out); + for (const _83 of slots) { + const _90: [rt.u32[], [rt.u8, rt.u8]] = _83; + rt.iterForEach(rt.iterSlice(_90[0]), (v3: rt.u32): undefined => { + put$lengths_Put_u32(v3, out); }); - rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_86[1][0], _86[1][1])), undefined, true); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_90[1][0], _90[1][1])), undefined, true); } } /** * Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while - * nothing points into them, the last two again beside a vector's iterator, which std - * drops, then changed in place, a pair of tags through a pointer to it, and read back. + * nothing points into them, the last two again from the values a vector's iterator gives + * beside them, which std drops, then changed in place, a pair of tags through a pointer to + * it, and read back. */ export function filled$u8_0(data: rt.ByteSlice, fill: Uint8Array, out: rt.ByteVec): void { + let row!: Uint8Array; const item = ([new Uint8Array(0), [undefined, undefined]] as unknown) as [Uint8Array, [rt.u8, rt.u8]]; const slots: [Uint8Array, [rt.u8, rt.u8]][] = Array.from({ length: 3 }, (): [Uint8Array, [rt.u8, rt.u8]] => { return copy$mem_MaybeUninit_tuple2_array0_u8_tuple2_u8_u8(item); @@ -1146,37 +1294,45 @@ export function filled$u8_0(data: rt.ByteSlice, fill: Uint8Array, out: rt.ByteVe if (_41 === rt.DONE) { break; } + const pick: rt.u8 | undefined = _41[1]; + if (pick === undefined) { + row = fill; + } else { + row = rt.bytes(0).fill(pick); + } const uninit2 = _41[0]; - rt.ptrWrite(uninit2, [copy$array_u8(fill), [0, 90] as [rt.u8, rt.u8]] as [Uint8Array, [rt.u8, rt.u8]]); + rt.ptrWrite(uninit2, [copy$array_u8(row), [0, 90] as [rt.u8, rt.u8]] as [Uint8Array, [rt.u8, rt.u8]]); uninit2; } for (const byte of rt.byteSliceView(data)) { - const _58: rt.usize = rt.usizeRem(byte as rt.usize, 3); - if (!(_58 < 3)) { - rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _58); + const _62: rt.usize = rt.usizeRem(byte as rt.usize, 3); + if (!(_62 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _62); } - const slot: [Uint8Array, [rt.u8, rt.u8]] = slots[_58]; + const slot: [Uint8Array, [rt.u8, rt.u8]] = slots[_62]; rt.byteSliceRotateLeft(rt.byteSliceFrom(slot[0]), rt.usizeRem(byte as rt.usize, rt.max(0, 1))); const tags: [rt.u8, rt.u8] = slot[1]; tags[0] = tags[0] ^ byte; tags[1] = rt.u8WrappingAdd(tags[1], byte); rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(tags[0], tags[1])), undefined, true); } - for (const _79 of slots) { - const _86: [Uint8Array, [rt.u8, rt.u8]] = _79; - rt.iterForEach(rt.iterSlice(rt.byteSliceView(rt.byteSliceFrom(_86[0]))), (v2: rt.u8): undefined => { - put$lengths_Put_u8(v2, out); + for (const _83 of slots) { + const _90: [Uint8Array, [rt.u8, rt.u8]] = _83; + rt.iterForEach(rt.iterSlice(rt.byteSliceView(rt.byteSliceFrom(_90[0]))), (v3: rt.u8): undefined => { + put$lengths_Put_u8(v3, out); }); - rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_86[1][0], _86[1][1])), undefined, true); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_90[1][0], _90[1][1])), undefined, true); } } /** * Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while - * nothing points into them, the last two again beside a vector's iterator, which std - * drops, then changed in place, a pair of tags through a pointer to it, and read back. + * nothing points into them, the last two again from the values a vector's iterator gives + * beside them, which std drops, then changed in place, a pair of tags through a pointer to + * it, and read back. */ export function filled$u8_1(data: rt.ByteSlice, fill: Uint8Array, out: rt.ByteVec): void { + let row!: Uint8Array; const item = ([new Uint8Array(1), [undefined, undefined]] as unknown) as [Uint8Array, [rt.u8, rt.u8]]; const slots: [Uint8Array, [rt.u8, rt.u8]][] = Array.from({ length: 3 }, (): [Uint8Array, [rt.u8, rt.u8]] => { return copy$mem_MaybeUninit_tuple2_array1_u8_tuple2_u8_u8(item); @@ -1202,37 +1358,45 @@ export function filled$u8_1(data: rt.ByteSlice, fill: Uint8Array, out: rt.ByteVe if (_41 === rt.DONE) { break; } + const pick: rt.u8 | undefined = _41[1]; + if (pick === undefined) { + row = fill; + } else { + row = rt.bytes(1).fill(pick); + } const uninit2 = _41[0]; - rt.ptrWrite(uninit2, [copy$array_u8(fill), [1, 90] as [rt.u8, rt.u8]] as [Uint8Array, [rt.u8, rt.u8]]); + rt.ptrWrite(uninit2, [copy$array_u8(row), [1, 90] as [rt.u8, rt.u8]] as [Uint8Array, [rt.u8, rt.u8]]); uninit2; } for (const byte of rt.byteSliceView(data)) { - const _58: rt.usize = rt.usizeRem(byte as rt.usize, 3); - if (!(_58 < 3)) { - rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _58); + const _62: rt.usize = rt.usizeRem(byte as rt.usize, 3); + if (!(_62 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _62); } - const slot: [Uint8Array, [rt.u8, rt.u8]] = slots[_58]; + const slot: [Uint8Array, [rt.u8, rt.u8]] = slots[_62]; rt.byteSliceRotateLeft(rt.byteSliceFrom(slot[0]), rt.usizeRem(byte as rt.usize, rt.max(1, 1))); const tags: [rt.u8, rt.u8] = slot[1]; tags[0] = tags[0] ^ byte; tags[1] = rt.u8WrappingAdd(tags[1], byte); rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(tags[0], tags[1])), undefined, true); } - for (const _79 of slots) { - const _86: [Uint8Array, [rt.u8, rt.u8]] = _79; - rt.iterForEach(rt.iterSlice(rt.byteSliceView(rt.byteSliceFrom(_86[0]))), (v2: rt.u8): undefined => { - put$lengths_Put_u8(v2, out); + for (const _83 of slots) { + const _90: [Uint8Array, [rt.u8, rt.u8]] = _83; + rt.iterForEach(rt.iterSlice(rt.byteSliceView(rt.byteSliceFrom(_90[0]))), (v3: rt.u8): undefined => { + put$lengths_Put_u8(v3, out); }); - rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_86[1][0], _86[1][1])), undefined, true); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_90[1][0], _90[1][1])), undefined, true); } } /** * Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while - * nothing points into them, the last two again beside a vector's iterator, which std - * drops, then changed in place, a pair of tags through a pointer to it, and read back. + * nothing points into them, the last two again from the values a vector's iterator gives + * beside them, which std drops, then changed in place, a pair of tags through a pointer to + * it, and read back. */ export function filled$u8_17(data: rt.ByteSlice, fill: Uint8Array, out: rt.ByteVec): void { + let row!: Uint8Array; const item = ([new Uint8Array(17), [undefined, undefined]] as unknown) as [Uint8Array, [rt.u8, rt.u8]]; const slots: [Uint8Array, [rt.u8, rt.u8]][] = Array.from({ length: 3 }, (): [Uint8Array, [rt.u8, rt.u8]] => { return copy$mem_MaybeUninit_tuple2_array17_u8_tuple2_u8_u8(item); @@ -1258,37 +1422,45 @@ export function filled$u8_17(data: rt.ByteSlice, fill: Uint8Array, out: rt.ByteV if (_41 === rt.DONE) { break; } + const pick: rt.u8 | undefined = _41[1]; + if (pick === undefined) { + row = fill; + } else { + row = rt.bytes(17).fill(pick); + } const uninit2 = _41[0]; - rt.ptrWrite(uninit2, [copy$array_u8(fill), [17, 90] as [rt.u8, rt.u8]] as [Uint8Array, [rt.u8, rt.u8]]); + rt.ptrWrite(uninit2, [copy$array_u8(row), [17, 90] as [rt.u8, rt.u8]] as [Uint8Array, [rt.u8, rt.u8]]); uninit2; } for (const byte of rt.byteSliceView(data)) { - const _58: rt.usize = rt.usizeRem(byte as rt.usize, 3); - if (!(_58 < 3)) { - rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _58); + const _62: rt.usize = rt.usizeRem(byte as rt.usize, 3); + if (!(_62 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _62); } - const slot: [Uint8Array, [rt.u8, rt.u8]] = slots[_58]; + const slot: [Uint8Array, [rt.u8, rt.u8]] = slots[_62]; rt.byteSliceRotateLeft(rt.byteSliceFrom(slot[0]), rt.usizeRem(byte as rt.usize, rt.max(17, 1))); const tags: [rt.u8, rt.u8] = slot[1]; tags[0] = tags[0] ^ byte; tags[1] = rt.u8WrappingAdd(tags[1], byte); rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(tags[0], tags[1])), undefined, true); } - for (const _79 of slots) { - const _86: [Uint8Array, [rt.u8, rt.u8]] = _79; - rt.iterForEach(rt.iterSlice(rt.byteSliceView(rt.byteSliceFrom(_86[0]))), (v2: rt.u8): undefined => { - put$lengths_Put_u8(v2, out); + for (const _83 of slots) { + const _90: [Uint8Array, [rt.u8, rt.u8]] = _83; + rt.iterForEach(rt.iterSlice(rt.byteSliceView(rt.byteSliceFrom(_90[0]))), (v3: rt.u8): undefined => { + put$lengths_Put_u8(v3, out); }); - rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_86[1][0], _86[1][1])), undefined, true); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_90[1][0], _90[1][1])), undefined, true); } } /** * Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while - * nothing points into them, the last two again beside a vector's iterator, which std - * drops, then changed in place, a pair of tags through a pointer to it, and read back. + * nothing points into them, the last two again from the values a vector's iterator gives + * beside them, which std drops, then changed in place, a pair of tags through a pointer to + * it, and read back. */ export function filled$u8_3(data: rt.ByteSlice, fill: Uint8Array, out: rt.ByteVec): void { + let row!: Uint8Array; const item = ([new Uint8Array(3), [undefined, undefined]] as unknown) as [Uint8Array, [rt.u8, rt.u8]]; const slots: [Uint8Array, [rt.u8, rt.u8]][] = Array.from({ length: 3 }, (): [Uint8Array, [rt.u8, rt.u8]] => { return copy$mem_MaybeUninit_tuple2_array3_u8_tuple2_u8_u8(item); @@ -1314,28 +1486,34 @@ export function filled$u8_3(data: rt.ByteSlice, fill: Uint8Array, out: rt.ByteVe if (_41 === rt.DONE) { break; } + const pick: rt.u8 | undefined = _41[1]; + if (pick === undefined) { + row = fill; + } else { + row = rt.bytes(3).fill(pick); + } const uninit2 = _41[0]; - rt.ptrWrite(uninit2, [copy$array_u8(fill), [3, 90] as [rt.u8, rt.u8]] as [Uint8Array, [rt.u8, rt.u8]]); + rt.ptrWrite(uninit2, [copy$array_u8(row), [3, 90] as [rt.u8, rt.u8]] as [Uint8Array, [rt.u8, rt.u8]]); uninit2; } for (const byte of rt.byteSliceView(data)) { - const _58: rt.usize = rt.usizeRem(byte as rt.usize, 3); - if (!(_58 < 3)) { - rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _58); + const _62: rt.usize = rt.usizeRem(byte as rt.usize, 3); + if (!(_62 < 3)) { + rt.panic("index out of bounds: the len is " + 3 + " but the index is " + _62); } - const slot: [Uint8Array, [rt.u8, rt.u8]] = slots[_58]; + const slot: [Uint8Array, [rt.u8, rt.u8]] = slots[_62]; rt.byteSliceRotateLeft(rt.byteSliceFrom(slot[0]), rt.usizeRem(byte as rt.usize, rt.max(3, 1))); const tags: [rt.u8, rt.u8] = slot[1]; tags[0] = tags[0] ^ byte; tags[1] = rt.u8WrappingAdd(tags[1], byte); rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(tags[0], tags[1])), undefined, true); } - for (const _79 of slots) { - const _86: [Uint8Array, [rt.u8, rt.u8]] = _79; - rt.iterForEach(rt.iterSlice(rt.byteSliceView(rt.byteSliceFrom(_86[0]))), (v2: rt.u8): undefined => { - put$lengths_Put_u8(v2, out); + for (const _83 of slots) { + const _90: [Uint8Array, [rt.u8, rt.u8]] = _83; + rt.iterForEach(rt.iterSlice(rt.byteSliceView(rt.byteSliceFrom(_90[0]))), (v3: rt.u8): undefined => { + put$lengths_Put_u8(v3, out); }); - rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_86[1][0], _86[1][1])), undefined, true); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(_90[1][0], _90[1][1])), undefined, true); } } @@ -1779,4 +1957,156 @@ export function swapped$u8_3(data: rt.ByteSlice, rows: Uint8Array[], out: rt.Byt } } +export const CLONES: rt.LocalKey> = /* @__PURE__ */ new rt.LocalKey(CLONES$init, false); + +export function CLONES$init(): rt.RefCell { + return new rt.RefCell(new rt.ByteVec()); +} + +/** + * Rows of `T`'s values copied out of an array and repeated by `vec!`, which runs `T`'s + * `Clone`, each vector then [`rewritten`], every row kept apart from the others and from + * the array's. + */ +export function repeated$lengths_Loud(_dataData: Uint8Array, _dataStart: number, dataLen: number, x: Loud.Loud, y: Loud.Loud, out: rt.ByteVec): void { + const rows: Row.Row[] = [new Row.Row(y, [258, 772] as [rt.u16, rt.u16]), new Row.Row(x, [1286, 1800] as [rt.u16, rt.u16])]; + const copies: Row.Row[] = rt.iterToArray(rt.iterCopied(rt.iterSlice(rows), copy$lengths_Row_lengths_Loud), undefined, 6, true); + if (true) { + const _16: Row.Row = new Row.Row(x, [12337, 12851] as [rt.u16, rt.u16]); + copies[rt.idx(copies, 0)] = _16; + const tags: [rt.u16, rt.u16] = copies[rt.idx(copies, 0)]._1; + tags[0] = tags[0] ^ 4112; + } + if (true) { + const at3 = rt.idx(copies, 1); + copies[at3]._1[1] = copies[at3]._1[1] ^ 8224; + } + for (const _29 of copies) { + const value: Loud.Loud = _29._0; + const a: rt.u16 = _29._1[0]; + const b: rt.u16 = _29._1[1]; + Loud.put$lengths_Put(value, out); + rt.iterExtendBytes(out, rt.iterChain(rt.iterSlice(rt.u16ToBeBytes(a).reverse()), rt.iterSlice(rt.u16ToBeBytes(b).reverse())), undefined, true); + } + const repeats: Row.Row[] = rt.vecFromElem(new Row.Row(x, [2314, 2828] as [rt.u16, rt.u16]), rt.usizeAdd(1, rt.usizeRem(dataLen, 3)), Row.clone$Clone_lengths_Loud); + if (rt.usizeAdd(1, rt.usizeRem(dataLen, 3)) > 0) { + const _56: Row.Row = new Row.Row(x, [12337, 12851] as [rt.u16, rt.u16]); + repeats[rt.idx(repeats, 0)] = _56; + const tags2: [rt.u16, rt.u16] = repeats[rt.idx(repeats, 0)]._1; + tags2[0] = tags2[0] ^ 4112; + } + if (rt.usizeAdd(1, rt.usizeRem(dataLen, 3)) > 1) { + const at6 = rt.idx(repeats, 1); + repeats[at6]._1[1] = repeats[at6]._1[1] ^ 8224; + } + for (const _74 of repeats) { + const value2: Loud.Loud = _74._0; + const a2: rt.u16 = _74._1[0]; + const b2: rt.u16 = _74._1[1]; + Loud.put$lengths_Put(value2, out); + rt.iterExtendBytes(out, rt.iterChain(rt.iterSlice(rt.u16ToBeBytes(a2).reverse()), rt.iterSlice(rt.u16ToBeBytes(b2).reverse())), undefined, true); + } + for (const _90 of rows) { + Loud.put$lengths_Put(_90._0, out); + rt.iterExtendBytes(out, rt.iterChain(rt.iterSlice(rt.u16ToBeBytes(_90._1[0]).reverse()), rt.iterSlice(rt.u16ToBeBytes(_90._1[1]).reverse())), undefined, true); + } +} + +/** + * Rows of `T`'s values copied out of an array and repeated by `vec!`, which runs `T`'s + * `Clone`, each vector then [`rewritten`], every row kept apart from the others and from + * the array's. + */ +export function repeated$u8(_dataData: Uint8Array, _dataStart: number, dataLen: number, x: rt.u8, y: rt.u8, out: rt.ByteVec): void { + const rows: Row.Row[] = [new Row.Row(y, [258, 772] as [rt.u16, rt.u16]), new Row.Row(x, [1286, 1800] as [rt.u16, rt.u16])]; + const copies: Row.Row[] = rt.iterToArray(rt.iterCopied(rt.iterSlice(rows), copy$lengths_Row_u8), undefined, 6, true); + if (true) { + const _16: Row.Row = new Row.Row(x, [12337, 12851] as [rt.u16, rt.u16]); + copies[rt.idx(copies, 0)] = _16; + const tags: [rt.u16, rt.u16] = copies[rt.idx(copies, 0)]._1; + tags[0] = tags[0] ^ 4112; + } + if (true) { + const at3 = rt.idx(copies, 1); + copies[at3]._1[1] = copies[at3]._1[1] ^ 8224; + } + for (const _29 of copies) { + const value: rt.u8 = _29._0; + const a: rt.u16 = _29._1[0]; + const b: rt.u16 = _29._1[1]; + put$lengths_Put_u8(value, out); + rt.iterExtendBytes(out, rt.iterChain(rt.iterSlice(rt.u16ToBeBytes(a).reverse()), rt.iterSlice(rt.u16ToBeBytes(b).reverse())), undefined, true); + } + const repeats: Row.Row[] = rt.vecFromElem(new Row.Row(x, [2314, 2828] as [rt.u16, rt.u16]), rt.usizeAdd(1, rt.usizeRem(dataLen, 3)), copy$lengths_Row_u8); + if (rt.usizeAdd(1, rt.usizeRem(dataLen, 3)) > 0) { + const _56: Row.Row = new Row.Row(x, [12337, 12851] as [rt.u16, rt.u16]); + repeats[rt.idx(repeats, 0)] = _56; + const tags2: [rt.u16, rt.u16] = repeats[rt.idx(repeats, 0)]._1; + tags2[0] = tags2[0] ^ 4112; + } + if (rt.usizeAdd(1, rt.usizeRem(dataLen, 3)) > 1) { + const at6 = rt.idx(repeats, 1); + repeats[at6]._1[1] = repeats[at6]._1[1] ^ 8224; + } + for (const _74 of repeats) { + const value2: rt.u8 = _74._0; + const a2: rt.u16 = _74._1[0]; + const b2: rt.u16 = _74._1[1]; + put$lengths_Put_u8(value2, out); + rt.iterExtendBytes(out, rt.iterChain(rt.iterSlice(rt.u16ToBeBytes(a2).reverse()), rt.iterSlice(rt.u16ToBeBytes(b2).reverse())), undefined, true); + } + for (const _90 of rows) { + put$lengths_Put_u8(_90._0, out); + rt.iterExtendBytes(out, rt.iterChain(rt.iterSlice(rt.u16ToBeBytes(_90._1[0]).reverse()), rt.iterSlice(rt.u16ToBeBytes(_90._1[1]).reverse())), undefined, true); + } +} + +/** [`repeated`] of the crate's own type, in a body generic over none. */ +export function loud(data: rt.ByteSlice, out: rt.ByteVec): void { + const byte: (a0: rt.usize) => rt.u16 = (at: rt.usize): rt.u16 => { + return option_unwrapOr$0r2bmpr(rt.byteSliceGet(data, at), 0) as rt.u16; + }; + const rows: Row.Row[] = [new Row.Row({ _0: byte(0) }, [258, 772] as [rt.u16, rt.u16]), new Row.Row({ _0: byte(2) }, [1286, 1800] as [rt.u16, rt.u16])]; + const copies: Row.Row[] = rt.iterToArray(rt.iterCopied(rt.iterSlice(rows), copy$lengths_Row_lengths_Loud), undefined, 6, true); + if (true) { + const _23: Row.Row = new Row.Row({ _0: byte(2) }, [12337, 12851] as [rt.u16, rt.u16]); + copies[rt.idx(copies, 0)] = _23; + const tags: [rt.u16, rt.u16] = copies[rt.idx(copies, 0)]._1; + tags[0] = tags[0] ^ 4112; + } + if (true) { + const at4 = rt.idx(copies, 1); + copies[at4]._1[1] = copies[at4]._1[1] ^ 8224; + } + for (const _40 of copies) { + const value: Loud.Loud = _40._0; + const a: rt.u16 = _40._1[0]; + const b: rt.u16 = _40._1[1]; + Loud.put$lengths_Put(value, out); + rt.iterExtendBytes(out, rt.iterChain(rt.iterSlice(rt.u16ToBeBytes(a).reverse()), rt.iterSlice(rt.u16ToBeBytes(b).reverse())), undefined, true); + } + const repeats: Row.Row[] = rt.vecFromElem(new Row.Row({ _0: byte(2) }, [2314, 2828] as [rt.u16, rt.u16]), rt.usizeAdd(1, rt.usizeRem(data.length, 3)), Row.clone$Clone_lengths_Loud); + if (rt.usizeAdd(1, rt.usizeRem(data.length, 3)) > 0) { + const _71: Row.Row = new Row.Row({ _0: byte(2) }, [12337, 12851] as [rt.u16, rt.u16]); + repeats[rt.idx(repeats, 0)] = _71; + const tags2: [rt.u16, rt.u16] = repeats[rt.idx(repeats, 0)]._1; + tags2[0] = tags2[0] ^ 4112; + } + if (rt.usizeAdd(1, rt.usizeRem(data.length, 3)) > 1) { + const at7 = rt.idx(repeats, 1); + repeats[at7]._1[1] = repeats[at7]._1[1] ^ 8224; + } + for (const _93 of repeats) { + const value2: Loud.Loud = _93._0; + const a2: rt.u16 = _93._1[0]; + const b2: rt.u16 = _93._1[1]; + Loud.put$lengths_Put(value2, out); + rt.iterExtendBytes(out, rt.iterChain(rt.iterSlice(rt.u16ToBeBytes(a2).reverse()), rt.iterSlice(rt.u16ToBeBytes(b2).reverse())), undefined, true); + } + for (const _109 of rows) { + Loud.put$lengths_Put(_109._0, out); + rt.iterExtendBytes(out, rt.iterChain(rt.iterSlice(rt.u16ToBeBytes(_109._1[0]).reverse()), rt.iterSlice(rt.u16ToBeBytes(_109._1[1]).reverse())), undefined, true); + } +} + //# sourceMappingURL=lengths.ts.map diff --git a/ts/fixtures/lang/lengths/expected/lib.ts b/ts/fixtures/lang/lengths/expected/lib.ts index 83a0ea0d3..d632df492 100644 --- a/ts/fixtures/lang/lengths/expected/lib.ts +++ b/ts/fixtures/lang/lengths/expected/lib.ts @@ -2,6 +2,8 @@ import * as rt from "./rt.ts"; import { lengths } from "./lengths.ts"; +import type * as Loud from "./lengths.Loud.ts"; +import * as Row from "./lengths.Row.ts"; import * as Tagged from "./lengths.Tagged.ts"; export function copy$Option_lengths_Tagged_array0_u32(v: Tagged.Tagged | undefined): Tagged.Tagged | undefined { @@ -64,6 +66,14 @@ export function copy$array_u8(v: Uint8Array): Uint8Array { return v.slice(); } +export function copy$lengths_Row_lengths_Loud(v: Row.Row): Row.Row { + return new Row.Row(v._0, copy$tuple2_u16_u16(v._1)); +} + +export function copy$lengths_Row_u8(v: Row.Row): Row.Row { + return new Row.Row(v._0, copy$tuple2_u16_u16(v._1)); +} + export function copy$lengths_Tagged_array0_u32(v: Tagged.Tagged): Tagged.Tagged { return new Tagged.Tagged(copy$array_u32(v._0), v._1); } @@ -264,6 +274,10 @@ export function copy$mem_MaybeUninit_tuple2_u8_u8(v: [rt.u8, rt.u8]): [rt.u8, rt return [v[0], v[1]]; } +export function copy$tuple2_u16_u16(v: [rt.u16, rt.u16]): [rt.u16, rt.u16] { + return [v[0], v[1]]; +} + /** * Each case's name and what it runs. The first two bytes, big-endian, pick one modulo * their count, so a case added at the end moves no other. diff --git a/ts/fixtures/lang/lengths/src/lengths.rs b/ts/fixtures/lang/lengths/src/lengths.rs index 4064c8139..b39edbec1 100644 --- a/ts/fixtures/lang/lengths/src/lengths.rs +++ b/ts/fixtures/lang/lengths/src/lengths.rs @@ -1,18 +1,28 @@ //! Functions generic over an array's length whose calls take values of types holding it: //! arrays of bytes, of a type parameter's values, and of arrays, each at a length of none, //! one, and more. Their writes are judged in the bounds of the body making them, as -//! filling memory nothing points into yet or giving what they replace another object. +//! filling memory nothing points into yet or giving what they replace another object, +//! through what std's iterators give back and what `copied` and `vec![x; n]` make of a +//! `Copy` type whose `Clone` logs and panics. +use std::cell::RefCell; use std::mem::MaybeUninit; /// Each case at the length `kind` picks. pub fn lengths(kind: u8, data: &[u8], out: &mut Vec) { + // What a case that panicked left, which a translation outlives, as native Rust's trap does not. + CLONES.with_borrow_mut(Vec::clear); match kind % 4 { 0 => each::<0>(data, out), 1 => each::<1>(data, out), 2 => each::<3>(data, out), _ => each::<17>(data, out), } + let byte = |at: usize| u16::from(data.get(at).copied().unwrap_or(0)); + repeated::(data, 0x41, 0x42, out); + repeated::(data, Loud(byte(1)), Loud(byte(0)), out); + loud(data, out); + CLONES.with_borrow_mut(|log| out.extend(log.drain(..))); } fn each(data: &[u8], out: &mut Vec) { @@ -83,8 +93,9 @@ fn recloned, const N: usize>(rows: &[[T; N]], out: &mut Vec< } /// Slots of `MaybeUninit` arrays of `T`, each written whole through an iterator while -/// nothing points into them, the last two again beside a vector's iterator, which std -/// drops, then changed in place, a pair of tags through a pointer to it, and read back. +/// nothing points into them, the last two again from the values a vector's iterator gives +/// beside them, which std drops, then changed in place, a pair of tags through a pointer to +/// it, and read back. fn filled(data: &[u8], fill: [T; N], out: &mut Vec) { let mut slots: [MaybeUninit<([T; N], (u8, u8))>; 3] = [const { MaybeUninit::uninit() }; 3]; for (slot, at) in slots.iter_mut().zip(0u8..) { @@ -94,8 +105,12 @@ fn filled(data: &[u8], fill: [T; N], out: &mut Ve for &v in &fill { picks.push(Some(v)); } - for (slot, _) in slots.iter_mut().skip(1).zip(picks) { - slot.write((fill, (N as u8, 0x5a))); + for (slot, pick) in slots.iter_mut().skip(1).zip(picks) { + let row = match pick { + Some(v) => [v; N], + None => fill, + }; + slot.write((row, (N as u8, 0x5a))); } for &byte in data { let slot = unsafe { slots[usize::from(byte) % 3].assume_init_mut() }; @@ -168,3 +183,80 @@ fn swapped, const N: usize>(data: &[u8], rows: &[[T; N]], ou out.extend(row.iter().chain(grid.iter().flatten()).map(|&x| x.into() as u8)); } } + +thread_local! { + /// The value of each `Loud` cloned, in order. + static CLONES: RefCell> = const { RefCell::new(Vec::new()) }; +} + +/// A `Copy` type whose `Clone`, written by hand, logs its value, panics on `0xff`, and +/// counts up, so a clone tells from a copy: `copied` never calls it, and `vec![x; n]` calls +/// it `n - 1` times. +#[derive(Copy)] +struct Loud(u16); + +#[allow(clippy::non_canonical_clone_impl, reason = "a `Clone` that differs from the copy")] +impl Clone for Loud { + fn clone(&self) -> Self { + CLONES.with_borrow_mut(|log| log.extend(self.0.to_le_bytes())); + assert_ne!(self.0, 0xff, "a clone of 0xff"); + Self(self.0.wrapping_add(1)) + } +} + +impl Put for Loud { + fn put(&self, out: &mut Vec) { + out.extend(self.0.to_le_bytes()); + } +} + +/// A value and a pair of tags kept as an object, of no byte held in place. +#[derive(Clone, Copy)] +struct Row(T, (u16, u16)); + +/// The first row of a vector of `$len` written whole and its tags changed through a pointer +/// to them, the second's changed in place, and each row put. +macro_rules! rewritten { + ($rows:ident, $len:expr, $x:expr, $out:ident) => { + if $len > 0 { + $rows[0] = Row($x, (0x3031, 0x3233)); + let tags = &raw mut $rows[0].1; + unsafe { (*tags).0 ^= 0x1010 } + } + if $len > 1 { + $rows[1].1.1 ^= 0x2020; + } + for Row(value, (a, b)) in $rows { + value.put($out); + $out.extend(a.to_le_bytes().into_iter().chain(b.to_le_bytes())); + } + }; +} + +/// [`repeated`]'s body, over `$x`'s type. +macro_rules! repeated { + ($data:ident, $x:expr, $y:expr, $out:ident) => {{ + let rows = [Row($y, (0x0102, 0x0304)), Row($x, (0x0506, 0x0708))]; + let mut copies: Vec<_> = rows.iter().copied().collect(); + rewritten!(copies, 2, $x, $out); + let mut repeats = vec![Row($x, (0x090a, 0x0b0c)); 1 + $data.len() % 3]; + rewritten!(repeats, 1 + $data.len() % 3, $x, $out); + for Row(value, (a, b)) in &rows { + value.put($out); + $out.extend(a.to_le_bytes().into_iter().chain(b.to_le_bytes())); + } + }}; +} + +/// Rows of `T`'s values copied out of an array and repeated by `vec!`, which runs `T`'s +/// `Clone`, each vector then [`rewritten`], every row kept apart from the others and from +/// the array's. +fn repeated(data: &[u8], x: T, y: T, out: &mut Vec) { + repeated!(data, x, y, out); +} + +/// [`repeated`] of the crate's own type, in a body generic over none. +fn loud(data: &[u8], out: &mut Vec) { + let byte = |at: usize| u16::from(data.get(at).copied().unwrap_or(0)); + repeated!(data, Loud(byte(2)), Loud(byte(0)), out); +} diff --git a/ts/fixtures/reject/census.txt b/ts/fixtures/reject/census.txt index ef87004bd..461364239 100644 --- a/ts/fixtures/reject/census.txt +++ b/ts/fixtures/reject/census.txt @@ -26,6 +26,7 @@ fixtures/reject/src/clones.rs:kept_slots+5:2: a raw pointer to `(u8, u8)` in `([ fixtures/reject/src/clones.rs:moved_slots+5:2: a raw pointer to `(u8, u8)` in `(clones::Dropped, (u8, u8))`, which the crate may put another object in place of fixtures/reject/src/clones.rs:recloned+1:4: `slice::clone_from_slice` of `clones::Reused`, whose `clone_from` is its own, which is not supported yet fixtures/reject/src/clones.rs:refilled+1:4: `slice::fill` of `clones::Reused`, whose `clone_from` is its own, which is not supported yet +fixtures/reject/src/clones.rs:stashed_slots+5:19: a raw pointer to `(u8, u8)` in `([u8; 2], (u8, u8))`, which the crate may put another object in place of fixtures/reject/src/clones.rs:vec_clone_from+1:4: `Clone::clone_from` of `std::vec::Vec`, whose `clone_from` is its own, which is not supported yet fixtures/reject/src/config.rs:Meters+0:1: a printable type must implement `Display` or `Debug` fixtures/reject/src/config.rs:generic+0:51: unsupported type `f16` diff --git a/ts/fixtures/reject/expected.txt b/ts/fixtures/reject/expected.txt index 36541ec3c..f261a1624 100644 --- a/ts/fixtures/reject/expected.txt +++ b/ts/fixtures/reject/expected.txt @@ -27,6 +27,7 @@ fixtures/reject/src/buffers.rs:shared+1:2: a coercion to `std::sync::Arc<[u8]>` fixtures/reject/src/clones.rs:greatest_slot+6:13: a raw pointer to `(u8, u8)` in `([clones::Greatest; 2], (u8, u8))`, which the crate may put another object in place of fixtures/reject/src/clones.rs:recloned+1:4: `slice::clone_from_slice` of `clones::Reused`, whose `clone_from` is its own, which is not supported yet fixtures/reject/src/clones.rs:refilled+1:4: `slice::fill` of `clones::Reused`, whose `clone_from` is its own, which is not supported yet +fixtures/reject/src/clones.rs:stashed_slots+5:19: a raw pointer to `(u8, u8)` in `([u8; 2], (u8, u8))`, which the crate may put another object in place of fixtures/reject/src/clones.rs:tagged_slots!+2:23: a raw pointer to `(u8, u8)` in `([clones::Cloned; 2], (u8, u8))`, which the crate may put another object in place of fixtures/reject/src/clones.rs:tagged_slots!+2:23: a raw pointer to `(u8, u8)` in `([clones::Touched; 2], (u8, u8))`, which the crate may put another object in place of fixtures/reject/src/clones.rs:tagged_slots!+2:23: a raw pointer to `(u8, u8)` in `(clones::Dropped, (u8, u8))`, which the crate may put another object in place of diff --git a/ts/fixtures/reject/src/clones.rs b/ts/fixtures/reject/src/clones.rs index 8655caa3b..9eddac8f0 100644 --- a/ts/fixtures/reject/src/clones.rs +++ b/ts/fixtures/reject/src/clones.rs @@ -122,3 +122,19 @@ fn given_slots(fill: [T; 2]) -> u8 { } tagged_slots!(slots) } + +/// Slots written whole in a loop after a pointer to the first's tags is kept by a function +/// generic over what it keeps, which sees the pointer only as a type parameter's value. +pub fn stashed_slots(fill: [u8; 2]) -> u8 { + let mut slots: [std::mem::MaybeUninit<([u8; 2], (u8, u8))>; 2] = [const { std::mem::MaybeUninit::uninit() }; 2]; + let mut kept = Vec::new(); + for slot in slots.iter_mut() { + slot.write((fill, (0, 1))); + stash((unsafe { &raw mut slot.assume_init_mut().1 }, 0), &mut kept); + } + unsafe { (*kept[0]).0 } +} + +fn stash(pair: (T, u8), kept: &mut Vec) { + kept.push(pair.0); +} diff --git a/ts/fixtures/reject/ts.toml b/ts/fixtures/reject/ts.toml index 2e364da1c..a273e0717 100644 --- a/ts/fixtures/reject/ts.toml +++ b/ts/fixtures/reject/ts.toml @@ -20,6 +20,7 @@ roots = [ "clones::recloned", "clones::refilled", "clones::slice_of_object", + "clones::stashed_slots", "clones::touched_slots", "clones::vec_clone_from", "config::generic", diff --git a/ts/src/lower/copy.rs b/ts/src/lower/copy.rs index 270d10895..cccca15f1 100644 --- a/ts/src/lower/copy.rs +++ b/ts/src/lower/copy.rs @@ -21,7 +21,7 @@ use rustc_mir_dataflow::impls::MaybeLiveLocals; use rustc_span::Span; use super::library::{Flow, Std}; -use super::mir::holders::{Filled, Trace}; +use super::mir::holders::{Filled, Holds, Trace}; use super::{AdtRepr, Translator, field_name, names}; use crate::program::{SymKind, Symbol}; use crate::ts::{self, Expr, Key, Param, Stmt, StmtKind}; @@ -1060,7 +1060,7 @@ impl<'tcx> BodyWrites<'_, '_, '_, 'tcx> { let Some(made) = made.as_local() else { return true; }; - let held = self.trace.holders(made, false, false); + let held = self.trace.holders(made, Holds::Pointers, false); let env = ty::TypingEnv::post_analysis(self.tcx, self.def_id); let raw = |ty: Ty<'tcx>| { ty.is_raw_ptr() diff --git a/ts/src/lower/mir/holders.rs b/ts/src/lower/mir/holders.rs index 3ab574961..940646c3a 100644 --- a/ts/src/lower/mir/holders.rs +++ b/ts/src/lower/mir/holders.rs @@ -48,7 +48,8 @@ impl<'tcx> Fx<'_, '_, '_, 'tcx> { return None; } let memo = RefCell::default(); - let held = Trace::new(self.b.t, self.mir, self.b.t.typing_env_pub(), &memo).holders(made.local, false, true); + let held = + Trace::new(self.b.t, self.mir, self.b.t.typing_env_pub(), &memo).holders(made.local, Holds::Pointers, true); held.escapes.is_empty().then_some(held.all) } } @@ -91,6 +92,9 @@ pub(in crate::lower) struct Held { elems: DenseBitSet, /// The local the pointers point to, if they are made of it rather than held in it. value: Option, + /// Whether a value of a type parameter may itself be one of the pointers, as [`Holds`] + /// tells. + params: bool, /// Whether a value read through a holder holds the pointers too, as [`Trace::holders`] /// takes `loads`. loads: bool, @@ -117,6 +121,20 @@ enum Def<'x, 'tcx> { Call(&'x Operand<'tcx>, &'x [Spanned>]), } +/// What the root of [`Trace::holders`] holds. +#[derive(Clone, Copy, PartialEq, Eq)] +pub(in crate::lower) enum Holds { + /// The pointers, each in a value whose type shows one. Neither std's code nor a body + /// generic over a type parameter makes a value of it out of a pointer, but by reading + /// one through a pointer cast to point at it. + Pointers, + /// The pointers, a type parameter's value among them, as a parameter of a function + /// generic over it may be one. + Any, + /// What the pointers point at, which are made of it. + Value, +} + /// How much of what a pointer was made for one may point at, finest last. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] enum Level { @@ -165,20 +183,21 @@ impl<'x, 'a, 'tcx> Trace<'x, 'a, 'tcx> { } } - /// The locals that may hold the pointer `root` holds, or with `value`, one to `root` - /// itself, or what is made of it: a copy, a cast, a reference or pointer made through - /// it, a value read through it that could hold one, or what std or the crate returns - /// given one. Without `loads`, a value read through a pointer that points at no holder, - /// as std's `ptr::read` reads one, holds none of them: what the pointer points at holds - /// it only once it is put in memory, which is an escape. Only a pointer read after - /// counts then, not one into memory a holder reaches. - pub fn holders(&self, root: Local, value: bool, loads: bool) -> Held { + /// The locals that may hold the pointer `root` holds, or one to `root` itself, as + /// `holds` tells, or what is made of it: a copy, a cast, a reference or pointer made + /// through it, a value read through it that could hold one, or what std or the crate + /// returns given one. Without `loads`, a value read through a pointer that points at no + /// holder, as std's `ptr::read` reads one, holds none of them: what the pointer points + /// at holds it only once it is put in memory, which is an escape. Only a pointer read + /// after counts then, not one into memory a holder reaches. + pub fn holders(&self, root: Local, holds: Holds, loads: bool) -> Held { let mir = self.mir; let mut held = Held { all: DenseBitSet::new_empty(mir.local_decls.len()), parts: DenseBitSet::new_empty(mir.local_decls.len()), elems: DenseBitSet::new_empty(mir.local_decls.len()), - value: value.then_some(root), + value: (holds == Holds::Value).then_some(root), + params: holds == Holds::Any, loads, behind: DenseBitSet::new_empty(mir.local_decls.len()), escapes: Vec::new(), @@ -288,9 +307,11 @@ impl<'x, 'a, 'tcx> Trace<'x, 'a, 'tcx> { } /// Whether `to`, given a pointer at `level` of what it points at, newly holds it; `None` - /// if that is memory, reached through a pointer. + /// if that is memory, reached through a pointer. A value of a type parameter, which a + /// pointer is only as [`Holds`] tells, holds one only if read as a part. fn held_in(&self, to: Place<'tcx>, level: Level, held: &mut Held) -> Option { - if !self.carries(to.ty(&self.mir.local_decls, self.t.tcx).ty) { + let ty = to.ty(&self.mir.local_decls, self.t.tcx).ty; + if !self.carries(ty) || level != Level::Part && !held.params && !self.shows_pointer(ty) { return Some(false); } if !own(to) { @@ -400,7 +421,7 @@ impl<'x, 'a, 'tcx> Trace<'x, 'a, 'tcx> { let kept = key .1 .iter() - .any(|¶m| !callee.holders(param, false, key.2).escapes.is_empty()); + .any(|¶m| !callee.holders(param, Holds::Any, key.2).escapes.is_empty()); self.memo.borrow_mut().kept.insert(key, kept); kept } @@ -496,7 +517,10 @@ impl<'x, 'a, 'tcx> Trace<'x, 'a, 'tcx> { return true; }; let trait_ref = tcx.instantiate_bound_regions_with_erased(clause).trait_ref; - if !trait_ref.args.types().any(|t| self.runs_own_code(t)) || calls_nothing(tcx, trait_ref.def_id) { + if !trait_ref.args.types().any(|t| self.runs_own_code(t)) + || calls_nothing(tcx, trait_ref.def_id) + || tcx.is_lang_item(trait_ref.def_id, rustc_attr_ir::LangItem::Copy) && copies(tcx, did) + { return true; } let Ok(trait_ref) = @@ -515,6 +539,18 @@ impl<'x, 'a, 'tcx> Trace<'x, 'a, 'tcx> { inert } + /// Whether a call of `def_id` with `args` is `vec![x; n]` of a value that shows no pointer + /// and whose drop runs none of the crate's code. It runs the crate's code only as its + /// element's `Clone`, which it gives the value it moves into the vector last, never the + /// memory it returns, and which returns no pointer std's code could keep. + fn repeats(&self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> bool { + let tcx = self.t.tcx; + crate::lower::library::is_std(tcx, def_id) + && matches!(crate::lower::library::key(tcx, def_id), Some((owner, name)) if owner == "vec" && name == "from_elem") + && !self.shows_pointer(args.type_at(0)) + && !self.drops_own_code(args.type_at(0)) + } + /// Whether std's function `did` takes or returns what could run code that its generic /// arguments don't tell: a trait object or a function pointer. fn opaque_sig(&self, did: DefId) -> bool { @@ -551,15 +587,14 @@ impl<'x, 'a, 'tcx> Trace<'x, 'a, 'tcx> { } /// Whether dropping a value of `ty` may run the crate's code: it has drop glue and holds - /// what [`Self::runs_own_code`] counts, but a type parameter whose bounds in the body's - /// environment leave it no drop glue, as `Copy` does. + /// what [`Self::runs_own_code`] counts that has drop glue of its own in the body's + /// environment, which a `Copy` type, the crate's or a type parameter bound by it, has not. fn drops_own_code(&self, ty: Ty<'tcx>) -> bool { let tcx = self.t.tcx; ty.needs_drop(tcx, self.env) - && self.t.reaches(self.env, ty, |t| match t.kind() { - ty::Param(_) => t.needs_drop(tcx, self.env), - _ => self.own_code(t), - }) + && self + .t + .reaches(self.env, ty, |t| t.needs_drop(tcx, self.env) && self.own_code(t)) } /// Whether `ty` itself, not what it holds, is what [`Self::runs_own_code`] counts. @@ -645,8 +680,8 @@ impl<'x, 'a, 'tcx> Trace<'x, 'a, 'tcx> { }; sources.into_iter().all(|source| { let held = match source { - Source::Fresh(root) => self.holders(root, false, true), - Source::Local(root) => self.holders(root, true, true), + Source::Fresh(root) => self.holders(root, Holds::Pointers, true), + Source::Local(root) => self.holders(root, Holds::Value, true), Source::Param(_) | Source::Static => return false, }; if held.escapes.iter().any(|&escape| self.reaches(escape, at)) { @@ -901,7 +936,9 @@ impl<'x, 'a, 'tcx> Trace<'x, 'a, 'tcx> { _ => _ = sources.insert(source), } } - } else if self.runs_std(def_id, gargs.skip_binder(), args) { + } else if self.runs_std(def_id, gargs.skip_binder(), args) + || self.repeats(def_id, gargs.skip_binder()) + { sources.insert(Source::Fresh(local)); reached(args, &mut stack)?; } else { @@ -1097,6 +1134,15 @@ fn calls_nothing(tcx: ty::TyCtxt<'_>, trait_id: DefId) -> bool { }) } +/// Whether std's `did` is a `copied` or of the `Copied` iterator, which copy what a `Copy` +/// bound gives them rather than run its `Clone`, unlike `Extend<&T>` for a set, which +/// clones under the same bound. +fn copies(tcx: ty::TyCtxt<'_>, did: DefId) -> bool { + let path = crate::lower::library::std_path(tcx, did); + path.last().is_some_and(|name| name == "copied") + || path.starts_with(&["iter".into(), "adapters".into(), "copied".into()]) +} + /// `ty` as storage, which an array shares with a slice of its element. fn storage<'tcx>(tcx: ty::TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { match ty.kind() {