diff --git a/quest/m3/README.md b/quest/m3/README.md index 689f9c635..8dff0c960 100644 --- a/quest/m3/README.md +++ b/quest/m3/README.md @@ -34,7 +34,6 @@ 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 - [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 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 6c0d6df9f..c70a4d19a 100644 --- a/quest/m3/ts-fresh-shapes.md +++ b/quest/m3/ts-fresh-shapes.md @@ -34,7 +34,3 @@ Recommend the first if it stays sound under specialization; it covers every adap 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 deleted file mode 100644 index f1e5444e7..000000000 --- a/quest/m3/ts-fresh-vec-access.md +++ /dev/null @@ -1,32 +0,0 @@ -# [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/expected/lengths.Row.ts b/ts/fixtures/lang/lengths/expected/lengths.Row.ts index 2d206a852..49d600f5a 100644 --- a/ts/fixtures/lang/lengths/expected/lengths.Row.ts +++ b/ts/fixtures/lang/lengths/expected/lengths.Row.ts @@ -1,19 +1,19 @@ // Generated by rust2-ts. Do not edit. import * as rt from "./rt.ts"; -import { copy$tuple2_u16_u16 } from "./lib.ts"; +import { copy$tuple2_u8_u8 } 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)); + return new Row(Loud.clone$Clone(self._0), copy$tuple2_u8_u8(self._1)); } -/** A value and a pair of tags kept as an object, of no byte held in place. */ +/** A value and a pair of tags kept as an object. */ export class Row { _0: T; - _1: [rt.u16, rt.u16]; + _1: [rt.u8, rt.u8]; - constructor(_0: T, _1: [rt.u16, rt.u16]) { + constructor(_0: T, _1: [rt.u8, rt.u8]) { this._0 = _0; this._1 = _1; } diff --git a/ts/fixtures/lang/lengths/expected/lengths.ts b/ts/fixtures/lang/lengths/expected/lengths.ts index 9f61daeae..ed7b0382e 100644 --- a/ts/fixtures/lang/lengths/expected/lengths.ts +++ b/ts/fixtures/lang/lengths/expected/lengths.ts @@ -1,7 +1,7 @@ // 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$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 { 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_Row_lengths_Loud, copy$array_lengths_Row_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"; @@ -1969,46 +1969,56 @@ export function CLONES$init(): rt.RefCell { * 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]; + const rows: Row.Row[] = [new Row.Row(y, [1, 2] as [rt.u8, rt.u8]), new Row.Row(x, [3, 4] as [rt.u8, rt.u8])]; + const copies: Row.Row[] = rt.iterToArray(rt.iterCopied(rt.iterSlice(rows), copy$lengths_Row_lengths_Loud), undefined, 4, true); + rt.byteVecPush(out, copies.length & 0xff); + const _19: Row.Row | undefined = rt.sliceFirst(copies); + if (_19 !== undefined) { + Object.assign(_19, new Row.Row(x, [48, 49] as [rt.u8, rt.u8])); + const tags: [rt.u8, rt.u8] = _19._1; + tags[0] = tags[0] ^ 16; + } + const _27: Row.Row | undefined = rt.sliceGet(copies, 1); + if (_27 !== undefined) { + _27._1[1] = _27._1[1] ^ 32; + } + for (const _35 of copies) { + const value: Loud.Loud = _35._0; + const a: rt.u8 = _35._1[0]; + const b: rt.u8 = _35._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]; + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(a, b)), undefined, true); + } + const repeats: Row.Row[] = rt.vecFromElem(new Row.Row(x, [5, 6] as [rt.u8, rt.u8]), rt.usizeAdd(1, rt.usizeRem(dataLen, 3)), Row.clone$Clone_lengths_Loud); + rt.byteVecPush(out, repeats.length & 0xff); + const _57: Row.Row | undefined = rt.sliceFirst(repeats); + if (_57 !== undefined) { + Object.assign(_57, new Row.Row(x, [48, 49] as [rt.u8, rt.u8])); + const tags2: [rt.u8, rt.u8] = _57._1; + tags2[0] = tags2[0] ^ 16; + } + const _65: Row.Row | undefined = rt.sliceGet(repeats, 1); + if (_65 !== undefined) { + _65._1[1] = _65._1[1] ^ 32; + } + for (const _73 of repeats) { + const value2: Loud.Loud = _73._0; + const a2: rt.u8 = _73._1[0]; + const b2: rt.u8 = _73._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); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(a2, b2)), 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); + const iter3: rt.Iter> = rt.iterSlice(copy$array_lengths_Row_lengths_Loud(rows)); + while (true) { + const _86: Row.Row | rt.Done = iter3.next(); + if (_86 === rt.DONE) { + break; + } + const value3: Loud.Loud = _86._0; + const a3: rt.u8 = _86._1[0]; + const b3: rt.u8 = _86._1[1]; + Loud.put$lengths_Put(value3, out); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(a3, b3)), undefined, true); } } @@ -2018,46 +2028,56 @@ export function repeated$lengths_Loud(_dataData: Uint8Array, _dataStart: number, * 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]; + const rows: Row.Row[] = [new Row.Row(y, [1, 2] as [rt.u8, rt.u8]), new Row.Row(x, [3, 4] as [rt.u8, rt.u8])]; + const copies: Row.Row[] = rt.iterToArray(rt.iterCopied(rt.iterSlice(rows), copy$lengths_Row_u8), undefined, 3, true); + rt.byteVecPush(out, copies.length & 0xff); + const _19: Row.Row | undefined = rt.sliceFirst(copies); + if (_19 !== undefined) { + Object.assign(_19, new Row.Row(x, [48, 49] as [rt.u8, rt.u8])); + const tags: [rt.u8, rt.u8] = _19._1; + tags[0] = tags[0] ^ 16; + } + const _27: Row.Row | undefined = rt.sliceGet(copies, 1); + if (_27 !== undefined) { + _27._1[1] = _27._1[1] ^ 32; + } + for (const _35 of copies) { + const value: rt.u8 = _35._0; + const a: rt.u8 = _35._1[0]; + const b: rt.u8 = _35._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]; + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(a, b)), undefined, true); + } + const repeats: Row.Row[] = rt.vecFromElem(new Row.Row(x, [5, 6] as [rt.u8, rt.u8]), rt.usizeAdd(1, rt.usizeRem(dataLen, 3)), copy$lengths_Row_u8); + rt.byteVecPush(out, repeats.length & 0xff); + const _57: Row.Row | undefined = rt.sliceFirst(repeats); + if (_57 !== undefined) { + Object.assign(_57, new Row.Row(x, [48, 49] as [rt.u8, rt.u8])); + const tags2: [rt.u8, rt.u8] = _57._1; + tags2[0] = tags2[0] ^ 16; + } + const _65: Row.Row | undefined = rt.sliceGet(repeats, 1); + if (_65 !== undefined) { + _65._1[1] = _65._1[1] ^ 32; + } + for (const _73 of repeats) { + const value2: rt.u8 = _73._0; + const a2: rt.u8 = _73._1[0]; + const b2: rt.u8 = _73._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); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(a2, b2)), 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); + const iter3: rt.Iter> = rt.iterSlice(copy$array_lengths_Row_u8(rows)); + while (true) { + const _86: Row.Row | rt.Done = iter3.next(); + if (_86 === rt.DONE) { + break; + } + const value3: rt.u8 = _86._0; + const a3: rt.u8 = _86._1[0]; + const b3: rt.u8 = _86._1[1]; + put$lengths_Put_u8(value3, out); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(a3, b3)), undefined, true); } } @@ -2066,46 +2086,56 @@ 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]; + const rows: Row.Row[] = [new Row.Row({ _0: byte(0) }, [1, 2] as [rt.u8, rt.u8]), new Row.Row({ _0: byte(2) }, [3, 4] as [rt.u8, rt.u8])]; + const copies: Row.Row[] = rt.iterToArray(rt.iterCopied(rt.iterSlice(rows), copy$lengths_Row_lengths_Loud), undefined, 4, true); + rt.byteVecPush(out, copies.length & 0xff); + const _26: Row.Row | undefined = rt.sliceFirst(copies); + if (_26 !== undefined) { + Object.assign(_26, new Row.Row({ _0: byte(2) }, [48, 49] as [rt.u8, rt.u8])); + const tags: [rt.u8, rt.u8] = _26._1; + tags[0] = tags[0] ^ 16; + } + const _38: Row.Row | undefined = rt.sliceGet(copies, 1); + if (_38 !== undefined) { + _38._1[1] = _38._1[1] ^ 32; + } + for (const _46 of copies) { + const value: Loud.Loud = _46._0; + const a: rt.u8 = _46._1[0]; + const b: rt.u8 = _46._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]; + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(a, b)), undefined, true); + } + const repeats: Row.Row[] = rt.vecFromElem(new Row.Row({ _0: byte(2) }, [5, 6] as [rt.u8, rt.u8]), rt.usizeAdd(1, rt.usizeRem(data.length, 3)), Row.clone$Clone_lengths_Loud); + rt.byteVecPush(out, repeats.length & 0xff); + const _72: Row.Row | undefined = rt.sliceFirst(repeats); + if (_72 !== undefined) { + Object.assign(_72, new Row.Row({ _0: byte(2) }, [48, 49] as [rt.u8, rt.u8])); + const tags2: [rt.u8, rt.u8] = _72._1; + tags2[0] = tags2[0] ^ 16; + } + const _84: Row.Row | undefined = rt.sliceGet(repeats, 1); + if (_84 !== undefined) { + _84._1[1] = _84._1[1] ^ 32; + } + for (const _92 of repeats) { + const value2: Loud.Loud = _92._0; + const a2: rt.u8 = _92._1[0]; + const b2: rt.u8 = _92._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); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(a2, b2)), 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); + const iter3: rt.Iter> = rt.iterSlice(copy$array_lengths_Row_lengths_Loud(rows)); + while (true) { + const _104: Row.Row | rt.Done = iter3.next(); + if (_104 === rt.DONE) { + break; + } + const value3: Loud.Loud = _104._0; + const a3: rt.u8 = _104._1[0]; + const b3: rt.u8 = _104._1[1]; + Loud.put$lengths_Put(value3, out); + rt.iterExtendBytes(out, rt.iterSlice(Uint8Array.of(a3, b3)), undefined, true); } } diff --git a/ts/fixtures/lang/lengths/expected/lib.ts b/ts/fixtures/lang/lengths/expected/lib.ts index d632df492..bee069453 100644 --- a/ts/fixtures/lang/lengths/expected/lib.ts +++ b/ts/fixtures/lang/lengths/expected/lib.ts @@ -54,6 +54,14 @@ export function copy$array_array3_u8(v: Uint8Array[]): Uint8Array[] { return v.map(copy$array_u8); } +export function copy$array_lengths_Row_lengths_Loud(v: Row.Row[]): Row.Row[] { + return v.map(copy$lengths_Row_lengths_Loud); +} + +export function copy$array_lengths_Row_u8(v: Row.Row[]): Row.Row[] { + return v.map(copy$lengths_Row_u8); +} + export function copy$array_lengths_Tagged_u32(v: Tagged.Tagged[]): Tagged.Tagged[] { return v.slice(); } @@ -67,11 +75,11 @@ export function copy$array_u8(v: Uint8Array): Uint8Array { } export function copy$lengths_Row_lengths_Loud(v: Row.Row): Row.Row { - return new Row.Row(v._0, copy$tuple2_u16_u16(v._1)); + return new Row.Row(v._0, copy$tuple2_u8_u8(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)); + return new Row.Row(v._0, copy$tuple2_u8_u8(v._1)); } export function copy$lengths_Tagged_array0_u32(v: Tagged.Tagged): Tagged.Tagged { @@ -274,7 +282,7 @@ 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] { +export function copy$tuple2_u8_u8(v: [rt.u8, rt.u8]): [rt.u8, rt.u8] { return [v[0], v[1]]; } diff --git a/ts/fixtures/lang/lengths/src/lengths.rs b/ts/fixtures/lang/lengths/src/lengths.rs index b39edbec1..0384d180c 100644 --- a/ts/fixtures/lang/lengths/src/lengths.rs +++ b/ts/fixtures/lang/lengths/src/lengths.rs @@ -2,8 +2,8 @@ //! 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, -//! through what std's iterators give back and what `copied` and `vec![x; n]` make of a -//! `Copy` type whose `Clone` logs and panics. +//! through what std's iterators and a vector's accessors 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; @@ -210,25 +210,26 @@ impl Put for Loud { } } -/// A value and a pair of tags kept as an object, of no byte held in place. +/// A value and a pair of tags kept as an object. #[derive(Clone, Copy)] -struct Row(T, (u16, u16)); +struct Row(T, (u8, u8)); -/// 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. +/// A vector's length, its first row written whole and its tags changed through a pointer +/// to them, the second's changed in place, and each row put as the vector is moved out. 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 } + ($rows:ident, $x:expr, $out:ident) => { + $out.push($rows.len() as u8); + if let Some(first) = $rows.first_mut() { + *first = Row($x, (0x30, 0x31)); + let tags = &raw mut first.1; + unsafe { (*tags).0 ^= 0x10 } } - if $len > 1 { - $rows[1].1.1 ^= 0x2020; + if let Some(Row(_, (_, b))) = $rows.get_mut(1) { + *b ^= 0x20; } for Row(value, (a, b)) in $rows { value.put($out); - $out.extend(a.to_le_bytes().into_iter().chain(b.to_le_bytes())); + $out.extend([a, b]); } }; } @@ -236,14 +237,14 @@ macro_rules! rewritten { /// [`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 rows = [Row($y, (0x01, 0x02)), Row($x, (0x03, 0x04))]; 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 { + rewritten!(copies, $x, $out); + let mut repeats = vec![Row($x, (0x05, 0x06)); 1 + $data.len() % 3]; + rewritten!(repeats, $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())); + $out.extend([a, b]); } }}; } diff --git a/ts/fixtures/reject/census.txt b/ts/fixtures/reject/census.txt index a9b98f1c9..2d1c7f021 100644 --- a/ts/fixtures/reject/census.txt +++ b/ts/fixtures/reject/census.txt @@ -71,8 +71,10 @@ fixtures/reject/src/kept.rs:lent_kept+4:46: a raw pointer to `std::cell::UnsafeC fixtures/reject/src/kept.rs:lent_kept+6:22: `std::iter::once` with a mutable reference to a value JS copies, which its mapping would copy fixtures/reject/src/kept.rs:mapped_kept+4:39: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Mapped`, which the crate may put another object in place of fixtures/reject/src/kept.rs:pushed_part_kept+4:22: a raw pointer to `(u16, u16)` in `kept::Pushed`, which the crate may put another object in place of +fixtures/reject/src/kept.rs:reaimed+2:13: a raw pointer to `(u16, u16)` in `kept::Reaimed`, which the crate may put another object in place of fixtures/reject/src/kept.rs:ref_replaced+2:32: a raw pointer to `kept::ByRefReplace` in `(u16, kept::ByRefReplace)`, which the crate may put another object in place of fixtures/reject/src/kept.rs:ref_taken+2:32: a raw pointer to `kept::ByRefTake` in `(u16, kept::ByRefTake)`, which the crate may put another object in place of +fixtures/reject/src/kept.rs:reversed+3:13: a raw pointer to `(u16, u16)` in `kept::Reversed`, which the crate may put another object in place of fixtures/reject/src/kept.rs:uninit_rewritten+3:47: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Rewritten`, which the crate may put another object in place of fixtures/reject/src/kept.rs:written_through_alias+3:29: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Aliased`, which the crate may put another object in place of fixtures/reject/src/kept.rs:written_through_loaded+3:29: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Loaded`, which the crate may put another object in place of diff --git a/ts/fixtures/reject/expected.txt b/ts/fixtures/reject/expected.txt index 4726d135c..8acbe609b 100644 --- a/ts/fixtures/reject/expected.txt +++ b/ts/fixtures/reject/expected.txt @@ -74,8 +74,10 @@ fixtures/reject/src/kept.rs:lent_kept+4:46: a raw pointer to `std::cell::UnsafeC fixtures/reject/src/kept.rs:lent_kept+6:22: `std::iter::once` with a mutable reference to a value JS copies, which its mapping would copy fixtures/reject/src/kept.rs:mapped_kept+4:39: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Mapped`, which the crate may put another object in place of fixtures/reject/src/kept.rs:pushed_part_kept+4:22: a raw pointer to `(u16, u16)` in `kept::Pushed`, which the crate may put another object in place of +fixtures/reject/src/kept.rs:reaimed+2:13: a raw pointer to `(u16, u16)` in `kept::Reaimed`, which the crate may put another object in place of fixtures/reject/src/kept.rs:ref_replaced+2:32: a raw pointer to `kept::ByRefReplace` in `(u16, kept::ByRefReplace)`, which the crate may put another object in place of fixtures/reject/src/kept.rs:ref_taken+2:32: a raw pointer to `kept::ByRefTake` in `(u16, kept::ByRefTake)`, which the crate may put another object in place of +fixtures/reject/src/kept.rs:reversed+3:13: a raw pointer to `(u16, u16)` in `kept::Reversed`, which the crate may put another object in place of fixtures/reject/src/kept.rs:uninit_rewritten+3:47: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Rewritten`, which the crate may put another object in place of fixtures/reject/src/kept.rs:written_through_alias+3:29: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Aliased`, which the crate may put another object in place of fixtures/reject/src/kept.rs:written_through_loaded+3:29: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Loaded`, which the crate may put another object in place of diff --git a/ts/fixtures/reject/src/kept.rs b/ts/fixtures/reject/src/kept.rs index ab0d31891..56722ffe4 100644 --- a/ts/fixtures/reject/src/kept.rs +++ b/ts/fixtures/reject/src/kept.rs @@ -432,3 +432,29 @@ pub fn key_taken(n: u16) -> u16 { drop(KEY_TAKE.take()); unsafe { *part } } + +pub struct Reaimed(pub (u16, u16)); + +/// A fresh allocation written whole through a pointer that a shared borrow of the +/// `UnsafeCell` holding it aimed at another value, into which a pointer may still be read. +pub fn reaimed(n: u16) -> u16 { + let mut other = Reaimed((n, n)); + let part = &raw mut other.0; + let at = std::cell::UnsafeCell::new(Box::into_raw(Box::new(Reaimed((0, 0))))); + let shared = &at; + unsafe { *shared.get() = &raw mut other }; + unsafe { *at.into_inner() = Reaimed((1, 1)) }; + unsafe { (*part).0 } +} + +pub struct Reversed(pub (u16, u16)); + +/// A value std's `Reverse` holds, swapped whole for another while a pointer into it may +/// still be read. +pub fn reversed(n: u16) -> u16 { + let mut slot = std::cmp::Reverse(Reversed((n, n))); + let mut other = std::cmp::Reverse(Reversed((0, 0))); + let part = &raw mut slot.0.0; + std::mem::swap(&mut slot, &mut other); + unsafe { (*part).0 } +} diff --git a/ts/fixtures/reject/ts.toml b/ts/fixtures/reject/ts.toml index 01df3520c..9f483246f 100644 --- a/ts/fixtures/reject/ts.toml +++ b/ts/fixtures/reject/ts.toml @@ -62,8 +62,10 @@ roots = [ "kept::lent_kept", "kept::mapped_kept", "kept::pushed_part_kept", + "kept::reaimed", "kept::ref_replaced", "kept::ref_taken", + "kept::reversed", "kept::uninit_rewritten", "kept::written_through_alias", "kept::written_through_loaded", diff --git a/ts/src/lower/copy.rs b/ts/src/lower/copy.rs index b7cc3ffb5..c674d2f99 100644 --- a/ts/src/lower/copy.rs +++ b/ts/src/lower/copy.rs @@ -980,12 +980,13 @@ impl<'tcx> BodyWrites<'_, '_, '_, 'tcx> { } /// Whether the call at `at` given `arg` as a `ty`, a mutable reference or pointer to a - /// type that may be kept as an object, fills memory nothing points into yet there. + /// type that holds by value one that may be kept as an object, as an array's iterator + /// does, fills memory nothing points into yet there. fn fills_fresh(&mut self, ty: Ty<'tcx>, arg: &mir::Operand<'tcx>, at: Location, made: Option) -> bool { let (ty::Ref(_, inner, ty::Mutability::Mut) | ty::RawPtr(inner, ty::Mutability::Mut)) = *ty.kind() else { return false; }; - self.inline(inner) + !self.parts(inner).is_empty() && arg .place() .and_then(|p| p.as_local()) diff --git a/ts/src/lower/mir/holders.rs b/ts/src/lower/mir/holders.rs index 940646c3a..8834c2b7a 100644 --- a/ts/src/lower/mir/holders.rs +++ b/ts/src/lower/mir/holders.rs @@ -717,7 +717,9 @@ impl<'x, 'a, 'tcx> Trace<'x, 'a, 'tcx> { } /// Whether a value of `ty` may hold a pointer, or one behind it, to a value `to` holds - /// for, as what it points at is peeled; or one its type doesn't tell. + /// for, as what it points at is peeled; or one its type doesn't tell. A vector's buffer + /// is its own allocation, never a part of another value, so only what its elements hold + /// may point at one. fn points_to(&self, ty: Ty<'tcx>, to: impl Fn(Ty<'tcx>) -> bool) -> bool { let mut seen = FxHashSet::default(); let mut stack = vec![ty]; @@ -733,6 +735,11 @@ impl<'x, 'a, 'tcx> Trace<'x, 'a, 'tcx> { } stack.push(pointee); } + ty::Adt(adt, args) + if crate::lower::library::std_path(self.t.tcx, adt.did()) == ["raw_vec", "RawVec"] => + { + stack.extend(args.types()) + } _ => match self.fields(ty) { Some(fields) => stack.extend(fields), None => return true, @@ -742,6 +749,36 @@ impl<'x, 'a, 'tcx> Trace<'x, 'a, 'tcx> { false } + /// Whether code given a shared reference to a value of `ty` may change what it holds or + /// reaches: through an `UnsafeCell` in a field, behind a pointer, or in a type argument, + /// as a hash map's buffer holds its entries; or in one its type doesn't tell. A type + /// parameter's value holds none the body can read a pointer out of but through the + /// crate's code, which [`Self::origins`] follows on its own. + fn mutable_through_shared(&self, ty: Ty<'tcx>) -> bool { + let tcx = self.t.tcx; + let mut seen = FxHashSet::default(); + let mut stack = vec![ty]; + while let Some(ty) = stack.pop() { + if !seen.insert(ty) { + continue; + } + match ty.kind() { + ty::Adt(adt, _) if tcx.is_lang_item(adt.did(), rustc_attr_ir::LangItem::UnsafeCell) => return true, + ty::Adt(_, args) => stack.extend(args.types()), + ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => { + stack.push(*pointee); + continue; + } + _ => {} + } + match self.fields(ty) { + Some(fields) => stack.extend(fields), + None => return true, + } + } + false + } + /// Whether a value of `ty` may be or hold a `filled` value in place. fn holds_in_place(&self, ty: Ty<'tcx>, filled: Ty<'tcx>) -> bool { let tcx = self.t.tcx; @@ -1023,6 +1060,9 @@ impl<'x, 'a, 'tcx> Trace<'x, 'a, 'tcx> { { defs[borrowed].lent.push(to) } + // A shared borrow changes nothing but through an `UnsafeCell`. + Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake(_), place) + if !self.mutable_through_shared(place.ty(&mir.local_decls, self.t.tcx).ty) => {} Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) if !place.is_indirect() => { defs[place.local].other = true }