From 48a58cc6a38b78926dddc27abf91355cbd4debbe Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Sat, 7 Nov 2026 14:19:32 -0800 Subject: [PATCH 01/12] chore(quest): claim quest/m3/ts-slice-object.md Quest-Claim: 4035ae0cf9b09116 From 3cfe0d287c9fc28c8922a35c78d3c4e1e70cff20 Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Sat, 7 Nov 2026 14:51:41 -0800 Subject: [PATCH 02/12] feat(ts)!: parts of arrays written where they are, without arrayView A `&mut [T; N]` to part of an array is read and written where its slice holds it: `mem::replace` and `mem::swap` by `rs.sliceReplaceAll`, `ptr::replace` and `ptr::swap` by `rs.sliceCopy`, `Cell::from_mut` and `UnsafeCell::from_mut` by a cell of the slice whose pointer is the slice, `ptr::as_mut` and `NonNull::as_mut` as the slice itself, and `Box::from_raw` as the array a box owns all of. The runtime's `arrayView` and `rs.sliceView` go. Co-Authored-By: Claude Opus 5.5 --- quest/m3/README.md | 1 - quest/m3/ts-runtime-throws.md | 2 +- quest/m3/ts-slice-object.md | 55 ---- .../lang/conversions/expected/conversions.ts | 291 +++++++++++------- ts/fixtures/lang/objects/expected/objects.ts | 3 +- .../lang/pointers/expected/core/option.ts | 7 + ts/fixtures/lang/pointers/expected/lib.ts | 4 +- .../lang/pointers/expected/pointers.ts | 107 ++++++- ts/fixtures/lang/pointers/src/lib.rs | 1 + ts/fixtures/lang/pointers/src/pointers.rs | 42 ++- .../lang/slices/expected/core/option.ts | 8 + ts/fixtures/lang/slices/expected/lib.ts | 8 +- ts/fixtures/lang/slices/expected/slices.ts | 154 ++++++++- ts/fixtures/lang/slices/src/lib.rs | 1 + ts/fixtures/lang/slices/src/slices.rs | 91 +++++- ts/fixtures/reject/census.txt | 8 +- ts/fixtures/reject/expected.txt | 8 +- ts/fixtures/reject/src/alloc.rs | 7 +- ts/fixtures/task/expected/drops/called.ts | 2 +- ts/runtime/rs.ts | 213 ++++++------- ts/runtime/rs/task.ts | 41 ++- ts/src/lower/lend.rs | 42 +-- ts/src/lower/library.rs | 10 +- ts/src/lower/mir/call.rs | 28 +- ts/src/lower/pointer.rs | 48 +-- ts/src/lower/task.rs | 9 +- 26 files changed, 796 insertions(+), 395 deletions(-) delete mode 100644 quest/m3/ts-slice-object.md diff --git a/quest/m3/README.md b/quest/m3/README.md index f451cc0fd..30c6d1583 100644 --- a/quest/m3/README.md +++ b/quest/m3/README.md @@ -45,7 +45,6 @@ memory model for values whose address is reinterpreted, without a consumer. - [Unsafe code the translator can model](/quest/m3/ts-unsafe/README.md) - a dependency using only `unsafe` the translator can model translates from source - [Waiting: drop the lang fixture's mul_add allowance](/quest/m3/ts-fma-allowance.md) - the differential fails on any `mul_add` difference again once wasm32's `fma` rounds exactly - [Waiting: type-check in process with tsrs](/quest/m3/ts-tsrs.md) - rust2-ts checks bindings through tsrs instead of `tsc` once it is a stable library -- [Parts of arrays without arrayView](/quest/m3/ts-slice-object.md) - a `&mut [T; N]` to part of an array is taken where it is, with no `Proxy` - [Throw only where Rust panics](/quest/m3/ts-runtime-throws.md) - no runtime `rust2-ts:` error where native Rust goes on: an exact slower path, or a refusal at translation - [rust2-ts with no ts.toml](/quest/m3/ts-configless.md) - a crate's whole `pub` API translates with no config and no bound items - [Browser APIs through wasm-bindgen](/quest/m3/ts-wasm-bindgen/README.md) - web-sys and js-sys imports become direct JS calls, so idiomatic crates such as web-rs's web-codecs translate as stock crates diff --git a/quest/m3/ts-runtime-throws.md b/quest/m3/ts-runtime-throws.md index f3aa2146c..af4fad7bf 100644 --- a/quest/m3/ts-runtime-throws.md +++ b/quest/m3/ts-runtime-throws.md @@ -45,7 +45,7 @@ addresses stay refused (decided 2026-11-07 in [the model epic](/quest/m2/ts-mode ✅ Decided with the maintainer on 2026-11-06 in [moq-dev/rust2#608](https://github.com/moq-dev/rust2/pull/608): comparing `*const [T]` of -values JS copies moved here from [rs.Slice](/quest/m3/ts-slice-object.md). The options +values JS copies moved here from rs.Slice's quest. The options were to wait on rs.String ([moq-dev/rust2#574](https://github.com/moq-dev/rust2/pull/574)) and run only if `&str` shares its bytes, or to move it here with the other comparisons left refused (picked). Its only consumer in moq-net is form_urlencoded 1.2.2's `src/lib.rs:417`, diff --git a/quest/m3/ts-slice-object.md b/quest/m3/ts-slice-object.md deleted file mode 100644 index 2c9188be3..000000000 --- a/quest/m3/ts-slice-object.md +++ /dev/null @@ -1,55 +0,0 @@ -# [M] Parts of arrays without arrayView - -## Goal - -[rust2-ts](/ts/README.md) holds a slice of arrays as an `rs.ArraySlice` of the slice each array -is, with no `Proxy`. What remains is the runtime's `arrayView`, a `Proxy` JS array over -part of another, which `rs.sliceView` makes where a `&mut [T; N]` to part of an array is -taken whole as a JS array: by `mem::replace` and `mem::swap` of an element of a slice of -arrays, `Cell::from_mut` of one, std's mappings given one to write through, and a raw -pointer's `as_mut` or `Box::from_raw`. Each takes the slice where it is instead, or a -copy written back as `rs.arraySliceBy` writes arrays back, and `arrayView` and its `View` traps -go. Proven by differential tests against native Rust. - -## Plan - -✅ Decided with the maintainer on 2026-11-06 in -[moq-dev/rust2#608](https://github.com/moq-dev/rust2/pull/608), which made `rs.ArraySlice`: - -1. How a `&mut [[T; N]]` holds its arrays: - - ✅ (a) A runtime type for every slice of arrays, nested or flat, whose element `i` is - the slice of array `i`, which replaces the `Runs` and `ByteRuns` `Proxy` views and - `arrayView`. - - (b) Bytes only: `as_chunks_mut` makes eager `subarray` views, keeping the `Proxy` - path for other elements. - - (c) Keep the `Proxy` views and drop the item. -2. `slice::from_mut` of a `&mut u8`: kept, deferred to a quest of its own, since done - ([moq-dev/rust2#660](https://github.com/moq-dev/rust2/pull/660)). -3. Comparing `*const [T]` of values JS copies: moved to - [Throw only where Rust panics](/quest/m3/ts-runtime-throws.md). - -✅ Decided with the maintainer on 2026-11-07 at the round-3 design checkpoint of -[moq-dev/rust2#608](https://github.com/moq-dev/rust2/pull/608): - -4. Conversions that copied arrays where Rust borrows them: ✅ continue, with local fixes - (rejected: merge as is; `rs.ArraySlice` only for what `as_chunks` splits, keeping - `rs.Slice` for other slices of arrays; drop). Where each array of an array slice is - a JS array of its own, `rs.arraySliceItems` slices the list of them rather than copying - each, so a std callback's `ptr::eq` sees the array it was lent, and `join` reads its - array separator without copying it, since it clones it anyway. The arrays `as_chunks` - splits from one flat slice have none of their own, so a callback still gets a copy: - that `ptr::eq` gap moved to [Throw only where Rust panics](/quest/m3/ts-runtime-throws.md). -5. The type's name: ✅ `rs.ArraySlice`, as `rs.ByteSlice` and `rs.RawSlice` are named, - with its helpers `rs.arraySlice*` (rejected: `rs.Slices`, `rs.Chunks`, keep `rs.Runs`). - -Decided with the maintainer on 2026-11-03: Rust types the runtime can't hold as std's do -get a runtime wrapper, converted at API boundaries, rather than a JS native type -([#555](https://github.com/moq-dev/rust2/pull/555) made `Vec` one). - -`rs.replaceIn` and `rs.cellIn` of a JS array write a whole value into it, and copy its -elements to a depth where a write lands in them; a slice's form needs the same, as -`rs.arraySliceReplace` and `rs.cellOfArraySlice` do for arrays. A raw pointer to an array of arrays -that std's mapping gives back as a reference is refused today. - -Public API: the translator's output and what a hand-written caller passes for a slice of -arrays. diff --git a/ts/fixtures/lang/conversions/expected/conversions.ts b/ts/fixtures/lang/conversions/expected/conversions.ts index 14bbc791f..a3aa0d3aa 100644 --- a/ts/fixtures/lang/conversions/expected/conversions.ts +++ b/ts/fixtures/lang/conversions/expected/conversions.ts @@ -370,7 +370,7 @@ export function cloneFromParam$array1_u8(to: rs.ByteSlice, from: rs.ByteSlice): /** `clone_from` through a `&mut` whose place only the caller knows. */ export function cloneFromParam$array2_u32(to: rs.Slice, from: rs.Slice): void { - rs.replaceIn(rs.sliceView(to), rs.sliceToArray(from)); + rs.sliceReplaceAll(to, rs.sliceToArray(from)); } /** `clone_from` through a `&mut` whose place only the caller knows. */ @@ -440,7 +440,7 @@ export function cloneIntoParam$array1_u8(from: rs.ByteSlice, to: rs.ByteSlice): /** `clone_into` through a `&mut` whose place only the caller knows. */ export function cloneIntoParam$array2_u32(from: rs.Slice, to: rs.Slice): void { - rs.replaceIn(rs.sliceView(to), rs.sliceToArray(from)); + rs.sliceReplaceAll(to, rs.sliceToArray(from)); } /** `clone_into` through a `&mut` whose place only the caller knows. */ @@ -557,7 +557,7 @@ export function writeFirst$array2_u32(s: rs.ArraySlice>, value: value = copy$array_u32(value); rs.idx(s, 0); const _8: rs.u32[] = copy$array_u32(value.slice()); - const old: rs.u32[] = rs.replaceIn(rs.sliceView(rs.arraySliceAt(s, 0)), _8); + const old: rs.u32[] = rs.sliceReplaceAll(rs.arraySliceAt(s, 0), _8); const _10: rs.u32[] = value; rs.idx(s, 0); rs.sliceSet(rs.arraySliceAt(s, 0), _10); @@ -661,25 +661,25 @@ export function writeFirst$u8(s: rs.ByteSlice, value: rs.u8): rs.u8 { /** `mem::replace` of the first array, as a function given any slice of them makes it. */ export function replaceFirst$Option_u16(s: rs.ArraySlice>, value: Array): Array { rs.idx(s, 0); - return rs.replaceIn(rs.sliceView(rs.arraySliceAt(s, 0)), copy$array_Option_u16(value)); + return rs.sliceReplaceAll(rs.arraySliceAt(s, 0), copy$array_Option_u16(value)); } /** `mem::replace` of the first array, as a function given any slice of them makes it. */ export function replaceFirst$String(s: rs.ArraySlice>, value: rs.String[]): rs.String[] { rs.idx(s, 0); - return rs.replaceIn(rs.sliceView(rs.arraySliceAt(s, 0)), value, 1); + return rs.sliceReplaceAll(rs.arraySliceAt(s, 0), value, 1); } /** `mem::replace` of the first array, as a function given any slice of them makes it. */ export function replaceFirst$Vec_u32(s: rs.ArraySlice>>, value: rs.Vec[]): rs.Vec[] { rs.idx(s, 0); - return rs.replaceIn(rs.sliceView(rs.arraySliceAt(s, 0)), value, 1); + return rs.sliceReplaceAll(rs.arraySliceAt(s, 0), value, 1); } /** `mem::replace` of the first array, as a function given any slice of them makes it. */ export function replaceFirst$Vec_u8(s: rs.ArraySlice>, value: rs.ByteVec[]): rs.ByteVec[] { rs.idx(s, 0); - return rs.replaceIn(rs.sliceView(rs.arraySliceAt(s, 0)), value, 1); + return rs.sliceReplaceAll(rs.arraySliceAt(s, 0), value, 1); } /** `mem::replace` of the first array, as a function given any slice of them makes it. */ @@ -715,25 +715,25 @@ export function replaceFirst$array40_u8(s: rs.ArraySlice>, value: Logged.Logged[]): Logged.Logged[] { rs.idx(s, 0); - return rs.replaceIn(rs.sliceView(rs.arraySliceAt(s, 0)), value, 1); + return rs.sliceReplaceAll(rs.arraySliceAt(s, 0), value, 1); } /** `mem::replace` of the first array, as a function given any slice of them makes it. */ export function replaceFirst$conversions_Named(s: rs.ArraySlice>, value: Named.Named[]): Named.Named[] { rs.idx(s, 0); - return rs.replaceIn(rs.sliceView(rs.arraySliceAt(s, 0)), value, 1); + return rs.sliceReplaceAll(rs.arraySliceAt(s, 0), value, 1); } /** `mem::replace` of the first array, as a function given any slice of them makes it. */ export function replaceFirst$u32(s: rs.ArraySlice>, value: rs.u32[]): rs.u32[] { rs.idx(s, 0); - return rs.replaceIn(rs.sliceView(rs.arraySliceAt(s, 0)), copy$array_u32(value)); + return rs.sliceReplaceAll(rs.arraySliceAt(s, 0), copy$array_u32(value)); } /** `mem::replace` of the first array, as a function given any slice of them makes it. */ export function replaceFirst$u64(s: rs.ArraySlice>, value: rs.u64[]): rs.u64[] { rs.idx(s, 0); - return rs.replaceIn(rs.sliceView(rs.arraySliceAt(s, 0)), copy$array_u64(value)); + return rs.sliceReplaceAll(rs.arraySliceAt(s, 0), copy$array_u64(value)); } /** `mem::replace` of the first array, as a function given any slice of them makes it. */ @@ -785,14 +785,14 @@ export function lentParam$Option_u16(to: rs.Place, data: rs. const borrowed2 = s.start; const a: rs.Slice = rs.sliceOfPlace(rs.place(() => borrowed[borrowed2], (value) => borrowed[borrowed2] = value)); const _77: Array = [make$conversions_Value_Option_u16(data, 22)]; - put$conversions_Value_Option_u16(rs.replaceIn(rs.sliceView(a), _77)[0], out); + put$conversions_Value_Option_u16(rs.sliceReplaceAll(a, _77)[0], out); let by: rs.u16 | undefined = make$conversions_Value_Option_u16(data, 23); rs.idx(s, 0); const borrowed3 = s.start; let r: rs.Place = rs.place(() => s.data[borrowed3], (value2) => s.data[borrowed3] = value2); const _89: rs.Slice> = rs.sliceOfPlace(rs.place(() => r, (value3) => r = value3)); const _91: rs.Place[] = [rs.place(() => by, (value4) => by = value4)]; - rs.replaceIn(rs.sliceView(_89), _91)[0].v = make$conversions_Value_Option_u16(data, 24); + rs.sliceReplaceAll(_89, _91)[0].v = make$conversions_Value_Option_u16(data, 24); put$conversions_Value_Option_u16(r.v, out); rs.idx(s, 0); put$conversions_Value_Option_u16(s.data[s.start], out); @@ -803,10 +803,10 @@ export function lentParam$Option_u16(to: rs.Place, data: rs. rs.idx(s, 0); const borrowed6 = s.data; const borrowed7 = s.start; - const _114: rs.Cell> = rs.cellOfPlace(rs.partPlace(rs.sliceView(rs.sliceOfPlace(rs.place(() => borrowed6[borrowed7], (value6) => borrowed6[borrowed7] = value6))))); + const _114: rs.Cell> = rs.cellOfSlice(rs.sliceOfPlace(rs.place(() => borrowed6[borrowed7], (value6) => borrowed6[borrowed7] = value6))); const _121: Array = [make$conversions_Value_Option_u16(data, 26)]; - const pointer = rs.sliceFrom(_114.v); - const old6 = rs.objectCopy(rs.sliceView(pointer)); + const pointer = rs.cellArray(_114, rs.sliceFrom); + const old6 = rs.sliceCopy(pointer); rs.sliceSet(pointer, _121); put$conversions_Value_Option_u16(old6[0], out); rs.idx(s, 0); @@ -816,7 +816,12 @@ export function lentParam$Option_u16(to: rs.Place, data: rs. rs.idx(s, 0); const borrowed10 = s.data; const borrowed11 = s.start; - put$conversions_Value_Option_u16(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => borrowed10[borrowed11], (value8) => borrowed10[borrowed11] = value8)), 1)), [[make$conversions_Value_Option_u16(data, 28)]])[0][0], out); + const _147: rs.Cell[]> = rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => borrowed10[borrowed11], (value8) => borrowed10[borrowed11] = value8)), 1)); + const _148: Array[] = [[make$conversions_Value_Option_u16(data, 28)]]; + const pointer2 = rs.cellArray(_147, rs.arraySliceOf(rs.sliceFrom)); + const old7 = rs.arraySliceCopy(pointer2); + rs.arraySliceSet(pointer2, _148); + put$conversions_Value_Option_u16(old7[0][0], out); rs.idx(s, 0); s.data[s.start] = other; rs.idx(s, 0); @@ -855,13 +860,13 @@ export function lentParam$String(to: rs.String, data: rs.ByteSlice, out: rs.Byte const borrowed2 = s.start; const a: rs.Slice = rs.sliceOfPlace(rs.place(() => borrowed[borrowed2], (value) => borrowed[borrowed2] = value)); const _77: rs.String[] = [make$conversions_Value_String(data, 22)]; - put$conversions_Value_String(rs.replaceIn(rs.sliceView(a), _77, 1)[0], out); + put$conversions_Value_String(rs.sliceReplaceAll(a, _77, 1)[0], out); const by: rs.String = make$conversions_Value_String(data, 23); rs.idx(s, 0); let r: rs.String = s.data[s.start]; const _89: rs.Slice = rs.sliceOfPlace(rs.place(() => r, (value2) => r = value2)); const _91: rs.String[] = [by]; - Object.assign(rs.replaceIn(rs.sliceView(_89), _91)[0], make$conversions_Value_String(data, 24)); + Object.assign(rs.sliceReplaceAll(_89, _91)[0], make$conversions_Value_String(data, 24)); put$conversions_Value_String(r, out); rs.idx(s, 0); put$conversions_Value_String(s.data[s.start], out); @@ -870,10 +875,10 @@ export function lentParam$String(to: rs.String, data: rs.ByteSlice, out: rs.Byte rs.idx(s, 0); const borrowed3 = s.data; const borrowed4 = s.start; - const _114: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(rs.sliceOfPlace(rs.place(() => borrowed3[borrowed4], (value3) => borrowed3[borrowed4] = value3))))); + const _114: rs.Cell = rs.cellOfSlice(rs.sliceOfPlace(rs.place(() => borrowed3[borrowed4], (value3) => borrowed3[borrowed4] = value3))); const _121: rs.String[] = [make$conversions_Value_String(data, 26)]; - const pointer = rs.sliceFrom(_114.v); - const old6 = rs.objectCopy(rs.sliceView(pointer), 1); + const pointer = rs.cellArray(_114, rs.sliceFrom); + const old6 = rs.sliceCopy(pointer, 1); rs.sliceSet(pointer, _121); put$conversions_Value_String(old6[0], out); rs.idx(s, 0); @@ -883,7 +888,12 @@ export function lentParam$String(to: rs.String, data: rs.ByteSlice, out: rs.Byte rs.idx(s, 0); const borrowed7 = s.data; const borrowed8 = s.start; - put$conversions_Value_String(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => borrowed7[borrowed8], (value5) => borrowed7[borrowed8] = value5)), 1), rs.objectCopy), [[make$conversions_Value_String(data, 28)]])[0][0], out); + const _147: rs.Cell = rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => borrowed7[borrowed8], (value5) => borrowed7[borrowed8] = value5)), 1), rs.objectCopy); + const _148: rs.String[][] = [[make$conversions_Value_String(data, 28)]]; + const pointer2 = rs.cellArray(_147, rs.arraySliceOf(rs.sliceFrom)); + const old7 = rs.arraySliceCopy(pointer2, rs.objectCopy); + rs.arraySliceSet(pointer2, _148); + put$conversions_Value_String(old7[0][0], out); rs.idx(s, 0); s.data[s.start] = rs.stringCloneFrom(s.data[s.start], other); rs.idx(s, 0); @@ -922,13 +932,13 @@ export function lentParam$Vec_u32(to: rs.Vec, data: rs.ByteSlice, out: r const borrowed2 = s.start; const a: rs.Slice> = rs.sliceOfPlace(rs.place(() => borrowed[borrowed2], (value) => borrowed[borrowed2] = value)); const _77: rs.Vec[] = [make$conversions_Value_Vec_u32(data, 22)]; - put$conversions_Value_Vec_u32(rs.replaceIn(rs.sliceView(a), _77, 1)[0], out); + put$conversions_Value_Vec_u32(rs.sliceReplaceAll(a, _77, 1)[0], out); const by: rs.Vec = make$conversions_Value_Vec_u32(data, 23); rs.idx(s, 0); let r: rs.Vec = s.data[s.start]; const _89: rs.Slice> = rs.sliceOfPlace(rs.place(() => r, (value2) => r = value2)); const _91: rs.Vec[] = [by]; - Object.assign(rs.replaceIn(rs.sliceView(_89), _91)[0], make$conversions_Value_Vec_u32(data, 24)); + Object.assign(rs.sliceReplaceAll(_89, _91)[0], make$conversions_Value_Vec_u32(data, 24)); put$conversions_Value_Vec_u32(r, out); rs.idx(s, 0); put$conversions_Value_Vec_u32(s.data[s.start], out); @@ -937,10 +947,10 @@ export function lentParam$Vec_u32(to: rs.Vec, data: rs.ByteSlice, out: r rs.idx(s, 0); const borrowed3 = s.data; const borrowed4 = s.start; - const _114: rs.Cell[]> = rs.cellOfPlace(rs.partPlace(rs.sliceView(rs.sliceOfPlace(rs.place(() => borrowed3[borrowed4], (value3) => borrowed3[borrowed4] = value3))))); + const _114: rs.Cell[]> = rs.cellOfSlice(rs.sliceOfPlace(rs.place(() => borrowed3[borrowed4], (value3) => borrowed3[borrowed4] = value3))); const _121: rs.Vec[] = [make$conversions_Value_Vec_u32(data, 26)]; - const pointer = rs.sliceFrom(_114.v); - const old6 = rs.objectCopy(rs.sliceView(pointer), 1); + const pointer = rs.cellArray(_114, rs.sliceFrom); + const old6 = rs.sliceCopy(pointer, 1); rs.sliceSet(pointer, _121); put$conversions_Value_Vec_u32(old6[0], out); rs.idx(s, 0); @@ -950,7 +960,12 @@ export function lentParam$Vec_u32(to: rs.Vec, data: rs.ByteSlice, out: r rs.idx(s, 0); const borrowed7 = s.data; const borrowed8 = s.start; - put$conversions_Value_Vec_u32(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => borrowed7[borrowed8], (value5) => borrowed7[borrowed8] = value5)), 1), rs.objectCopy), [[make$conversions_Value_Vec_u32(data, 28)]])[0][0], out); + const _147: rs.Cell[][]> = rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => borrowed7[borrowed8], (value5) => borrowed7[borrowed8] = value5)), 1), rs.objectCopy); + const _148: rs.Vec[][] = [[make$conversions_Value_Vec_u32(data, 28)]]; + const pointer2 = rs.cellArray(_147, rs.arraySliceOf(rs.sliceFrom)); + const old7 = rs.arraySliceCopy(pointer2, rs.objectCopy); + rs.arraySliceSet(pointer2, _148); + put$conversions_Value_Vec_u32(old7[0][0], out); rs.idx(s, 0); rs.vecCloneFrom(s.data[s.start], other, 4); rs.idx(s, 0); @@ -989,13 +1004,13 @@ export function lentParam$Vec_u8(to: rs.ByteVec, data: rs.ByteSlice, out: rs.Byt const borrowed2 = s.start; const a: rs.Slice = rs.sliceOfPlace(rs.place(() => borrowed[borrowed2], (value) => borrowed[borrowed2] = value)); const _77: rs.ByteVec[] = [make$conversions_Value_Vec_u8(data, 22)]; - put$conversions_Value_Vec_u8(rs.replaceIn(rs.sliceView(a), _77, 1)[0], out); + put$conversions_Value_Vec_u8(rs.sliceReplaceAll(a, _77, 1)[0], out); const by: rs.ByteVec = make$conversions_Value_Vec_u8(data, 23); rs.idx(s, 0); let r: rs.ByteVec = s.data[s.start]; const _89: rs.Slice = rs.sliceOfPlace(rs.place(() => r, (value2) => r = value2)); const _91: rs.ByteVec[] = [by]; - Object.assign(rs.replaceIn(rs.sliceView(_89), _91)[0], make$conversions_Value_Vec_u8(data, 24)); + Object.assign(rs.sliceReplaceAll(_89, _91)[0], make$conversions_Value_Vec_u8(data, 24)); put$conversions_Value_Vec_u8(r, out); rs.idx(s, 0); put$conversions_Value_Vec_u8(s.data[s.start], out); @@ -1004,10 +1019,10 @@ export function lentParam$Vec_u8(to: rs.ByteVec, data: rs.ByteSlice, out: rs.Byt rs.idx(s, 0); const borrowed3 = s.data; const borrowed4 = s.start; - const _114: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(rs.sliceOfPlace(rs.place(() => borrowed3[borrowed4], (value3) => borrowed3[borrowed4] = value3))))); + const _114: rs.Cell = rs.cellOfSlice(rs.sliceOfPlace(rs.place(() => borrowed3[borrowed4], (value3) => borrowed3[borrowed4] = value3))); const _121: rs.ByteVec[] = [make$conversions_Value_Vec_u8(data, 26)]; - const pointer = rs.sliceFrom(_114.v); - const old6 = rs.objectCopy(rs.sliceView(pointer), 1); + const pointer = rs.cellArray(_114, rs.sliceFrom); + const old6 = rs.sliceCopy(pointer, 1); rs.sliceSet(pointer, _121); put$conversions_Value_Vec_u8(old6[0], out); rs.idx(s, 0); @@ -1017,7 +1032,12 @@ export function lentParam$Vec_u8(to: rs.ByteVec, data: rs.ByteSlice, out: rs.Byt rs.idx(s, 0); const borrowed7 = s.data; const borrowed8 = s.start; - put$conversions_Value_Vec_u8(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => borrowed7[borrowed8], (value5) => borrowed7[borrowed8] = value5)), 1), rs.objectCopy), [[make$conversions_Value_Vec_u8(data, 28)]])[0][0], out); + const _147: rs.Cell = rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => borrowed7[borrowed8], (value5) => borrowed7[borrowed8] = value5)), 1), rs.objectCopy); + const _148: rs.ByteVec[][] = [[make$conversions_Value_Vec_u8(data, 28)]]; + const pointer2 = rs.cellArray(_147, rs.arraySliceOf(rs.sliceFrom)); + const old7 = rs.arraySliceCopy(pointer2, rs.objectCopy); + rs.arraySliceSet(pointer2, _148); + put$conversions_Value_Vec_u8(old7[0][0], out); rs.idx(s, 0); rs.byteVecCloneFrom(s.data[s.start], other); rs.idx(s, 0); @@ -1058,7 +1078,7 @@ export function lentParam$array0_u8(to: rs.ByteSlice, data: rs.ByteSlice, out: r let r: rs.ByteSlice = rs.arraySliceAt(s, 0); const _89: rs.Slice = rs.sliceOfPlace(rs.place(() => r, (value) => r = value)); const _91: rs.ByteSlice[] = [rs.byteSliceFrom(by)]; - const _88: rs.ByteSlice[] = rs.replaceIn(rs.sliceView(_89), _91); + const _88: rs.ByteSlice[] = rs.sliceReplaceAll(_89, _91); const _93: Uint8Array = copy$array_u8(make$conversions_Value_array0_u8(data, 24)); _88[0].data.set(_93, _88[0].start); put$conversions_Value_array0_u8(r, out); @@ -1132,7 +1152,7 @@ export function lentParam$array1_u8(to: rs.ByteSlice, data: rs.ByteSlice, out: r let r: rs.ByteSlice = rs.arraySliceAt(s, 0); const _89: rs.Slice = rs.sliceOfPlace(rs.place(() => r, (value) => r = value)); const _91: rs.ByteSlice[] = [rs.byteSliceFrom(by)]; - const _88: rs.ByteSlice[] = rs.replaceIn(rs.sliceView(_89), _91); + const _88: rs.ByteSlice[] = rs.sliceReplaceAll(_89, _91); const _93: Uint8Array = copy$array_u8(make$conversions_Value_array1_u8(data, 24)); _88[0].data.set(_93, _88[0].start); put$conversions_Value_array1_u8(r, out); @@ -1146,11 +1166,21 @@ export function lentParam$array1_u8(to: rs.ByteSlice, data: rs.ByteSlice, out: r rs.byteSliceSet(pointer, _111); put$conversions_Value_array1_u8(rs.byteSliceFrom(old6), out); rs.idx(s, 0); - put$conversions_Value_array1_u8(rs.byteSliceFrom(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceAt(s, 0), 1)), [copy$array_u8(make$conversions_Value_array1_u8(data, 26))])[0]), out); + const _114: rs.Cell = rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceAt(s, 0), 1)); + const _121: Uint8Array[] = [copy$array_u8(make$conversions_Value_array1_u8(data, 26))]; + const pointer2 = rs.cellArray(_114, rs.arraySliceOf(rs.byteSliceFrom)); + const old7 = rs.arraySliceCopy(pointer2); + rs.arraySliceSet(pointer2, _121); + put$conversions_Value_array1_u8(rs.byteSliceFrom(old7[0]), out); rs.idx(s, 0); put$conversions_Value_array1_u8(rs.byteSliceFrom(replaceFirst$array1_u8(rs.arraySliceOne(rs.arraySliceOne(rs.arraySliceAt(s, 0), 1), 1), [make$conversions_Value_array1_u8(data, 27)])[0]), out); rs.idx(s, 0); - put$conversions_Value_array1_u8(rs.byteSliceFrom(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceOne(rs.arraySliceAt(s, 0), 1), 1)), [[copy$array_u8(make$conversions_Value_array1_u8(data, 28))]])[0][0]), out); + const _147: rs.Cell = rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceOne(rs.arraySliceAt(s, 0), 1), 1)); + const _148: Uint8Array[][] = [[copy$array_u8(make$conversions_Value_array1_u8(data, 28))]]; + const pointer3 = rs.cellArray(_147, rs.arraySliceOf(rs.arraySliceOf(rs.byteSliceFrom))); + const old8 = rs.arraySliceCopy(pointer3); + rs.arraySliceSet(pointer3, _148); + put$conversions_Value_array1_u8(rs.byteSliceFrom(old8[0][0]), out); rs.idx(s, 0); const _159: rs.ByteSlice = rs.byteSliceFrom(other); const slice7 = rs.arraySliceAt(s, 0); @@ -1171,24 +1201,24 @@ export function lentParam$array2_u32(to: rs.Slice, data: rs.ByteSlice, o const other: rs.u32[] = copy$array_u32(make$conversions_Value_array2_u32(data, 19)); rs.idx(s, 0); const _16: rs.Slice = rs.sliceFrom(other); - rs.sliceSet(_16, rs.replaceIn(rs.sliceView(rs.arraySliceAt(s, 0)), rs.sliceToArray(_16))); + rs.sliceSet(_16, rs.sliceReplaceAll(rs.arraySliceAt(s, 0), rs.sliceToArray(_16))); put$conversions_Value_array2_u32(rs.sliceFrom(other), out); const _20: rs.Slice = rs.sliceFrom(other); rs.idx(s, 0); const slice2 = rs.arraySliceAt(s, 0); - rs.sliceSet(slice2, rs.replaceIn(rs.sliceView(_20), rs.sliceToArray(slice2))); + rs.sliceSet(slice2, rs.sliceReplaceAll(_20, rs.sliceToArray(slice2))); put$conversions_Value_array2_u32(rs.sliceFrom(other), out); const t: rs.ArraySlice> = rs.arraySliceFrom(rs.vecFrom(copy$array_array2_u32([make$conversions_Value_array2_u32(data, 20), make$conversions_Value_array2_u32(data, 21)]).map(copy$array_u32)).items, rs.sliceFrom); rs.idx(s, 0); rs.idx(t, 1); const slice3 = rs.arraySliceAt(s, 0); const slice4 = rs.arraySliceAt(t, 1); - rs.sliceSet(slice4, rs.replaceIn(rs.sliceView(slice3), rs.sliceToArray(slice4))); + rs.sliceSet(slice4, rs.sliceReplaceAll(slice3, rs.sliceToArray(slice4))); rs.idx(t, 0); rs.idx(s, 0); const slice5 = rs.arraySliceAt(t, 0); const slice6 = rs.arraySliceAt(s, 0); - rs.sliceSet(slice6, rs.replaceIn(rs.sliceView(slice5), rs.sliceToArray(slice6))); + rs.sliceSet(slice6, rs.sliceReplaceAll(slice5, rs.sliceToArray(slice6))); rs.idx(t, 0); put$conversions_Value_array2_u32(rs.arraySliceAt(t, 0), out); rs.idx(t, 1); @@ -1202,28 +1232,38 @@ export function lentParam$array2_u32(to: rs.Slice, data: rs.ByteSlice, o let r: rs.Slice = rs.arraySliceAt(s, 0); const _89: rs.Slice> = rs.sliceOfPlace(rs.place(() => r, (value) => r = value)); const _91: rs.Slice[] = [rs.sliceFrom(by)]; - const _88: rs.Slice[] = rs.replaceIn(rs.sliceView(_89), _91); + const _88: rs.Slice[] = rs.sliceReplaceAll(_89, _91); const _93: rs.u32[] = copy$array_u32(make$conversions_Value_array2_u32(data, 24)); rs.sliceSet(_88[0], _93); put$conversions_Value_array2_u32(r, out); rs.idx(s, 0); put$conversions_Value_array2_u32(rs.arraySliceAt(s, 0), out); rs.idx(s, 0); - const _105: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(rs.arraySliceAt(s, 0)))); + const _105: rs.Cell = rs.cellOfSlice(rs.arraySliceAt(s, 0)); const _111: rs.u32[] = copy$array_u32(make$conversions_Value_array2_u32(data, 25)); - const pointer = rs.sliceFrom(_105.v); - const old6 = rs.objectCopy(rs.sliceView(pointer)); + const pointer = rs.cellArray(_105, rs.sliceFrom); + const old6 = rs.sliceCopy(pointer); rs.sliceSet(pointer, _111); put$conversions_Value_array2_u32(rs.sliceFrom(old6), out); rs.idx(s, 0); - put$conversions_Value_array2_u32(rs.sliceFrom(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceAt(s, 0), 2)), [copy$array_u32(make$conversions_Value_array2_u32(data, 26))])[0]), out); + const _114: rs.Cell = rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceAt(s, 0), 2)); + const _121: rs.u32[][] = [copy$array_u32(make$conversions_Value_array2_u32(data, 26))]; + const pointer2 = rs.cellArray(_114, rs.arraySliceOf(rs.sliceFrom)); + const old7 = rs.arraySliceCopy(pointer2); + rs.arraySliceSet(pointer2, _121); + put$conversions_Value_array2_u32(rs.sliceFrom(old7[0]), out); rs.idx(s, 0); put$conversions_Value_array2_u32(rs.sliceFrom(replaceFirst$array2_u32(rs.arraySliceOne(rs.arraySliceOne(rs.arraySliceAt(s, 0), 2), 1), [make$conversions_Value_array2_u32(data, 27)])[0]), out); rs.idx(s, 0); - put$conversions_Value_array2_u32(rs.sliceFrom(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceOne(rs.arraySliceAt(s, 0), 2), 1)), [[copy$array_u32(make$conversions_Value_array2_u32(data, 28))]])[0][0]), out); + const _147: rs.Cell = rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceOne(rs.arraySliceAt(s, 0), 2), 1)); + const _148: rs.u32[][][] = [[copy$array_u32(make$conversions_Value_array2_u32(data, 28))]]; + const pointer3 = rs.cellArray(_147, rs.arraySliceOf(rs.arraySliceOf(rs.sliceFrom))); + const old8 = rs.arraySliceCopy(pointer3); + rs.arraySliceSet(pointer3, _148); + put$conversions_Value_array2_u32(rs.sliceFrom(old8[0][0]), out); rs.idx(s, 0); const _159: rs.Slice = rs.sliceFrom(other); - rs.replaceIn(rs.sliceView(rs.arraySliceAt(s, 0)), rs.sliceToArray(_159)); + rs.sliceReplaceAll(rs.arraySliceAt(s, 0), rs.sliceToArray(_159)); rs.idx(s, 0); put$conversions_Value_array2_u32(rs.arraySliceAt(s, 0), out); } @@ -1280,7 +1320,7 @@ export function lentParam$array3_u8(to: rs.ByteSlice, data: rs.ByteSlice, out: r let r: rs.ByteSlice = rs.arraySliceAt(s, 0); const _89: rs.Slice = rs.sliceOfPlace(rs.place(() => r, (value) => r = value)); const _91: rs.ByteSlice[] = [rs.byteSliceFrom(by)]; - const _88: rs.ByteSlice[] = rs.replaceIn(rs.sliceView(_89), _91); + const _88: rs.ByteSlice[] = rs.sliceReplaceAll(_89, _91); const _93: Uint8Array = copy$array_u8(make$conversions_Value_array3_u8(data, 24)); _88[0].data.set(_93, _88[0].start); put$conversions_Value_array3_u8(r, out); @@ -1294,11 +1334,21 @@ export function lentParam$array3_u8(to: rs.ByteSlice, data: rs.ByteSlice, out: r rs.byteSliceSet(pointer, _111); put$conversions_Value_array3_u8(rs.byteSliceFrom(old6), out); rs.idx(s, 0); - put$conversions_Value_array3_u8(rs.byteSliceFrom(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceAt(s, 0), 3)), [copy$array_u8(make$conversions_Value_array3_u8(data, 26))])[0]), out); + const _114: rs.Cell = rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceAt(s, 0), 3)); + const _121: Uint8Array[] = [copy$array_u8(make$conversions_Value_array3_u8(data, 26))]; + const pointer2 = rs.cellArray(_114, rs.arraySliceOf(rs.byteSliceFrom)); + const old7 = rs.arraySliceCopy(pointer2); + rs.arraySliceSet(pointer2, _121); + put$conversions_Value_array3_u8(rs.byteSliceFrom(old7[0]), out); rs.idx(s, 0); put$conversions_Value_array3_u8(rs.byteSliceFrom(replaceFirst$array3_u8(rs.arraySliceOne(rs.arraySliceOne(rs.arraySliceAt(s, 0), 3), 1), [make$conversions_Value_array3_u8(data, 27)])[0]), out); rs.idx(s, 0); - put$conversions_Value_array3_u8(rs.byteSliceFrom(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceOne(rs.arraySliceAt(s, 0), 3), 1)), [[copy$array_u8(make$conversions_Value_array3_u8(data, 28))]])[0][0]), out); + const _147: rs.Cell = rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceOne(rs.arraySliceAt(s, 0), 3), 1)); + const _148: Uint8Array[][] = [[copy$array_u8(make$conversions_Value_array3_u8(data, 28))]]; + const pointer3 = rs.cellArray(_147, rs.arraySliceOf(rs.arraySliceOf(rs.byteSliceFrom))); + const old8 = rs.arraySliceCopy(pointer3); + rs.arraySliceSet(pointer3, _148); + put$conversions_Value_array3_u8(rs.byteSliceFrom(old8[0][0]), out); rs.idx(s, 0); const _159: rs.ByteSlice = rs.byteSliceFrom(other); const slice7 = rs.arraySliceAt(s, 0); @@ -1359,7 +1409,7 @@ export function lentParam$array40_u8(to: rs.ByteSlice, data: rs.ByteSlice, out: let r: rs.ByteSlice = rs.arraySliceAt(s, 0); const _89: rs.Slice = rs.sliceOfPlace(rs.place(() => r, (value) => r = value)); const _91: rs.ByteSlice[] = [rs.byteSliceFrom(by)]; - const _88: rs.ByteSlice[] = rs.replaceIn(rs.sliceView(_89), _91); + const _88: rs.ByteSlice[] = rs.sliceReplaceAll(_89, _91); const _93: Uint8Array = copy$array_u8(make$conversions_Value_array40_u8(data, 24)); _88[0].data.set(_93, _88[0].start); put$conversions_Value_array40_u8(r, out); @@ -1373,11 +1423,21 @@ export function lentParam$array40_u8(to: rs.ByteSlice, data: rs.ByteSlice, out: rs.byteSliceSet(pointer, _111); put$conversions_Value_array40_u8(rs.byteSliceFrom(old6), out); rs.idx(s, 0); - put$conversions_Value_array40_u8(rs.byteSliceFrom(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceAt(s, 0), 40)), [copy$array_u8(make$conversions_Value_array40_u8(data, 26))])[0]), out); + const _114: rs.Cell = rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceAt(s, 0), 40)); + const _121: Uint8Array[] = [copy$array_u8(make$conversions_Value_array40_u8(data, 26))]; + const pointer2 = rs.cellArray(_114, rs.arraySliceOf(rs.byteSliceFrom)); + const old7 = rs.arraySliceCopy(pointer2); + rs.arraySliceSet(pointer2, _121); + put$conversions_Value_array40_u8(rs.byteSliceFrom(old7[0]), out); rs.idx(s, 0); put$conversions_Value_array40_u8(rs.byteSliceFrom(replaceFirst$array40_u8(rs.arraySliceOne(rs.arraySliceOne(rs.arraySliceAt(s, 0), 40), 1), [make$conversions_Value_array40_u8(data, 27)])[0]), out); rs.idx(s, 0); - put$conversions_Value_array40_u8(rs.byteSliceFrom(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceOne(rs.arraySliceAt(s, 0), 40), 1)), [[copy$array_u8(make$conversions_Value_array40_u8(data, 28))]])[0][0]), out); + const _147: rs.Cell = rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceOne(rs.arraySliceAt(s, 0), 40), 1)); + const _148: Uint8Array[][] = [[copy$array_u8(make$conversions_Value_array40_u8(data, 28))]]; + const pointer3 = rs.cellArray(_147, rs.arraySliceOf(rs.arraySliceOf(rs.byteSliceFrom))); + const old8 = rs.arraySliceCopy(pointer3); + rs.arraySliceSet(pointer3, _148); + put$conversions_Value_array40_u8(rs.byteSliceFrom(old8[0][0]), out); rs.idx(s, 0); const _159: rs.ByteSlice = rs.byteSliceFrom(other); const slice7 = rs.arraySliceAt(s, 0); @@ -1421,7 +1481,7 @@ export function lentParam$conversions_Logged(to: Logged.Logged, data: rs.ByteSli const borrowed2 = s.start; const a: rs.Slice = rs.sliceOfPlace(rs.place(() => borrowed[borrowed2], (value) => borrowed[borrowed2] = value)); const _77: Logged.Logged[] = [Logged.make$conversions_Value(data, 22)]; - const _76: Logged.Logged[] = rs.replaceIn(rs.sliceView(a), _77, 1); + const _76: Logged.Logged[] = rs.sliceReplaceAll(a, _77, 1); Logged.put$conversions_Value(_76[0], out); rs.dropAll(_76); const by: Logged.Logged = Logged.make$conversions_Value(data, 23); @@ -1429,7 +1489,7 @@ export function lentParam$conversions_Logged(to: Logged.Logged, data: rs.ByteSli let r: Logged.Logged = s.data[s.start]; const _89: rs.Slice = rs.sliceOfPlace(rs.place(() => r, (value2) => r = value2)); const _91: Logged.Logged[] = [by]; - const _88: Logged.Logged[] = rs.replaceIn(rs.sliceView(_89), _91); + const _88: Logged.Logged[] = rs.sliceReplaceAll(_89, _91); const _93: Logged.Logged = Logged.make$conversions_Value(data, 24); _88[0][Symbol.dispose](); Object.assign(_88[0], _93); @@ -1448,10 +1508,10 @@ export function lentParam$conversions_Logged(to: Logged.Logged, data: rs.ByteSli rs.idx(s, 0); const borrowed3 = s.data; const borrowed4 = s.start; - const _114: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(rs.sliceOfPlace(rs.place(() => borrowed3[borrowed4], (value3) => borrowed3[borrowed4] = value3))))); + const _114: rs.Cell = rs.cellOfSlice(rs.sliceOfPlace(rs.place(() => borrowed3[borrowed4], (value3) => borrowed3[borrowed4] = value3))); const _121: Logged.Logged[] = [Logged.make$conversions_Value(data, 26)]; - const pointer2 = rs.sliceFrom(_114.v); - const old7 = rs.objectCopy(rs.sliceView(pointer2), 1); + const pointer2 = rs.cellArray(_114, rs.sliceFrom); + const old7 = rs.sliceCopy(pointer2, 1); rs.sliceSet(pointer2, _121); const old: Logged.Logged = old7[0]; Logged.put$conversions_Value(old, out); @@ -1463,7 +1523,12 @@ export function lentParam$conversions_Logged(to: Logged.Logged, data: rs.ByteSli rs.idx(s, 0); const borrowed7 = s.data; const borrowed8 = s.start; - const old3: Logged.Logged = rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => borrowed7[borrowed8], (value5) => borrowed7[borrowed8] = value5)), 1), copy$conversions_Logged), [[Logged.make$conversions_Value(data, 28)]])[0][0]; + const _147: rs.Cell = rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => borrowed7[borrowed8], (value5) => borrowed7[borrowed8] = value5)), 1), copy$conversions_Logged); + const _148: Logged.Logged[][] = [[Logged.make$conversions_Value(data, 28)]]; + const pointer3 = rs.cellArray(_147, rs.arraySliceOf(rs.sliceFrom)); + const old8 = rs.arraySliceCopy(pointer3, copy$conversions_Logged); + rs.arraySliceSet(pointer3, _148); + const old3: Logged.Logged = old8[0][0]; Logged.put$conversions_Value(old3, out); rs.idx(s, 0); rs.sliceReplace(s.data, s.start, Logged.clone$Clone(other))[Symbol.dispose](); @@ -1509,13 +1574,13 @@ export function lentParam$conversions_Named(to: Named.Named, data: rs.ByteSlice, const borrowed2 = s.start; const a: rs.Slice = rs.sliceOfPlace(rs.place(() => borrowed[borrowed2], (value) => borrowed[borrowed2] = value)); const _77: Named.Named[] = [Named.make$conversions_Value(data, 22)]; - Named.put$conversions_Value(rs.replaceIn(rs.sliceView(a), _77, 1)[0], out); + Named.put$conversions_Value(rs.sliceReplaceAll(a, _77, 1)[0], out); const by: Named.Named = Named.make$conversions_Value(data, 23); rs.idx(s, 0); let r: Named.Named = s.data[s.start]; const _89: rs.Slice = rs.sliceOfPlace(rs.place(() => r, (value2) => r = value2)); const _91: Named.Named[] = [by]; - Object.assign(rs.replaceIn(rs.sliceView(_89), _91)[0], Named.make$conversions_Value(data, 24)); + Object.assign(rs.sliceReplaceAll(_89, _91)[0], Named.make$conversions_Value(data, 24)); Named.put$conversions_Value(r, out); rs.idx(s, 0); Named.put$conversions_Value(s.data[s.start], out); @@ -1529,10 +1594,10 @@ export function lentParam$conversions_Named(to: Named.Named, data: rs.ByteSlice, rs.idx(s, 0); const borrowed3 = s.data; const borrowed4 = s.start; - const _114: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(rs.sliceOfPlace(rs.place(() => borrowed3[borrowed4], (value3) => borrowed3[borrowed4] = value3))))); + const _114: rs.Cell = rs.cellOfSlice(rs.sliceOfPlace(rs.place(() => borrowed3[borrowed4], (value3) => borrowed3[borrowed4] = value3))); const _121: Named.Named[] = [Named.make$conversions_Value(data, 26)]; - const pointer2 = rs.sliceFrom(_114.v); - const old7 = rs.objectCopy(rs.sliceView(pointer2), 1); + const pointer2 = rs.cellArray(_114, rs.sliceFrom); + const old7 = rs.sliceCopy(pointer2, 1); rs.sliceSet(pointer2, _121); Named.put$conversions_Value(old7[0], out); rs.idx(s, 0); @@ -1542,7 +1607,12 @@ export function lentParam$conversions_Named(to: Named.Named, data: rs.ByteSlice, rs.idx(s, 0); const borrowed7 = s.data; const borrowed8 = s.start; - Named.put$conversions_Value(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => borrowed7[borrowed8], (value5) => borrowed7[borrowed8] = value5)), 1), copy$conversions_Named), [[Named.make$conversions_Value(data, 28)]])[0][0], out); + const _147: rs.Cell = rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => borrowed7[borrowed8], (value5) => borrowed7[borrowed8] = value5)), 1), copy$conversions_Named); + const _148: Named.Named[][] = [[Named.make$conversions_Value(data, 28)]]; + const pointer3 = rs.cellArray(_147, rs.arraySliceOf(rs.sliceFrom)); + const old8 = rs.arraySliceCopy(pointer3, copy$conversions_Named); + rs.arraySliceSet(pointer3, _148); + Named.put$conversions_Value(old8[0][0], out); rs.idx(s, 0); s.data[s.start] = Named.clone$Clone(other); rs.idx(s, 0); @@ -1589,14 +1659,14 @@ export function lentParam$u32(to: rs.Place, data: rs.ByteSlice, out: rs. const borrowed2 = s.start; const a: rs.Slice = rs.sliceOfPlace(rs.place(() => borrowed[borrowed2], (value) => borrowed[borrowed2] = value)); const _77: rs.u32[] = [make$conversions_Value_u32(data, 22)]; - put$conversions_Value_u32(rs.replaceIn(rs.sliceView(a), _77)[0], out); + put$conversions_Value_u32(rs.sliceReplaceAll(a, _77)[0], out); let by: rs.u32 = make$conversions_Value_u32(data, 23); rs.idx(s, 0); const borrowed3 = s.start; let r: rs.Place = rs.place(() => s.data[borrowed3], (value2) => s.data[borrowed3] = value2); const _89: rs.Slice> = rs.sliceOfPlace(rs.place(() => r, (value3) => r = value3)); const _91: rs.Place[] = [rs.place(() => by, (value4) => by = value4)]; - rs.replaceIn(rs.sliceView(_89), _91)[0].v = make$conversions_Value_u32(data, 24); + rs.sliceReplaceAll(_89, _91)[0].v = make$conversions_Value_u32(data, 24); put$conversions_Value_u32(r.v, out); rs.idx(s, 0); put$conversions_Value_u32(s.data[s.start], out); @@ -1607,10 +1677,10 @@ export function lentParam$u32(to: rs.Place, data: rs.ByteSlice, out: rs. rs.idx(s, 0); const borrowed6 = s.data; const borrowed7 = s.start; - const _114: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(rs.sliceOfPlace(rs.place(() => borrowed6[borrowed7], (value6) => borrowed6[borrowed7] = value6))))); + const _114: rs.Cell = rs.cellOfSlice(rs.sliceOfPlace(rs.place(() => borrowed6[borrowed7], (value6) => borrowed6[borrowed7] = value6))); const _121: rs.u32[] = [make$conversions_Value_u32(data, 26)]; - const pointer = rs.sliceFrom(_114.v); - const old6 = rs.objectCopy(rs.sliceView(pointer)); + const pointer = rs.cellArray(_114, rs.sliceFrom); + const old6 = rs.sliceCopy(pointer); rs.sliceSet(pointer, _121); put$conversions_Value_u32(old6[0], out); rs.idx(s, 0); @@ -1620,7 +1690,12 @@ export function lentParam$u32(to: rs.Place, data: rs.ByteSlice, out: rs. rs.idx(s, 0); const borrowed10 = s.data; const borrowed11 = s.start; - put$conversions_Value_u32(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => borrowed10[borrowed11], (value8) => borrowed10[borrowed11] = value8)), 1)), [[make$conversions_Value_u32(data, 28)]])[0][0], out); + const _147: rs.Cell = rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => borrowed10[borrowed11], (value8) => borrowed10[borrowed11] = value8)), 1)); + const _148: rs.u32[][] = [[make$conversions_Value_u32(data, 28)]]; + const pointer2 = rs.cellArray(_147, rs.arraySliceOf(rs.sliceFrom)); + const old7 = rs.arraySliceCopy(pointer2); + rs.arraySliceSet(pointer2, _148); + put$conversions_Value_u32(old7[0][0], out); rs.idx(s, 0); s.data[s.start] = other; rs.idx(s, 0); @@ -1667,14 +1742,14 @@ export function lentParam$u64(to: rs.Place, data: rs.ByteSlice, out: rs. const borrowed2 = s.start; const a: rs.Slice = rs.sliceOfPlace(rs.place(() => borrowed[borrowed2], (value) => borrowed[borrowed2] = value)); const _77: rs.u64[] = [make$conversions_Value_u64(data, 22)]; - put$conversions_Value_u64(rs.replaceIn(rs.sliceView(a), _77)[0], out); + put$conversions_Value_u64(rs.sliceReplaceAll(a, _77)[0], out); let by: rs.u64 = make$conversions_Value_u64(data, 23); rs.idx(s, 0); const borrowed3 = s.start; let r: rs.Place = rs.place(() => s.data[borrowed3], (value2) => s.data[borrowed3] = value2); const _89: rs.Slice> = rs.sliceOfPlace(rs.place(() => r, (value3) => r = value3)); const _91: rs.Place[] = [rs.place(() => by, (value4) => by = value4)]; - rs.replaceIn(rs.sliceView(_89), _91)[0].v = make$conversions_Value_u64(data, 24); + rs.sliceReplaceAll(_89, _91)[0].v = make$conversions_Value_u64(data, 24); put$conversions_Value_u64(r.v, out); rs.idx(s, 0); put$conversions_Value_u64(s.data[s.start], out); @@ -1685,10 +1760,10 @@ export function lentParam$u64(to: rs.Place, data: rs.ByteSlice, out: rs. rs.idx(s, 0); const borrowed6 = s.data; const borrowed7 = s.start; - const _114: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(rs.sliceOfPlace(rs.place(() => borrowed6[borrowed7], (value6) => borrowed6[borrowed7] = value6))))); + const _114: rs.Cell = rs.cellOfSlice(rs.sliceOfPlace(rs.place(() => borrowed6[borrowed7], (value6) => borrowed6[borrowed7] = value6))); const _121: rs.u64[] = [make$conversions_Value_u64(data, 26)]; - const pointer = rs.sliceFrom(_114.v); - const old6 = rs.objectCopy(rs.sliceView(pointer)); + const pointer = rs.cellArray(_114, rs.sliceFrom); + const old6 = rs.sliceCopy(pointer); rs.sliceSet(pointer, _121); put$conversions_Value_u64(old6[0], out); rs.idx(s, 0); @@ -1698,7 +1773,12 @@ export function lentParam$u64(to: rs.Place, data: rs.ByteSlice, out: rs. rs.idx(s, 0); const borrowed10 = s.data; const borrowed11 = s.start; - put$conversions_Value_u64(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => borrowed10[borrowed11], (value8) => borrowed10[borrowed11] = value8)), 1)), [[make$conversions_Value_u64(data, 28)]])[0][0], out); + const _147: rs.Cell = rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => borrowed10[borrowed11], (value8) => borrowed10[borrowed11] = value8)), 1)); + const _148: rs.u64[][] = [[make$conversions_Value_u64(data, 28)]]; + const pointer2 = rs.cellArray(_147, rs.arraySliceOf(rs.sliceFrom)); + const old7 = rs.arraySliceCopy(pointer2); + rs.arraySliceSet(pointer2, _148); + put$conversions_Value_u64(old7[0][0], out); rs.idx(s, 0); s.data[s.start] = other; rs.idx(s, 0); @@ -1762,8 +1842,7 @@ export function lentParam$u8(to: rs.Place, data: rs.ByteSlice, out: rs.By let r: rs.Place = rs.place(() => s.data[borrowed], (value) => s.data[borrowed] = value); const _89: rs.Slice> = rs.sliceOfPlace(rs.place(() => r, (value2) => r = value2)); rs.byteMirrorFlush(mirror); - const _91: rs.Place[] = [rs.place(() => by, (value3) => by = value3)]; - const _88: rs.Place[] = rs.replaceIn(rs.sliceView(_89), _91); + const _88: rs.Place[] = rs.sliceReplaceAll(_89, [rs.place(() => by, (value3) => by = value3)]); rs.byteMirrorFlush(mirror); const _93: rs.u8 = make$conversions_Value_u8(data, 24); rs.byteMirrorFlush(mirror); @@ -1809,7 +1888,11 @@ export function lentParam$u8(to: rs.Place, data: rs.ByteSlice, out: rs.By rs.byteMirrorFlush(mirror); const _147: rs.Cell = rs.cellOfArraySlice(b); rs.byteMirrorFlush(mirror); - const _146: Uint8Array[] = rs.cellReplace(_147, [Uint8Array.of(make$conversions_Value_u8(data, 28))]); + const _148: Uint8Array[] = [Uint8Array.of(make$conversions_Value_u8(data, 28))]; + const pointer2 = rs.cellArray(_147, rs.arraySliceOf(rs.byteSliceFrom)); + const old7 = rs.arraySliceCopy(pointer2); + rs.arraySliceSet(pointer2, _148); + const _146: Uint8Array[] = old7; rs.byteMirrorFlush(mirror); put$conversions_Value_u8(_146[0][0], out); rs.idx(s, 0); @@ -2202,8 +2285,8 @@ export function setThrough$array1_u8(to: rs.ByteSlice, value: Uint8Array): Uint8 /** A cell of what a `&mut` whose place only the caller knows points at, written through. */ export function setThrough$array2_u32(to: rs.Slice, value: rs.u32[]): rs.u32[] { - const pointer = rs.sliceFrom(rs.cellOfPlace(rs.partPlace(rs.sliceView(to))).v); - const old = rs.objectCopy(rs.sliceView(pointer)); + const pointer = rs.cellArray(rs.cellOfSlice(to), rs.sliceFrom); + const old = rs.sliceCopy(pointer); rs.sliceSet(pointer, copy$array_u32(value)); return old; } @@ -2841,29 +2924,23 @@ export function converted$array2_u32(data: rs.ByteSlice, out: rs.ByteVec): void const a: rs.u32[] = copy$array_u32(make$conversions_Value_array2_u32(data, 0)); const b: rs.u32[] = make$conversions_Value_array2_u32(data, 3); const owned: rs.u32[] = a.slice(); - const _8: rs.Slice = rs.sliceFrom(a); - const _9: rs.Slice = rs.sliceFrom(b); - rs.replaceIn(rs.sliceView(_8), rs.sliceToArray(_9)); + rs.sliceReplaceAll(rs.sliceFrom(a), b.slice()); put$conversions_Value_array2_u32(rs.sliceFrom(owned), out); put$conversions_Value_array2_u32(rs.sliceFrom(a), out); const c: rs.u32[] = copy$array_u32(make$conversions_Value_array2_u32(data, 6)); const _16: rs.Slice = rs.sliceFrom(owned); - rs.replaceIn(rs.sliceView(rs.sliceFrom(c)), rs.sliceToArray(_16)); + rs.sliceReplaceAll(rs.sliceFrom(c), rs.sliceToArray(_16)); put$conversions_Value_array2_u32(rs.sliceFrom(c), out); cloneFromParam$array2_u32(rs.sliceFrom(c), rs.sliceFrom(b)); cloneIntoParam$array2_u32(rs.sliceFrom(owned), rs.sliceFrom(a)); put$conversions_Value_array2_u32(rs.sliceFrom(c), out); put$conversions_Value_array2_u32(rs.sliceFrom(a), out); const held: Held.Held = new Held.Held(copy$array_u32(make$conversions_Value_array2_u32(data, 1))); - const _33: rs.Slice = rs.sliceFrom(held.value); - const _34: rs.Slice = rs.sliceFrom(c); - rs.replaceIn(rs.sliceView(_33), rs.sliceToArray(_34)); + rs.sliceReplaceAll(rs.sliceFrom(held.value), c.slice()); const v: rs.Vec = rs.vecFrom(copy$array_array2_u32([make$conversions_Value_array2_u32(data, 2), make$conversions_Value_array2_u32(data, 4)]).map(copy$array_u32)); - const _40: rs.Slice = rs.sliceFrom(v.items[rs.idx(v.items, 1)]); - const _42: rs.Slice = rs.sliceFrom(held.value); - rs.replaceIn(rs.sliceView(_40), rs.sliceToArray(_42)); + rs.sliceReplaceAll(rs.sliceFrom(v.items[rs.idx(v.items, 1)]), held.value.slice()); const _44: rs.Slice = rs.sliceFrom(b); - rs.replaceIn(rs.sliceView(rs.sliceFrom(v.items[rs.idx(v.items, 0)])), rs.sliceToArray(_44)); + rs.sliceReplaceAll(rs.sliceFrom(v.items[rs.idx(v.items, 0)]), rs.sliceToArray(_44)); put$conversions_Value_array2_u32(rs.sliceFrom(held.value), out); put$conversions_Value_array2_u32(rs.sliceFrom(v.items[rs.idx(v.items, 0)]), out); put$conversions_Value_array2_u32(rs.sliceFrom(v.items[rs.idx(v.items, 1)]), out); @@ -2871,26 +2948,24 @@ export function converted$array2_u32(data: rs.ByteSlice, out: rs.ByteVec): void rs.byteVecPush(out, one.length & 0xff); const copied: rs.u32[] = rs.sliceToArray(rs.arraySliceAt(one, 0)); put$conversions_Value_array2_u32(rs.arraySliceAt(one, 0), out); - const _70: rs.Slice = rs.sliceFrom(a); - const _71: rs.Slice = rs.sliceFrom(copied); - rs.replaceIn(rs.sliceView(_70), rs.sliceToArray(_71)); + rs.sliceReplaceAll(rs.sliceFrom(a), copied.slice()); put$conversions_Value_array2_u32(rs.sliceFrom(copied), out); put$conversions_Value_array2_u32(rs.sliceFrom(a), out); - const cell: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(rs.sliceFrom(c)))); + const cell: rs.Cell = rs.cellOfSlice(rs.sliceFrom(c)); const _79: rs.u32[] = copy$array_u32(make$conversions_Value_array2_u32(data, 10)); - const pointer = rs.sliceFrom(cell.v); - const old2 = rs.objectCopy(rs.sliceView(pointer)); + const pointer = rs.cellArray(cell, rs.sliceFrom); + const old2 = rs.sliceCopy(pointer); rs.sliceSet(pointer, _79); const old: rs.u32[] = old2; const _81: rs.u32[] = copy$array_u32(make$conversions_Value_array2_u32(data, 11)); - rs.sliceSet(rs.sliceFrom(cell.v), _81); + rs.sliceSet(rs.cellArray(cell, rs.sliceFrom), _81); put$conversions_Value_array2_u32(rs.sliceFrom(old), out); put$conversions_Value_array2_u32(rs.sliceFrom(c), out); put$conversions_Value_array2_u32(rs.sliceFrom(setThrough$array2_u32(rs.sliceFrom(v.items[rs.idx(v.items, 0)]), make$conversions_Value_array2_u32(data, 12))), out); put$conversions_Value_array2_u32(rs.sliceFrom(v.items[rs.idx(v.items, 0)]), out); - const _96: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(rs.sliceFrom(held.value)))); + const _96: rs.Cell = rs.cellOfSlice(rs.sliceFrom(held.value)); const _98: rs.u32[] = copy$array_u32(make$conversions_Value_array2_u32(data, 17)); - rs.sliceSet(rs.sliceFrom(_96.v), _98); + rs.sliceSet(rs.cellArray(_96, rs.sliceFrom), _98); put$conversions_Value_array2_u32(rs.sliceFrom(held.value), out); const array: rs.u32[][] = [copy$array_u32(make$conversions_Value_array2_u32(data, 13)), copy$array_u32(make$conversions_Value_array2_u32(data, 14)), copy$array_u32(make$conversions_Value_array2_u32(data, 15))]; rs.iterExtendBytes(out, rs.iterSlice(rs.bytesMap([rs.arraySliceFrom(array, rs.sliceFrom).length, rs.arraySliceFrom(array, rs.sliceFrom).length], (n: rs.usize): rs.u8 => { @@ -2903,7 +2978,7 @@ export function converted$array2_u32(data: rs.ByteSlice, out: rs.ByteVec): void const _124: rs.ArraySlice> = rs.arraySliceFrom(array, rs.sliceFrom); rs.idx(_124, 2); const _130: rs.Slice = rs.sliceFrom(c); - rs.replaceIn(rs.sliceView(rs.arraySliceAt(_124, 2)), rs.sliceToArray(_130)); + rs.sliceReplaceAll(rs.arraySliceAt(_124, 2), rs.sliceToArray(_130)); const iter: rs.Iter> = rs.arraySliceIter(rs.arraySliceFrom(array, rs.sliceFrom)); while (true) { const _134: rs.Slice | rs.Done = iter.next(); @@ -2924,7 +2999,7 @@ export function converted$array2_u32(data: rs.ByteSlice, out: rs.ByteVec): void const _173: rs.ArraySlice> = rs.arraySliceFrom(list.items, rs.sliceFrom); rs.idx(_173, 1); const _179: rs.Slice = rs.sliceFrom(c); - rs.replaceIn(rs.sliceView(rs.arraySliceAt(_173, 1)), rs.sliceToArray(_179)); + rs.sliceReplaceAll(rs.arraySliceAt(_173, 1), rs.sliceToArray(_179)); rs.arraySliceSwap(rs.arraySliceFrom(list.items, rs.sliceFrom), 0, 1, undefined); const _184: rs.Vec = list; const _186: rs.u32[] = copy$array_u32(make$conversions_Value_array2_u32(data, 15)); @@ -4742,7 +4817,7 @@ export function lentOne$array2_u32(data: rs.ByteSlice, out: rs.ByteVec): void { rs.byteVecPush(out, s.length & 0xff); rs.idx(s, 0); const _28: rs.u32[] = copy$array_u32(make$conversions_Value_array2_u32(data, 5)); - put$conversions_Value_array2_u32(rs.sliceFrom(rs.replaceIn(rs.sliceView(rs.arraySliceAt(s, 0)), _28)), out); + put$conversions_Value_array2_u32(rs.sliceFrom(rs.sliceReplaceAll(rs.arraySliceAt(s, 0), _28)), out); put$conversions_Value_array2_u32(rs.sliceFrom(a), out); put$conversions_Value_array2_u32(rs.sliceFrom(writeFirst$array2_u32(rs.arraySliceOne(rs.sliceFrom(held.value), 2), make$conversions_Value_array2_u32(data, 7))), out); put$conversions_Value_array2_u32(rs.sliceFrom(held.value), out); diff --git a/ts/fixtures/lang/objects/expected/objects.ts b/ts/fixtures/lang/objects/expected/objects.ts index 9dfda98b8..ebf3f5492 100644 --- a/ts/fixtures/lang/objects/expected/objects.ts +++ b/ts/fixtures/lang/objects/expected/objects.ts @@ -142,8 +142,7 @@ export function swapIn(v: rs.Vec>, with_: rs.Arc): rs.Vec, to: rs.u16): rs.u16[] { const captured = to; return ((): rs.u16[] => { - const _2: rs.u16[] = [captured, rs.u16WrappingAdd(captured, 1)]; - return rs.replaceIn(rs.sliceView(a), _2); + return rs.sliceReplaceAll(a, [captured, rs.u16WrappingAdd(captured, 1)]); })(); } diff --git a/ts/fixtures/lang/pointers/expected/core/option.ts b/ts/fixtures/lang/pointers/expected/core/option.ts index 8f6edbacb..2bdef468d 100644 --- a/ts/fixtures/lang/pointers/expected/core/option.ts +++ b/ts/fixtures/lang/pointers/expected/core/option.ts @@ -69,6 +69,13 @@ export function mapOr$00zno7m(self: Spot.Spot | undefined, default_: Spot.Spot, return f(copy$pointers_Spot(self)); } +export function mapOr$1wlsr3s(self: rs.u8 | undefined, default_: rs.u32, f: (a0: rs.u8) => rs.u32): rs.u32 { + if (self === undefined) { + return default_; + } + return f(self); +} + export function mapOr$173j2gr(self: [rs.u8, rs.Arc] | undefined, default_: rs.u8, f: (a0: [rs.u8, rs.Arc]) => rs.u8): rs.u8 { if (self === undefined) { return default_; diff --git a/ts/fixtures/lang/pointers/expected/lib.ts b/ts/fixtures/lang/pointers/expected/lib.ts index d654e3dda..9de202b84 100644 --- a/ts/fixtures/lang/pointers/expected/lib.ts +++ b/ts/fixtures/lang/pointers/expected/lib.ts @@ -1,7 +1,7 @@ // Generated by rust2-ts. Do not edit. import * as rs from "./rs.ts"; -import { lists, shared, places, unchecked, nested, copies, sentinels, cells, rebound, lapsed, writers, made, segments, uninitRuns, iteratedRuns, besideWritten, waiters, taken, bytes, loaded, reattached, partWritten, aimed, distinct, rawArcs, rawPlaces, arrays, arrayCasts, genericUnions, rawCells, cellWrites, nestedCells, loneBytes } from "./pointers.ts"; +import { lists, shared, places, unchecked, nested, copies, sentinels, cells, rebound, lapsed, writers, made, segments, uninitRuns, iteratedRuns, besideWritten, waiters, taken, bytes, loaded, reattached, partWritten, aimed, distinct, rawArcs, rawPlaces, arrays, arrayCasts, genericUnions, rawCells, cellWrites, nestedCells, loneBytes, arrayParts } from "./pointers.ts"; import type * as Aimed from "./pointers.Aimed.ts"; import * as Bin from "./pointers.Bin.ts"; import type * as ByCall from "./pointers.ByCall.ts"; @@ -323,6 +323,8 @@ export function cases(): rs.Vec<[string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.By nestedCells(data32, out32); }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["pointers::lone_bytes", (_242: rs.u8, data33: rs.ByteSlice, out33: rs.ByteVec): undefined => { loneBytes(data33, out33); + }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["pointers::array_parts", (_243: rs.u8, data34: rs.ByteSlice, out34: rs.ByteVec): undefined => { + arrayParts(data34, out34); }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined]]); } diff --git a/ts/fixtures/lang/pointers/expected/pointers.ts b/ts/fixtures/lang/pointers/expected/pointers.ts index 5e9b3d68b..ea1f870f7 100644 --- a/ts/fixtures/lang/pointers/expected/pointers.ts +++ b/ts/fixtures/lang/pointers/expected/pointers.ts @@ -3,7 +3,7 @@ import * as rs from "./rs.ts"; import { copy$Option_pointers_Pair, copy$Option_tuple2_u16_u8, copy$array_array2_u32, copy$array_ptr_array4_u8, copy$array_tuple2_u8_u8, copy$array_u16, copy$array_u32, copy$array_u8, copy$mem_MaybeUninit_array_u32, copy$mem_MaybeUninit_array_u8, copy$mem_MaybeUninit_tuple2_u8_u8, copy$pointers_Aimed_Cell_u8, copy$pointers_Aimed_array2_u16, copy$pointers_Aimed_array4_u8, copy$pointers_Aimed_pointers_Housed_u8, copy$pointers_Aimed_pointers_Leaning, copy$pointers_Aimed_pointers_Paired, copy$pointers_Aimed_u8, copy$pointers_ByCall, copy$pointers_ByClosure, copy$pointers_ByObject, copy$pointers_Duo, copy$pointers_Either_u32, copy$pointers_Either_u8, copy$pointers_Halves, copy$pointers_Outer, copy$pointers_Pair, copy$pointers_Reentrant, copy$pointers_Spot, copy$pointers_Twin, copy$tuple2_array2_u32_u8, copy$tuple2_u16_u8, copy$tuple2_u32_u32, copy$tuple2_u8_u16, copy$tuple2_u8_u8, drop$pointers_List_String, drop$pointers_List_sync_Arc_u8, drop$tuple2_sync_Arc_pointers_Twin_Rc_pointers_Twin, drop$tuple3_sync_Arc_u32_Rc_pointers_Duo_sync_Arc_unit, drop$tuple4_sync_Arc_pointers_Twin_sync_Arc_pointers_Twin_Rc_pointers_Twin_Rc_pointers_Twin, of$pointers_Bin_pointers_ByObject } from "./lib.ts"; import { then$0bgt67i, then$1a5xgoh, then$0jw3xip } from "./core/bool.ts"; -import { isSomeAnd$1s2u5lz, isSomeAnd$1nosv3e, isSomeAnd$07atiew, unwrapOr$0mkoact as option_unwrapOr$0mkoact, unwrapOr$179xo1w as option_unwrapOr$179xo1w, unwrapOr$1fr498u as option_unwrapOr$1fr498u, map$1cfrse5 as option_map$1cfrse5, mapOr$078vnqn as option_mapOr$078vnqn, mapOr$00zno7m as option_mapOr$00zno7m, mapOr$173j2gr as option_mapOr$173j2gr, filter$0wvwd70 } from "./core/option.ts"; +import { isSomeAnd$1s2u5lz, isSomeAnd$1nosv3e, isSomeAnd$07atiew, unwrapOr$0mkoact as option_unwrapOr$0mkoact, unwrapOr$179xo1w as option_unwrapOr$179xo1w, unwrapOr$1fr498u as option_unwrapOr$1fr498u, map$1cfrse5 as option_map$1cfrse5, mapOr$078vnqn as option_mapOr$078vnqn, mapOr$00zno7m as option_mapOr$00zno7m, mapOr$1wlsr3s as option_mapOr$1wlsr3s, mapOr$173j2gr as option_mapOr$173j2gr, filter$0wvwd70 } from "./core/option.ts"; import type * as Aimed from "./pointers.Aimed.ts"; import * as Bin from "./pointers.Bin.ts"; import type * as ByCall from "./pointers.ByCall.ts"; @@ -1260,12 +1260,12 @@ export function wrapped(n: rs.u8): Uint8Array { const nonNull: rs.ByteSlice = rs.byteSliceFrom(a); const shared: rs.ByteSlice = rs.byteSliceFrom(a); const same: boolean = rs.byteSliceSame(nonNull, shared); - const _10: rs.ByteSlice = rs.byteSliceFrom(rs.byteSliceView(nonNull)); + const _10: rs.ByteSlice = nonNull; _10.data[_10.start + 1] = n ^ 85; - const _15: rs.ByteSlice = rs.byteSliceFrom(rs.byteSliceView(shared)); + const _15: rs.ByteSlice = shared; const viewed: rs.u8 = _15.data[_15.start + 1]; const pointer = nonNull; - const _20: rs.ByteSlice = rs.optionUnwrap(rs.optionMap(pointer === rs.NULL ? undefined : rs.byteSliceView(pointer), rs.byteSliceFrom)); + const _20: rs.ByteSlice = rs.optionUnwrap(pointer === rs.NULL ? undefined : pointer); const asRef: rs.u8 = _20.data[_20.start]; const boxed: rs.ByteSlice = rs.byteSliceFrom(rs.bytes(3).fill(n)); boxed.data[boxed.start + 2] = 9; @@ -3008,7 +3008,7 @@ export function arrayCasts(data: rs.ByteSlice, out: rs.ByteVec): void { rs.byteVecPush(out, rs.byteSliceSame(pair, rs.optionUnwrap(rs.byteSliceGetRange(rest, 0, 2))) ? 1 : 0); rs.byteVecPush(out, rs.byteSliceSame(pair, rs.optionUnwrap(rs.byteSliceGetRange(rest, 0, 2))) ? 1 : 0); } - const _43: rs.ByteSlice = rs.byteSliceFrom(rs.byteSliceView(rs.rawByteSliceOf(rs.byteSliceRange(rs.byteVecSlice(bytes), at)).byteArray(1))); + const _43: rs.ByteSlice = rs.rawByteSliceOf(rs.byteSliceRange(rs.byteVecSlice(bytes), at)).byteArray(1); rs.byteVecPush(out, _43.data[_43.start]); } if (bytes.length >= 3) { @@ -3190,7 +3190,7 @@ export function rawCells(data: rs.ByteSlice, out: rs.ByteVec): void { } _67.data[_67.start + _70] = _67.data[_67.start + _70] ^ n; const _74: rs.u16 = ((n as rs.u16) << 4) & 0xffff; - const _78: rs.Slice = rs.sliceFrom(wide.v); + const _78: rs.Slice = rs.cellArray(wide, rs.sliceFrom); const _81: rs.usize = rs.u8Rem(n, 2) as rs.usize; if (!(_81 < 2)) { rs.panic("index out of bounds: the len is " + 2 + " but the index is " + _81); @@ -3200,7 +3200,7 @@ export function rawCells(data: rs.ByteSlice, out: rs.ByteVec): void { rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(duo.v._1, held.v.n)), undefined, true); rs.iterExtendBytes(out, rs.iterSlice(rs.u16ToBeBytes(pair.v[1]).reverse()), undefined, true); rs.iterExtendBytes(out, rs.iterSlice(rs.byteSliceToArray(rs.byteSliceFrom(bytes.v))), undefined, true); - const _110: rs.Slice = rs.sliceFrom(wide.v); + const _110: rs.Slice = rs.cellArray(wide, rs.sliceFrom); rs.iterExtendBytes(out, rs.iterSlice(rs.u16ToBeBytes(_110.data[_110.start + 1]).reverse()), undefined, true); } else if (_41 === 1) { const p: rs.Place> = rs.place(() => num, (value9) => num = value9); @@ -3315,12 +3315,12 @@ export function rawCells(data: rs.ByteSlice, out: rs.ByteVec): void { _303[1] = _303[1] ^ _302; const _305: rs.ByteSlice = rs.byteSliceFrom(bytes.v); _305.data[_305.start + 1] = _305.data[_305.start + 1] ^ n; - rs.sliceSet(rs.sliceFrom(wide.v), [n as rs.u16, 1]); + rs.sliceSet(rs.cellArray(wide, rs.sliceFrom), [n as rs.u16, 1]); rs.iterExtendBytes(out, rs.iterSlice(rs.u32ToBeBytes(num.v).reverse()), undefined, true); rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(held.v.n, duo.v._0)), undefined, true); rs.iterExtendBytes(out, rs.iterSlice(rs.u16ToBeBytes(pair.v[1]).reverse()), undefined, true); rs.iterExtendBytes(out, rs.iterSlice(rs.byteSliceView(rs.byteSliceFrom(bytes.v))), undefined, true); - const _336: rs.Slice = rs.sliceFrom(wide.v); + const _336: rs.Slice = rs.cellArray(wide, rs.sliceFrom); rs.iterExtendBytes(out, rs.iterSlice(rs.u16ToBeBytes(_336.data[_336.start]).reverse()), undefined, true); const arr: Uint8Array = Uint8Array.of(n, 1, 2); const a: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.byteSliceView(rs.byteSliceFrom(arr)))); @@ -3457,7 +3457,7 @@ export function cellWrites(data: rs.ByteSlice, out: rs.ByteVec): void { const toPair: [rs.u8, rs.u16] = _21[0]; const toDuo: Duo.Duo = _21[1]; const toOwner: Held.Held = _21[2]; - const _30: [rs.ByteSlice, rs.Slice] = [rs.byteSliceFrom(bytes.v), rs.sliceFrom(wide.v)]; + const _30: [rs.ByteSlice, rs.Slice] = [rs.byteSliceFrom(bytes.v), rs.cellArray(wide, rs.sliceFrom)]; const toBytes: rs.ByteSlice = _30[0]; const toWide: rs.Slice = _30[1]; const lent: [rs.u8, rs.u16] = [10, 11]; @@ -3489,8 +3489,8 @@ export function cellWrites(data: rs.ByteSlice, out: rs.ByteVec): void { rs.byteSliceSet(pointer18, _72); rs.iterExtendBytes(out, rs.iterSlice(old19), undefined, true); const _78: rs.u16[] = [n as rs.u16, 2]; - const pointer19 = rs.sliceFrom(wide.v); - const old20 = rs.objectCopy(rs.sliceView(pointer19)); + const pointer19 = rs.cellArray(wide, rs.sliceFrom); + const old20 = rs.sliceCopy(pointer19); rs.sliceSet(pointer19, _78); rs.iterExtendBytes(out, rs.iterSlice(rs.u16ToBeBytes(old20[1]).reverse()), undefined, true); } else if (_46 === 1) { @@ -3504,7 +3504,7 @@ export function cellWrites(data: rs.ByteSlice, out: rs.ByteVec): void { const _98: Uint8Array = Uint8Array.of(n ^ 4, 5); rs.byteSliceSet(rs.byteSliceFrom(bytes.v), _98); const _102: rs.u16[] = [6, ((n as rs.u16) << 4) & 0xffff]; - rs.sliceSet(rs.sliceFrom(wide.v), _102); + rs.sliceSet(rs.cellArray(wide, rs.sliceFrom), _102); } else if (_46 === 2) { const _110: rs.Cell<[rs.u8, rs.u16]> = new rs.Cell([n, 7] as [rs.u8, rs.u16]); const x2 = pair.v; @@ -3542,8 +3542,8 @@ export function cellWrites(data: rs.ByteSlice, out: rs.ByteVec): void { const value5 = Array.from({ length: 2 }, (): rs.u16 => { return 0; }); - const pointer13 = rs.sliceFrom(wide.v); - const old11 = rs.objectCopy(rs.sliceView(pointer13)); + const pointer13 = rs.cellArray(wide, rs.sliceFrom); + const old11 = rs.sliceCopy(pointer13); rs.sliceSet(pointer13, value5); rs.iterExtendBytes(out, rs.iterSlice(rs.u16ToBeBytes(old11[0]).reverse()), undefined, true); } else if (_46 === 4) { @@ -3568,7 +3568,7 @@ export function cellWrites(data: rs.ByteSlice, out: rs.ByteVec): void { const a6: rs.u16 = _29[0]; return [rs.intRotateLeft(_29[1], n as rs.u32, 16, false), a6]; }; - const pointer10 = rs.sliceFrom(wide.v); + const pointer10 = rs.cellArray(wide, rs.sliceFrom); rs.sliceSet(pointer10, _165(rs.sliceToArray(pointer10))); } else if (_46 === 6) { ((c3: rs.Cell): undefined => { @@ -4076,4 +4076,79 @@ export function tripled(b: rs.u8): rs.u8 { return b2[0]; } +/** + * A raw pointer to a `[T; N]` that is part of a slice: lent back as a reference by + * `as_mut`, `NonNull::as_mut`, and `Box::from_raw`, and written whole by `ptr::replace` + * and `ptr::swap`. + */ +export function arrayParts(data: rs.ByteSlice, out: rs.ByteVec): void { + const n: rs.u32 = option_mapOr$1wlsr3s(rs.byteSliceFirst(data), 0, (_2: rs.u8): rs.u32 => { + return _2 as rs.u32; + }); + const words: rs.Vec = rs.iterToVec(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (_22: rs.u8): rs.u32 => { + return _22 as rs.u32; + }), undefined, 4, true); + rs.vecResize(words, rs.max(words.items.length, 6), 9, 4, undefined); + const p: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(rs.sliceFrom(words.items), 1), 0, 2)); + const pointer = p; + const _19: rs.Slice | undefined = pointer === rs.NULL ? undefined : pointer; + if (_19 !== undefined) { + _19.data[_19.start] = n; + } + const _25: rs.u32[] = [rs.u32Add(n, 1), rs.u32Add(n, 2)]; + const pointer2 = p; + const old2 = rs.sliceCopy(pointer2); + rs.sliceSet(pointer2, _25); + rs.iterExtendBytes(out, rs.iterMap(rs.iterSlice(old2), (_24: rs.u32): rs.u8 => { + return _24 & 0xff; + }), undefined, true); + const q: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(rs.sliceFrom(words.items), 3), 0, 2)); + const x = rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(rs.sliceFrom(words.items), 1), 0, 2)); + const y = q; + const old3 = rs.sliceCopy(x); + rs.sliceSet(x, rs.sliceCopy(y)); + rs.sliceSet(y, old3); + const nn: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(rs.sliceFrom(words.items), 2), 0, 2)); + const _54: rs.u32 = rs.u32Add(n, 3); + const _55: rs.Slice = nn; + _55.data[_55.start + 1] = _54; + const raw: rs.Slice = rs.sliceFrom([n, rs.u32Add(n, 1), rs.u32Add(n, 2)]); + raw.data[raw.start + 1] = 7; + rs.iterExtendBytes(out, rs.iterMap(rs.iterSlice(rs.boxArrayFromRaw(raw)), (_210: rs.u32): rs.u8 => { + return _210 & 0xff; + }), undefined, true); + rs.iterExtendBytes(out, rs.iterMap(rs.iterSlice(words.items), (_211: rs.u32): rs.u8 => { + return _211 & 0xff; + }), undefined, true); + const rows: rs.Vec = rs.iterToVec(rs.iterMap(rs.sliceChunks(rs.sliceFrom(words.items), 2), (c: rs.Slice): rs.u32[] => { + rs.idx(c, 0); + const _3: rs.u32 = c.data[c.start]; + const _8: rs.usize = rs.usizeSub(c.length, 1); + rs.idx(c, _8); + return [_3, c.data[c.start + _8]]; + }), undefined, 8, true); + const p3: rs.ArraySlice> = rs.optionUnwrap(rs.arraySliceGetRange(rs.arraySliceRange(rs.arraySliceFrom(rows.items, rs.sliceFrom), 1), 0, 2)); + const pointer3 = p3; + const _90: rs.ArraySlice> | undefined = pointer3 === rs.NULL ? undefined : pointer3; + if (_90 !== undefined) { + const _93: rs.u32 = rs.u32Add(n, 4); + const slice6 = rs.arraySliceAt(_90, 1); + slice6.data[slice6.start] = _93; + } + const pointer4 = p3; + const nn2: rs.ArraySlice> = rs.optionUnwrap(pointer4 === rs.NULL ? undefined : pointer4); + const _100: rs.u32 = rs.u32Add(n, 5); + const slice7 = rs.arraySliceAt(nn2, 0); + slice7.data[slice7.start + 1] = _100; + rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rows.items, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_212: rs.u32): rs.u8 => { + return _212 & 0xff; + }), undefined, true); + const raw2: rs.ArraySlice> = rs.arraySliceFrom([[n, 1], [2, n]], rs.sliceFrom); + const slice8 = rs.arraySliceAt(raw2, 1); + slice8.data[slice8.start + 1] = 8; + rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rs.boxArrayFromRaw(raw2), rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_213: rs.u32): rs.u8 => { + return _213 & 0xff; + }), undefined, true); +} + //# sourceMappingURL=pointers.ts.map diff --git a/ts/fixtures/lang/pointers/src/lib.rs b/ts/fixtures/lang/pointers/src/lib.rs index 985c039c8..52f681baf 100644 --- a/ts/fixtures/lang/pointers/src/lib.rs +++ b/ts/fixtures/lang/pointers/src/lib.rs @@ -59,6 +59,7 @@ fn cases() -> Vec<(&'static str, Case)> { pointers::nested_cells(data, out) }), ("pointers::lone_bytes", |_, data, out| pointers::lone_bytes(data, out)), + ("pointers::array_parts", |_, data, out| pointers::array_parts(data, out)), ] } diff --git a/ts/fixtures/lang/pointers/src/pointers.rs b/ts/fixtures/lang/pointers/src/pointers.rs index 1705c9f96..3b9ebd485 100644 --- a/ts/fixtures/lang/pointers/src/pointers.rs +++ b/ts/fixtures/lang/pointers/src/pointers.rs @@ -5,7 +5,7 @@ //! `UnsafeCell::get` gives; slots of fresh memory written whole before any pointer //! into them is taken, by index or through std's iterators over them; pointers into //! nodes that an `AtomicPtr` and memory hold pointers to; pointers to arrays, compared -//! where they point; a +//! where they point, and to parts of slices as arrays, written through; a //! pointer into a cell that other functions write whole through a `&mut` to it; //! pointers a generic type holds to its parameter, at each form a pointer takes; the //! raw pointers of an `Arc` and an `Rc`, counted and taken back; and unions over a type @@ -3034,3 +3034,43 @@ fn tripled(mut b: u8) -> u8 { s[0] = s[0].wrapping_mul(3); b } + +/// A raw pointer to a `[T; N]` and to a `[[T; N]; M]` that is part of a slice, lent back as +/// a reference by `as_mut` and `NonNull::as_mut`, and the first written whole by +/// `ptr::replace` and `ptr::swap`; and a box of each taken back by `Box::from_raw`. +pub fn array_parts(data: &[u8], out: &mut Vec) { + let n = data.first().map_or(0, |&b| u32::from(b)); + let mut words: Vec = data.iter().map(|&b| u32::from(b)).collect(); + words.resize(words.len().max(6), 9); + let a: &mut [u32; 2] = words[1..].first_chunk_mut().unwrap(); + let p: *mut [u32; 2] = a; + if let Some(a) = unsafe { p.as_mut() } { + a[0] = n; + } + let old = unsafe { ptr::replace(p, [n + 1, n + 2]) }; + out.extend(old.iter().map(|&w| w as u8)); + let q: *mut [u32; 2] = words[3..].first_chunk_mut().unwrap(); + let p: *mut [u32; 2] = words[1..].first_chunk_mut().unwrap(); + unsafe { ptr::swap(p, q) }; + let mut nn = NonNull::from(words[2..].first_chunk_mut::<2>().unwrap()); + unsafe { nn.as_mut()[1] = n + 3 }; + let boxed = Box::new([n, n + 1, n + 2]); + let raw = Box::into_raw(boxed); + unsafe { (*raw)[1] = 7 }; + let back = unsafe { Box::from_raw(raw) }; + out.extend(back.iter().map(|&w| w as u8)); + out.extend(words.iter().map(|&w| w as u8)); + // Of arrays of arrays. + let mut rows: Vec<[u32; 2]> = words.chunks(2).map(|c| [c[0], c[c.len() - 1]]).collect(); + let p: *mut [[u32; 2]; 2] = rows[1..].first_chunk_mut().unwrap(); + if let Some(r) = unsafe { p.as_mut() } { + r[1][0] = n + 4; + } + let mut nn = NonNull::new(p).unwrap(); + unsafe { nn.as_mut()[0][1] = n + 5 }; + out.extend(rows.iter().flatten().map(|&w| w as u8)); + let raw = Box::into_raw(Box::new([[n, 1], [2, n]])); + unsafe { (*raw)[1][1] = 8 }; + let back = unsafe { Box::from_raw(raw) }; + out.extend(back.iter().flatten().map(|&w| w as u8)); +} diff --git a/ts/fixtures/lang/slices/expected/core/option.ts b/ts/fixtures/lang/slices/expected/core/option.ts index 544458dd4..152c7e08f 100644 --- a/ts/fixtures/lang/slices/expected/core/option.ts +++ b/ts/fixtures/lang/slices/expected/core/option.ts @@ -59,6 +59,14 @@ export function map$13tab2s(self: rs.u16[] | undefined, f: (a0: rs.u16[]) => rs. return f(copy$array_u16(self)); } +export function map$0cigbgc(self: rs.Slice | undefined, f: (a0: rs.Slice) => undefined): undefined | rs.None { + if (self === undefined) { + return rs.None; + } + f(self); + return undefined; +} + export function map$0duedp1(self: rs.Slice | undefined, f: (a0: rs.Slice) => rs.u8): rs.u8 | undefined { if (self === undefined) { return undefined; diff --git a/ts/fixtures/lang/slices/expected/lib.ts b/ts/fixtures/lang/slices/expected/lib.ts index 9eec864ab..e894c911a 100644 --- a/ts/fixtures/lang/slices/expected/lib.ts +++ b/ts/fixtures/lang/slices/expected/lib.ts @@ -1,7 +1,7 @@ // Generated by rust2-ts. Do not edit. import * as rs from "./rs.ts"; -import { parts, chunked, subslices, drains, ranges, edits, arrays, arraysMut, arrayForms, arrayIdentity, arraySources, itemWrites } from "./slices.ts"; +import { parts, chunked, subslices, drains, ranges, edits, arrays, arraysMut, arrayForms, arrayIdentity, arraySources, itemWrites, arrayParts } from "./slices.ts"; import type * as Noisy from "./slices.Noisy.ts"; import type * as Pair from "./slices.Pair.ts"; @@ -29,6 +29,10 @@ export function copy$array_u16(v: rs.u16[]): rs.u16[] { return v.slice(); } +export function copy$array_u32(v: rs.u32[]): rs.u32[] { + return v.slice(); +} + export function copy$array_u8(v: Uint8Array): Uint8Array { return v.slice(); } @@ -53,7 +57,7 @@ export function drop$tuple2_Vec_slices_Noisy_Vec_u8(_1: [rs.Vec, rs * their count, so a case added at the end moves no other. */ export function cases(): rs.Vec<[string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined]> { - return rs.vecFrom([["slices::parts", parts as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::drains", drains as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::chunked", chunked as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::subslices", subslices as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::ranges", ranges as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::edits", edits as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::arrays", arrays as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::arrays_mut", arraysMut as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::array_forms", arrayForms as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::array_identity", arrayIdentity as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::array_sources", arraySources as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::item_writes", itemWrites as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined]]); + return rs.vecFrom([["slices::parts", parts as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::drains", drains as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::chunked", chunked as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::subslices", subslices as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::ranges", ranges as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::edits", edits as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::arrays", arrays as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::arrays_mut", arraysMut as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::array_forms", arrayForms as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::array_identity", arrayIdentity as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::array_sources", arraySources as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::item_writes", itemWrites as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["slices::array_parts", arrayParts as (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined]]); } //# sourceMappingURL=lib.ts.map diff --git a/ts/fixtures/lang/slices/expected/slices.ts b/ts/fixtures/lang/slices/expected/slices.ts index d825f8d0a..9e39316b6 100644 --- a/ts/fixtures/lang/slices/expected/slices.ts +++ b/ts/fixtures/lang/slices/expected/slices.ts @@ -1,9 +1,9 @@ // Generated by rust2-ts. Do not edit. import * as rs from "./rs.ts"; -import { copy$Option_array2_u16, copy$Option_array2_u8, copy$array_array2_array2_u8, copy$array_array2_u16, copy$array_array2_u8, copy$array_u16, copy$array_u8, copy$mem_MaybeUninit_array_u8, copy$slices_Pair, drop$tuple2_Vec_slices_Noisy_Vec_u8 } from "./lib.ts"; +import { copy$Option_array2_u16, copy$Option_array2_u8, copy$array_array2_array2_u8, copy$array_array2_u16, copy$array_array2_u8, copy$array_u16, copy$array_u32, copy$array_u8, copy$mem_MaybeUninit_array_u8, copy$slices_Pair, drop$tuple2_Vec_slices_Noisy_Vec_u8 } from "./lib.ts"; import { thenSome$1gvhopg } from "./core/bool.ts"; -import { isSomeAnd$1ouf3e6, unwrapOr$1la41a6 as option_unwrapOr$1la41a6, unwrapOr$1fr498u as option_unwrapOr$1fr498u, unwrapOrDefault$1n9qa5p as option_unwrapOrDefault$1n9qa5p, unwrapOrDefault$0h81s8g as option_unwrapOrDefault$0h81s8g, map$13tab2s as option_map$13tab2s, map$0duedp1 as option_map$0duedp1, map$0q6fk7x as option_map$0q6fk7x, map$1uud0v7 as option_map$1uud0v7, map$1j0y4j0 as option_map$1j0y4j0, map$0vk4zok as option_map$0vk4zok, map$1aqm6sp as option_map$1aqm6sp, map$04ry0e1 as option_map$04ry0e1, mapOr$135q041 as option_mapOr$135q041, mapOr$17z0l8m as option_mapOr$17z0l8m, or$0as8tia as option_or$0as8tia, zip$0wdt346, clone$1omlcob as option_clone$1omlcob } from "./core/option.ts"; +import { isSomeAnd$1ouf3e6, unwrapOr$1la41a6 as option_unwrapOr$1la41a6, unwrapOr$1fr498u as option_unwrapOr$1fr498u, unwrapOrDefault$1n9qa5p as option_unwrapOrDefault$1n9qa5p, unwrapOrDefault$0h81s8g as option_unwrapOrDefault$0h81s8g, map$13tab2s as option_map$13tab2s, map$0cigbgc as option_map$0cigbgc, map$0duedp1 as option_map$0duedp1, map$0q6fk7x as option_map$0q6fk7x, map$1uud0v7 as option_map$1uud0v7, map$1j0y4j0 as option_map$1j0y4j0, map$0vk4zok as option_map$0vk4zok, map$1aqm6sp as option_map$1aqm6sp, map$04ry0e1 as option_map$04ry0e1, mapOr$135q041 as option_mapOr$135q041, mapOr$17z0l8m as option_mapOr$17z0l8m, or$0as8tia as option_or$0as8tia, zip$0wdt346, clone$1omlcob as option_clone$1omlcob } from "./core/option.ts"; import * as Counted from "./slices.Counted.ts"; import type * as Held$item_writes from "./slices.Held$item_writes.ts"; import * as Item from "./slices.Item.ts"; @@ -2424,9 +2424,9 @@ export function arraysMut(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): voi rs.idx(_307[1], _315); const slice10 = rs.arraySliceAt(_307[0], 0); const slice11 = rs.arraySliceAt(_307[1], _315); - rs.sliceSet(slice11, rs.replaceIn(rs.sliceView(slice10), rs.sliceToArray(slice11))); + rs.sliceSet(slice11, rs.sliceReplaceAll(slice10, rs.sliceToArray(slice11))); rs.idx(_253[1], 0); - const old2: rs.u16[] = rs.replaceIn(rs.sliceView(rs.arraySliceAt(_253[1], 0)), [7, 8]); + const old2: rs.u16[] = rs.sliceReplaceAll(rs.arraySliceAt(_253[1], 0), [7, 8]); const _327: rs.usize = rs.usizeSub(n2, 1); rs.idx(_253[1], _327); rs.sliceSet(rs.arraySliceAt(_253[1], _327), copy$array_u16(old2)); @@ -2781,7 +2781,7 @@ export function arraysMut(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): voi const _875: [rs.ArraySlice>, rs.Slice] = rs.sliceAsChunks(rs.sliceFrom(items.items), 2); if (_875[0].length >= 2) { rs.idx(_875[0], 0); - const first7: Item.Item[] = rs.replaceIn(rs.sliceView(rs.arraySliceAt(_875[0], 0)), [new Item.Item(65), new Item.Item(66)], 1); + const first7: Item.Item[] = rs.sliceReplaceAll(rs.arraySliceAt(_875[0], 0), [new Item.Item(65), new Item.Item(66)], 1); flush(out); rs.arraySliceSwap(_875[0], 0, 1, rs.objectCopy); rs.arraySliceBy(_875[0], (arrays) => rs.sliceReverse(arrays), rs.objectCopy); @@ -2804,7 +2804,7 @@ export function arraysMut(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): voi rs.idx(_909[1], 0); const slice6 = rs.arraySliceAt(_909[0], 0); const slice7 = rs.arraySliceAt(_909[1], 0); - rs.sliceSet(slice7, rs.replaceIn(rs.sliceView(slice6), rs.sliceToArray(slice7), 1)); + rs.sliceSet(slice7, rs.sliceReplaceAll(slice6, rs.sliceToArray(slice7), 1)); rs.iterExtendBytes(out, rs.iterMap(rs.arraySliceIter(_875[0]), (c2: rs.Slice): rs.u8 => { return _11(c2); }), undefined, true); @@ -2965,8 +2965,13 @@ export function arrayForms(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): vo const runs2: rs.ArraySlice> = rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => item, (value) => item = value)), 1); rs.idx(runs2, 0); const _354: rs.ByteVec[] = [rs.byteVecFrom(Uint8Array.of(byte(1), byte(2)))]; - rs.iterExtendBytes(out, rs.iterSlice(rs.byteVecView(rs.replaceIn(rs.sliceView(rs.arraySliceAt(runs2, 0)), _354, 1)[0])), undefined, true); - rs.iterExtendBytes(out, rs.iterSlice(rs.byteVecView(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => item, (value2) => item = value2)), 1), rs.objectCopy), [[rs.byteVecFrom(Uint8Array.of(byte(3)))]])[0][0])), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(rs.byteVecView(rs.sliceReplaceAll(rs.arraySliceAt(runs2, 0), _354, 1)[0])), undefined, true); + const _367: rs.Cell = rs.cellOfArraySlice(rs.arraySliceOne(rs.sliceOfPlace(rs.place(() => item, (value2) => item = value2)), 1), rs.objectCopy); + const _371: rs.ByteVec[][] = [[rs.byteVecFrom(Uint8Array.of(byte(3)))]]; + const pointer = rs.cellArray(_367, rs.arraySliceOf(rs.sliceFrom)); + const old4 = rs.arraySliceCopy(pointer, rs.objectCopy); + rs.arraySliceSet(pointer, _371); + rs.iterExtendBytes(out, rs.iterSlice(rs.byteVecView(old4[0][0])), undefined, true); rs.iterExtendBytes(out, rs.iterSlice(rs.byteVecView(item)), undefined, true); } } @@ -3477,4 +3482,137 @@ export function rowLen(cut: rs.usize): rs.u8 { return (cut & 0xff) | 1; } +/** Puts each word's low byte. */ +export function putWords(words: rs.Slice, out: rs.ByteVec): void { + rs.iterExtendBytes(out, rs.iterMap(rs.iterSlice(rs.sliceItems(words)), (_2: rs.u32): rs.u8 => { + return _2 & 0xff; + }), undefined, true); +} + +/** + * A `&mut [T; N]` to part of a slice, of numbers and of strings, written whole: by + * `mem::replace` and `mem::swap`, through a `Cell` and an `UnsafeCell` of it, by std given + * it to write through, and through a raw pointer to it. + */ +export function arrayParts(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { + const words: rs.Vec = rs.iterToVec(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (_2: rs.u8): rs.u32 => { + return _2 as rs.u32; + }), undefined, 4, true); + rs.vecResize(words, rs.max(words.items.length, 6), 9, 4, undefined); + const names: rs.Vec = rs.iterToVec(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (b2: rs.u8): rs.String => { + return rs.fmtToString((f: rs.Formatter) => rs.u8Display(b2, f), 0); + }), undefined, 12, true); + const _17: rs.usize = rs.max(names.items.length, 6); + const _20: rs.String = rs.stringFrom("z"); + rs.vecResize(names, _17, _20, 12, (a0: rs.String): rs.String => { + return rs.stringClone(a0); + }); + const n: rs.u32 = kind as rs.u32; + const _22: rs.u8 = rs.u8Rem(kind, 4); + if (_22 === 0) { + const _26: [rs.Slice, rs.Slice] = rs.sliceSplitAt(rs.sliceFrom(words.items), 1); + putWords(rs.sliceFrom(rs.sliceReplaceAll(rs.optionUnwrap(rs.sliceGetRange(_26[1], 0, 2)), [n, rs.u32Add(n, 1)])), out); + const _40: [rs.Slice, rs.Slice] = rs.optionUnwrap(rs.sliceSplitAtChecked(rs.sliceRange(_26[1], 2), 2)); + const y: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(_40[1], 0, 2)); + rs.sliceSet(y, rs.sliceReplaceAll(_40[0], rs.sliceToArray(y))); + rs.idx(_26[0], 0); + _26[0].data[_26[0].start] = n; + const s: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(rs.sliceFrom(names.items), 1), 0, 2)); + const _57: rs.String[] = [rs.stringFrom("a"), rs.stringFrom("b")]; + rs.iterExtendBytes(out, rs.iterMap(rs.iterMap(rs.iterSlice(rs.sliceReplaceAll(s, _57, 1)), (a02: rs.String): rs.usize => { + return a02.len; + }), (l: rs.usize): rs.u8 => { + return l & 0xff; + }), undefined, true); + } else if (_22 === 1) { + const cell: rs.Cell = rs.cellOfSlice(rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(rs.sliceFrom(words.items), 1), 0, 2))); + const _73: rs.u32[] = [n, rs.u32Add(n, 2)]; + const pointer = rs.cellArray(cell, rs.sliceFrom); + const old5 = rs.sliceCopy(pointer); + rs.sliceSet(pointer, _73); + putWords(rs.sliceFrom(old5), out); + putWords(rs.sliceFrom(copy$array_u32(cell.v)), out); + const _84: rs.u32[] = [rs.u32Add(n, 3), rs.u32Add(n, 4)]; + rs.sliceSet(rs.cellArray(cell, rs.sliceFrom), _84); + const p: rs.Slice = rs.cellArray(cell, rs.sliceFrom); + p.data[p.start + 1] = rs.u32Add(n, 5); + const pointer2 = rs.cellArray(cell, rs.sliceFrom); + rs.sliceSet(pointer2, ((_24: rs.u32[]): rs.u32[] => { + return [_24[1], _24[0]]; + })(rs.sliceToArray(pointer2))); + const value2 = Array.from({ length: 2 }, (): rs.u32 => { + return 0; + }); + const pointer3 = rs.cellArray(cell, rs.sliceFrom); + const old6 = rs.sliceCopy(pointer3); + rs.sliceSet(pointer3, value2); + putWords(rs.sliceFrom(old6), out); + const rows: rs.Vec = rs.iterToVec(rs.iterMap(rs.sliceChunks(rs.sliceFrom(words.items), 2), (c: rs.Slice): rs.u32[] => { + rs.idx(c, 0); + const _35: rs.u32 = c.data[c.start]; + const _8: rs.usize = rs.usizeSub(c.length, 1); + rs.idx(c, _8); + return [_35, c.data[c.start + _8]]; + }), undefined, 8, true); + const cell2: rs.Cell = rs.cellOfArraySlice(rs.optionUnwrap(rs.arraySliceGetRange(rs.arraySliceRange(rs.arraySliceFrom(rows.items, rs.sliceFrom), 1), 0, 2))); + const p2: rs.ArraySlice> = rs.cellArray(cell2, rs.arraySliceOf(rs.sliceFrom)); + const _110: rs.u32 = rs.u32Add(n, 6); + const slice5 = rs.arraySliceAt(p2, 0); + slice5.data[slice5.start + 1] = _110; + const _116: rs.u32[][] = [[n, rs.u32Add(n, 7)], [rs.u32Add(n, 8), n]]; + const pointer4 = rs.cellArray(cell2, rs.arraySliceOf(rs.sliceFrom)); + const old7 = rs.arraySliceCopy(pointer4); + rs.arraySliceSet(pointer4, _116); + rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(old7, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_25: rs.u32): rs.u8 => { + return _25 & 0xff; + }), undefined, true); + const cell3: rs.Cell = rs.cellOfArraySlice(rs.optionUnwrap(rs.arraySliceGetRange(rs.arraySliceRange(rs.arraySliceFrom(rows.items, rs.sliceFrom), 0, 2), 0, 2))); + const _135: rs.u32 = rs.u32Add(n, 9); + const slice7 = rs.arraySliceAt(rs.cellArray(cell3, rs.arraySliceOf(rs.sliceFrom)), 1); + slice7.data[slice7.start] = _135; + const _142: rs.u32 = rs.u32Add(n, 10); + const slice8 = rs.arraySliceAt(rs.cellArray(cell3, rs.arraySliceOf(rs.sliceFrom)), 0); + slice8.data[slice8.start] = _142; + rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rows.items, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_28: rs.u32): rs.u8 => { + return _28 & 0xff; + }), undefined, true); + } else if (_22 === 2) { + const cell4: rs.Cell = rs.cellOfSlice(rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(rs.sliceFrom(words.items), 2), 0, 2))); + const _160: rs.Slice = rs.cellArray(cell4, rs.sliceFrom); + _160.data[_160.start] = n; + const _164: rs.u32 = rs.u32Add(n, 1); + const _165: rs.Slice = rs.cellArray(cell4, rs.sliceFrom); + _165.data[_165.start + 1] = _164; + } else { + const _170: [rs.Slice, rs.Slice] = rs.optionUnwrap(rs.sliceSplitAtChecked(rs.sliceRange(rs.sliceFrom(words.items), 1), 2)); + rs.idx(_170[1], 0); + _170[1].data[_170[1].start] = n; + let kept: rs.Slice | undefined = _170[0]; + const _180: rs.Place> | undefined = kept === undefined ? undefined : rs.place(() => kept as rs.Slice, (value) => kept = value); + if (_180 !== undefined) { + const _184: rs.u32 = rs.u32Add(n, 1); + const _223: rs.Slice = _180.v; + _223.data[_223.start] = _184; + } + option_map$0cigbgc(kept, (a4: rs.Slice): undefined => { + a4.data[a4.start + 1] = rs.u32Add(n, 2); + }); + const v: rs.Vec> = new rs.Vec(); + const _194: [rs.Slice, rs.Slice] = rs.sliceSplitAt(rs.sliceFrom(words.items), 2); + const _199: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(_194[1], 0, 2)); + v.items.push(_199); + const _203: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(_194[0], 0, 2)); + v.items.push(_203); + for (const _208 of v.items) { + rs.sliceSwap(_208, 0, 1); + } + } + putWords(rs.sliceFrom(words.items), out); + rs.iterExtendBytes(out, rs.iterMap(rs.iterMap(rs.iterSlice(names.items), (a03: rs.String): rs.usize => { + return a03.len; + }), (l2: rs.usize): rs.u8 => { + return l2 & 0xff; + }), undefined, true); +} + //# sourceMappingURL=slices.ts.map diff --git a/ts/fixtures/lang/slices/src/lib.rs b/ts/fixtures/lang/slices/src/lib.rs index 630056474..3f713cd77 100644 --- a/ts/fixtures/lang/slices/src/lib.rs +++ b/ts/fixtures/lang/slices/src/lib.rs @@ -28,5 +28,6 @@ fn cases() -> Vec<(&'static str, Case)> { ("slices::array_identity", slices::array_identity), ("slices::array_sources", slices::array_sources), ("slices::item_writes", slices::item_writes), + ("slices::array_parts", slices::array_parts), ] } diff --git a/ts/fixtures/lang/slices/src/slices.rs b/ts/fixtures/lang/slices/src/slices.rs index e4b75aedc..ba7e753b3 100644 --- a/ts/fixtures/lang/slices/src/slices.rs +++ b/ts/fixtures/lang/slices/src/slices.rs @@ -7,7 +7,8 @@ //! place, of values that log as they are cloned and drop; and a slice's runs as arrays, //! and a `Vec` cloned from a slice; and slices of arrays in each form they take: constants, //! defaults, an `Option`'s, a `Cow`'s, a generic struct's, clones, and runs of references -//! and of wrapped arrays. +//! and of wrapped arrays; and a mutable reference to part of a slice as an array, written +//! whole. use std::cell::RefCell; @@ -1805,3 +1806,91 @@ pub fn item_writes(kind: u8, data: &[u8], out: &mut Vec) { fn row_len(cut: usize) -> u8 { cut as u8 | 1 } + +/// Puts each word's low byte. +fn put_words(words: &[u32], out: &mut Vec) { + out.extend(words.iter().map(|&w| w as u8)); +} + +/// A `&mut [T; N]` to part of a slice, of numbers, of strings, and of arrays, written whole: +/// by `mem::replace` and `mem::swap`, and through a `Cell` and an `UnsafeCell` of it, each +/// way a cell reads, writes, and points at it; a cell of arrays pointed at before a write; +/// and one std holds in an `Option` and a `Vec` and writes through. +pub fn array_parts(kind: u8, data: &[u8], out: &mut Vec) { + use std::cell::{Cell, UnsafeCell}; + let mut words: Vec = data.iter().map(|&b| u32::from(b)).collect(); + words.resize(words.len().max(6), 9); + let mut names: Vec = data.iter().map(|b| b.to_string()).collect(); + names.resize(names.len().max(6), String::from("z")); + let mut rows: Vec<[u32; 2]> = words.chunks(2).map(|c| [c[0], c[c.len() - 1]]).collect(); + let n = u32::from(kind); + match kind % 4 { + 0 => { + let (head, rest) = words.split_at_mut(1); + let a: &mut [u32; 2] = rest.first_chunk_mut().unwrap(); + let old = std::mem::replace(a, [n, n + 1]); + put_words(&old, out); + let (x, y) = rest[2..].split_first_chunk_mut::<2>().unwrap(); + let y: &mut [u32; 2] = y.first_chunk_mut().unwrap(); + std::mem::swap(x, y); + head[0] = n; + let s: &mut [String; 2] = names[1..].first_chunk_mut().unwrap(); + let old = std::mem::replace(s, [String::from("a"), String::from("b")]); + out.extend(old.iter().map(String::len).map(|l| l as u8)); + } + 1 => { + let a: &mut [u32; 2] = words[1..].first_chunk_mut().unwrap(); + let cell = Cell::from_mut(a); + let old = cell.replace([n, n + 2]); + put_words(&old, out); + put_words(&cell.get(), out); + cell.set([n + 3, n + 4]); + let p = cell.as_ptr(); + unsafe { (*p)[1] = n + 5 }; + cell.update(|[x, y]| [y, x]); + put_words(&cell.take(), out); + let s: &mut [String; 2] = names[2..].first_chunk_mut().unwrap(); + let old = Cell::from_mut(s).replace([String::from("abc"), String::new()]); + out.extend(old.iter().map(String::len).map(|l| l as u8)); + let a: &mut [u32; 2] = words[2..].first_chunk_mut().unwrap(); + let cell = UnsafeCell::from_mut(a); + unsafe { (*cell.get())[0] = n + 6 }; + cell.get_mut()[1] = n + 7; + } + 2 => { + let r: &mut [[u32; 2]; 2] = rows[1..].first_chunk_mut().unwrap(); + let cell = Cell::from_mut(r); + let p = cell.as_ptr(); + unsafe { (*p)[0][1] = n + 6 }; + let old = cell.replace([[n, n + 7], [n + 8, n]]); + out.extend(old.iter().flatten().map(|&w| w as u8)); + let r: &mut [[u32; 2]; 2] = rows[..2].first_chunk_mut().unwrap(); + let cell = UnsafeCell::from_mut(r); + unsafe { (*cell.get())[1][0] = n + 9 }; + cell.get_mut()[0][0] = n + 10; + let held = Cell::new([[n, 1], [2, n]]); + let p = held.as_ptr(); + held.set([[3, n], [n, 4]]); + out.extend(unsafe { *p }.iter().flatten().map(|&w| w as u8)); + } + _ => { + let (a, b) = words[1..].split_first_chunk_mut::<2>().unwrap(); + b[0] = n; + let mut kept = Some(a); + if let Some(a) = kept.as_mut() { + a[0] = n + 1; + } + kept.map(|a| a[1] = n + 2); + let mut v: Vec<&mut [u32; 2]> = Vec::new(); + let (d, rest) = words.split_at_mut(2); + v.push(rest.first_chunk_mut().unwrap()); + v.push(d.first_chunk_mut().unwrap()); + for a in v { + a.swap(0, 1); + } + } + } + put_words(&words, out); + out.extend(names.iter().map(String::len).map(|l| l as u8)); + out.extend(rows.iter().flatten().map(|&w| w as u8)); +} diff --git a/ts/fixtures/reject/census.txt b/ts/fixtures/reject/census.txt index 38de56363..b4da095f8 100644 --- a/ts/fixtures/reject/census.txt +++ b/ts/fixtures/reject/census.txt @@ -10,9 +10,8 @@ fixtures/reject/src/alloc.rs:bytes_as_values+3:3: a byte of memory from `alloc`, fixtures/reject/src/alloc.rs:bytes_as_values+4:15: a cast from a pointer to `u8` to one to `u32`, which reads the bytes of one type as another fixtures/reject/src/alloc.rs:bytes_as_values+5:16: a cast from a pointer to `u8` to one to `pointers::Halves`, which reads the bytes of one type as another fixtures/reject/src/alloc.rs:bytes_as_values+7:15: a cast from a pointer to `u32` to one to `u8`, which reads the bytes of one type as another -fixtures/reject/src/alloc.rs:cell_of_arrays+1:10: `UnsafeCell::from_mut` of `[[u16; 2]; 2]`, an array of arrays, which a cell of it reads a copy of, so a write through its pointer would land in the copy -fixtures/reject/src/alloc.rs:cell_of_arrays+7:4: `Cell::swap` of `[[u16; 2]; 2]`, an array, whose cells may partially overlap, which Rust panics on -fixtures/reject/src/alloc.rs:cell_of_arrays+9:4: `Cell::swap` of `[u32; 2]`, an array, whose cells may partially overlap, which Rust panics on +fixtures/reject/src/alloc.rs:cell_of_arrays+5:4: `Cell::swap` of `[[u16; 2]; 2]`, an array, whose cells may partially overlap, which Rust panics on +fixtures/reject/src/alloc.rs:cell_of_arrays+7:4: `Cell::swap` of `[u32; 2]`, an array, whose cells may partially overlap, which Rust panics on fixtures/reject/src/alloc.rs:cell_of_objects+1:10: `UnsafeCell::from_mut` of `std::vec::Vec`, an object a whole write through it changes in place, so a value read out before would change too or be a copy at another address fixtures/reject/src/alloc.rs:cell_of_objects+2:10: `UnsafeCell::from_mut` of `std::string::String`, an object a whole write through it changes in place, so a value read out before would change too or be a copy at another address fixtures/reject/src/alloc.rs:cell_of_objects+3:10: `UnsafeCell::from_mut` of `std::pin::Pin>`, an object a whole write through it changes in place, so a value read out before would change too or be a copy at another address @@ -33,6 +32,9 @@ fixtures/reject/src/alloc.rs:cell_raw_unknown+9:13: `UnsafeCell::raw_get` of a p fixtures/reject/src/alloc.rs:pinned_lent+1:32: `UnsafeCell::get_mut` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:pinned_lent+2:43: `UnsafeCell::as_mut_unchecked` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:reinterpreted+1:27: a cast from a pointer to `u32` to one to `u8`, which reads the bytes of one type as another +fixtures/reject/src/alloc.rs:uninit_array_slice+1:42: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_slice+2:44: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_slice+2:52: an offset of a pointer to `std::mem::MaybeUninit<[u32; 2]>`, which JS keeps as an object that knows no array it is in fixtures/reject/src/alloc.rs:uninit_cell_lent+2:17: `MaybeUninit::assume_init_mut` of `std::cell::UnsafeCell`, whose mutable reference is the object, but the uninitialized value's is the place it is kept in fixtures/reject/src/alloc.rs:vec_pointer+1:10: a raw pointer to `std::vec::Vec` behind a reference, which is the object and not where it is kept fixtures/reject/src/alloc.rs:wrapped_cells+8:19: a whole write of `std::mem::MaybeUninit<(std::cell::UnsafeCell, u32)>`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds diff --git a/ts/fixtures/reject/expected.txt b/ts/fixtures/reject/expected.txt index a8d466b37..02b3a91fb 100644 --- a/ts/fixtures/reject/expected.txt +++ b/ts/fixtures/reject/expected.txt @@ -14,9 +14,8 @@ fixtures/reject/src/alloc.rs:bytes_as_values+3:3: a byte of memory from `alloc`, fixtures/reject/src/alloc.rs:bytes_as_values+4:15: a cast from a pointer to `u8` to one to `u32`, which reads the bytes of one type as another fixtures/reject/src/alloc.rs:bytes_as_values+5:16: a cast from a pointer to `u8` to one to `pointers::Halves`, which reads the bytes of one type as another fixtures/reject/src/alloc.rs:bytes_as_values+7:15: a cast from a pointer to `u32` to one to `u8`, which reads the bytes of one type as another -fixtures/reject/src/alloc.rs:cell_of_arrays+1:10: `UnsafeCell::from_mut` of `[[u16; 2]; 2]`, an array of arrays, which a cell of it reads a copy of, so a write through its pointer would land in the copy -fixtures/reject/src/alloc.rs:cell_of_arrays+7:4: `Cell::swap` of `[[u16; 2]; 2]`, an array, whose cells may partially overlap, which Rust panics on -fixtures/reject/src/alloc.rs:cell_of_arrays+9:4: `Cell::swap` of `[u32; 2]`, an array, whose cells may partially overlap, which Rust panics on +fixtures/reject/src/alloc.rs:cell_of_arrays+5:4: `Cell::swap` of `[[u16; 2]; 2]`, an array, whose cells may partially overlap, which Rust panics on +fixtures/reject/src/alloc.rs:cell_of_arrays+7:4: `Cell::swap` of `[u32; 2]`, an array, whose cells may partially overlap, which Rust panics on fixtures/reject/src/alloc.rs:cell_of_objects+1:10: `UnsafeCell::from_mut` of `std::vec::Vec`, an object a whole write through it changes in place, so a value read out before would change too or be a copy at another address fixtures/reject/src/alloc.rs:cell_of_objects+2:10: `UnsafeCell::from_mut` of `std::string::String`, an object a whole write through it changes in place, so a value read out before would change too or be a copy at another address fixtures/reject/src/alloc.rs:cell_of_objects+3:10: `UnsafeCell::from_mut` of `std::pin::Pin>`, an object a whole write through it changes in place, so a value read out before would change too or be a copy at another address @@ -37,6 +36,9 @@ fixtures/reject/src/alloc.rs:cell_raw_unknown+9:13: `UnsafeCell::raw_get` of a p fixtures/reject/src/alloc.rs:pinned_lent+1:32: `UnsafeCell::get_mut` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:pinned_lent+2:43: `UnsafeCell::as_mut_unchecked` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:reinterpreted+1:27: a cast from a pointer to `u32` to one to `u8`, which reads the bytes of one type as another +fixtures/reject/src/alloc.rs:uninit_array_slice+1:42: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_slice+2:44: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_slice+2:52: an offset of a pointer to `std::mem::MaybeUninit<[u32; 2]>`, which JS keeps as an object that knows no array it is in fixtures/reject/src/alloc.rs:uninit_cell_lent+2:17: `MaybeUninit::assume_init_mut` of `std::cell::UnsafeCell`, whose mutable reference is the object, but the uninitialized value's is the place it is kept in fixtures/reject/src/alloc.rs:vec_pointer+1:10: a raw pointer to `std::vec::Vec` behind a reference, which is the object and not where it is kept fixtures/reject/src/alloc.rs:wrapped_cells+8:19: a whole write of `std::mem::MaybeUninit<(std::cell::UnsafeCell, u32)>`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds diff --git a/ts/fixtures/reject/src/alloc.rs b/ts/fixtures/reject/src/alloc.rs index d3ec2b5ea..dd8887296 100644 --- a/ts/fixtures/reject/src/alloc.rs +++ b/ts/fixtures/reject/src/alloc.rs @@ -134,11 +134,8 @@ pub fn wrapped_cells(n: u32) -> u32 { } } -/// An `UnsafeCell::from_mut` of arrays of arrays, which a cell may read a copy of, and /// `Cell::swap`s of arrays, whose cells may partially overlap. -pub fn cell_of_arrays(a: &mut [[u16; 2]; 2]) -> u16 { - let c = std::cell::UnsafeCell::from_mut(a); - let first = unsafe { (*c.get())[0][0] }; +pub fn cell_of_arrays() -> u16 { let (x, y) = ( std::cell::Cell::new([[1u16, 2]; 2]), std::cell::Cell::new([[3u16, 4]; 2]), @@ -146,7 +143,7 @@ pub fn cell_of_arrays(a: &mut [[u16; 2]; 2]) -> u16 { x.swap(&y); let (v, w) = (std::cell::Cell::new([5u32, 6]), std::cell::Cell::new([7u32, 8])); v.swap(&w); - first ^ x.into_inner()[0][0] ^ v.into_inner()[0] as u16 + x.into_inner()[0][0] ^ v.into_inner()[0] as u16 } /// A `get_mut` and an `as_mut_unchecked` of a cell of a pinned `Box`, whose old value diff --git a/ts/fixtures/task/expected/drops/called.ts b/ts/fixtures/task/expected/drops/called.ts index 96d79fb7c..b4957ec1a 100644 --- a/ts/fixtures/task/expected/drops/called.ts +++ b/ts/fixtures/task/expected/drops/called.ts @@ -447,7 +447,7 @@ export function called(log: Log.Log, id: rs.u32, arg: rs.u8): void { Log.note(log, rs.fmtFormat(["pair ", args76[0], " ", args76[1]])); return copy$array_u32(p); }; - const pointer = rs.sliceFrom(pair.v); + const pointer = rs.cellArray(pair, rs.sliceFrom); rs.sliceSet(pointer, _510(rs.sliceToArray(pointer))); const part4 = rs.sliceFrom(copy$array_u32(pair.v)); Log.note(log, rs.fmtFormat(["paired ", (f: rs.Formatter) => rs.fmtList(rs.sliceItems(part4), f, rs.u32Debug)])); diff --git a/ts/runtime/rs.ts b/ts/runtime/rs.ts index 6f937c40c..4217d00d1 100644 --- a/ts/runtime/rs.ts +++ b/ts/runtime/rs.ts @@ -266,11 +266,10 @@ export type CowOf = Cow | ByteCow | Cow>; export function arrayAsPtr(s: { [i: number]: T }, index = 0): Place { if (s === NULL) return NULL; if (s === DANGLING) return DANGLING; - const view = (s as { [VIEW]?: View })[VIEW]; - const [array, at] = view ? [view.s, view.start + index] : [s, index]; + const array = roomItems(s) ?? s; // Null's is `null`, which `??` would pass over. const from = EMPTY.get(array) as Place | undefined; - return from !== undefined ? from : new AtIndex(array, at); + return from !== undefined ? from : new AtIndex(array, index); } /** The pointer to element `index` of `s`, or `s` if it is null or dangling, as `arrayAsPtr`'s. */ @@ -419,9 +418,9 @@ class Lone implements ProxyHandler { */ function elemOf(p: Place): AtIndex { if (p instanceof AtIndex) { - // A pointer into a mutable part of an array points into the array. - const view = (p.array as { [VIEW]?: View })[VIEW]; - return view ? new AtIndex(view.s, view.start + p.index) : p; + // A pointer into a `Vec`'s storage and its room points into its items. + const items = roomItems(p.array); + return items ? new AtIndex(items, p.index) : p; } if (p === NULL || p === DANGLING) return new AtIndex([] as T[], 0); let lone = LONE.get(p) as T[] | undefined; @@ -694,14 +693,14 @@ export function replaceIn(p: T, value: T, depth = 0): T { /** * A copy of the object `p`, one object deep: its fields, its bytes, or its items for a JS - * array. Its items, and theirs to `depth` levels of arrays, are objects - * a write may land in, as a `sliceIn`'s, which a view of one copies too. + * array. Its items, and theirs to `depth` levels of arrays, are copied where a write may land + * in them, as in a `sliceIn`'s. */ export function objectCopy(p: T, depth = 0): T { if (ArrayBuffer.isView(p)) return (p as unknown as Uint8Array).slice() as T; if (Array.isArray(p)) { const old: unknown[] = p.slice(); - if (depth > 0 && writesIn(p)) for (let i = 0; i < old.length; i++) old[i] = objectCopy(old[i] as object, depth - 1); + if (depth > 0 && ONE.has(p)) for (let i = 0; i < old.length; i++) old[i] = objectCopy(old[i] as object, depth - 1); return old as T; } if (moved(p)) return p.$move(); @@ -898,15 +897,42 @@ export function sliceSet(s: Slice, items: ArrayLike): void { for (let i = 0; i < s.length; i++) s.data[s.start + i] = items[i]; } +/** + * What a `&mut [T; N]`, `s`, points at, as an array of its own: its elements, and theirs to + * `depth` levels of arrays, copied where a write may land in them, as `objectCopy` copies. + */ +export function sliceCopy(s: Slice, depth = 0): T[] { + const old = s.data.slice(s.start, s.start + s.length); + if (depth > 0 && ONE.has(s.data)) for (let i = 0; i < old.length; i++) old[i] = objectCopy(old[i] as object, depth - 1) as T; + return old; +} + +/** `mem::replace` of what a `&mut [T; N]`, `s`, points at: a copy of it, as `sliceCopy` makes, then `items` written where `s` holds them. */ +export function sliceReplaceAll(s: Slice, items: ArrayLike, depth = 0): T[] { + const old = sliceCopy(s, depth); + sliceSet(s, items); + return old; +} + +/** + * `Box::from_raw` of a `*mut [T; N]`, `s`, the slice of its elements or of its arrays: the + * array `Box::into_raw` made all of it of, since a box owns all of its allocation. + */ +export function boxArrayFromRaw(s: Slice): T[]; +export function boxArrayFromRaw(s: ArraySlice): LentArray[]; +export function boxArrayFromRaw(s: Slice | ArraySlice): unknown[] { + const items = s instanceof Slice ? s.data : s instanceof ArraySlice ? s.items : undefined; + const all = items !== undefined && s.start === 0 && s.length === items.length; + return precondition(all ? (items as unknown[]) : undefined, "Box::from_raw requires a pointer Box::into_raw gave"); +} + /** * Whether pointers to a `[T; N]`, slices of its elements, point at the same place: the same - * element of the same array, through any `arrayView` of part of it, or both null. + * element of the same array, through a `Vec`'s view of its storage and room, or both null. */ export function sliceSame(a: Slice, b: Slice): boolean { if (!(a instanceof Slice && b instanceof Slice)) return a === b; - const [x, y] = [(a.data as { [VIEW]?: View })[VIEW], (b.data as { [VIEW]?: View })[VIEW]]; - const [xs, ys] = [x ? x.s : a.data, y ? y.s : b.data]; - return xs === ys && (x ? x.start : 0) + a.start === (y ? y.start : 0) + b.start; + return (roomItems(a.data) ?? a.data) === (roomItems(b.data) ?? b.data) && a.start === b.start; } /** A bounds-checked index into a slice. */ @@ -938,28 +964,6 @@ export function slicePart(s: Slice, start: number, end: number = s.length) return new Slice(s.data, s.start + start, end - start); } -/** - * Elements `start` to `end` of `s` as a JS array whose every element is `s`'s, read and - * written where it is, as a JS array has no views of its own: the `[T; N]` a `&mut` to part - * of an array lends where what takes it writes a JS array. Its own array, holes of the same - * length, answers for the rest, such as `length` and the methods. A view of a view reads - * the array beneath both. - */ -function arrayView(s: T[], start: number, end: number): T[] { - const outer = (s as { [VIEW]?: View })[VIEW]; - const view = outer ? outer.part(start, end - start) : new View(s, start, end - start); - return new Proxy(new Array(end - start), view); -} - -/** - * The `[T; N]` a `&mut [T; N]`, `s`, points at, as a JS array read and written where the - * slice holds it, as a `ByteSlice`'s `Uint8Array` view is: the array itself where the slice - * is all of it, and else a view of its part. - */ -export function sliceView(s: Slice): T[] { - return s.start === 0 && s.length === s.data.length ? s.data : arrayView(s.data, s.start, s.start + s.length); -} - /** `Option::as_slice` of `o`, whose `None` is `none`: its payload, if any, as `slice::from_ref` makes a slice of one. */ export function optionAsSlice(o: T | undefined): Slice; export function optionAsSlice(o: T | None, none: None): Slice; @@ -1039,22 +1043,14 @@ export function byteMirrorFlush(m: ByteMirror | undefined): void { if (byte !== m.last) m.p.v = m.last = byte; } -/** - * Whether a whole write of an element of `s`, an array a slice holds, may land in the object - * there, as one of `sliceIn`'s does, or of a place in one, which only `sliceOfPlace`'s can be. - */ -function writesIn(s: object): boolean { - const view = (s as { [VIEW]?: View })[VIEW]; - return ONE.has(view !== undefined ? view.s : s); -} - /** * `mem::replace` of element `i` of `s`, the array a slice of objects holds them in: what * it held, as an object of its own, copied to `depth` as `objectCopy` copies, where the * write lands in it. */ export function sliceReplace(s: T[], i: number, value: T, depth = 0): T { - if (writesIn(s)) return replaceIn(s[i], value, depth); + // A whole write of an element of an array of one `sliceIn` or `sliceOfPlace` made lands in the object there. + if (ONE.has(s)) return replaceIn(s[i], value, depth); const old = s[i]; s[i] = value; return old; @@ -1066,75 +1062,10 @@ export function sliceReplace(s: T[], i: number, value: T, dept * as `sliceReplace` copies, as the other's slot would otherwise take that object itself. */ export function sliceSwapAcross(a: T[], i: number, b: T[], j: number, depth = 0): void { - if (writesIn(b)) [a, i, b, j] = [b, j, a, i]; + if (ONE.has(b)) [a, i, b, j] = [b, j, a, i]; b[j] = sliceReplace(a, i, b[j], depth); } -/** What an `arrayView` answers to its own `View` by. */ -const VIEW = /* @__PURE__ */ Symbol("view"); - -/** An `arrayView`'s traps: of `length` elements of `s` from `start`. */ -class View implements ProxyHandler { - s: { [index: number]: T }; - start: number; - readonly length: number; - - constructor(s: { [index: number]: T }, start: number, length: number) { - this.s = s; - this.start = start; - this.length = length; - } - - /** The traps of a view of `length` of these elements from `start`. */ - part(start: number, length: number): View { - return new View(this.s, this.start + start, length); - } - - /** Element `i` of `s`. */ - item(i: number): T { - return this.s[i]; - } - - /** A write of element `i` of `s`. */ - put(i: number, value: T): void { - this.s[i] = value; - } - - /** Where in `s` the element `key` names is, or -1 if it names none. */ - at(key: string | symbol): number { - if (typeof key !== "string") return -1; - const i = Number(key); - return Number.isInteger(i) && i >= 0 && i < this.length && String(i) === key ? this.start + i : -1; - } - - get(target: T[], key: string | symbol): unknown { - if (key === VIEW) return this; - const i = this.at(key); - return i < 0 ? Reflect.get(target, key) : this.item(i); - } - - set(target: T[], key: string | symbol, value: T): boolean { - const i = this.at(key); - if (i < 0) return Reflect.set(target, key, value); - this.put(i, value); - return true; - } - - has(target: T[], key: string | symbol): boolean { - return this.at(key) >= 0 || Reflect.has(target, key); - } - - ownKeys(target: T[]): (string | symbol)[] { - return [...Array.from({ length: this.length }, (_, i) => String(i)), ...Reflect.ownKeys(target)]; - } - - getOwnPropertyDescriptor(target: T[], key: string | symbol): PropertyDescriptor | undefined { - const i = this.at(key); - if (i < 0) return Reflect.getOwnPropertyDescriptor(target, key); - return { value: this.item(i), writable: true, enumerable: true, configurable: true }; - } -} - /** * `op` of the elements of `s`, which it reads before writes that may overwrite them, as a * JS array: the storage itself where `s` is all of it, or else a copy, written back after. @@ -2785,32 +2716,70 @@ export function roomPast(array: object, end: number): Room | undefined { return room; } -/** The traps of a view of a `Vec`'s storage, its items and then its room, from `start`. */ -class RoomView extends View { +/** What a `Vec`'s view of its storage and room answers to its own traps by. */ +const VIEW = /* @__PURE__ */ Symbol("view"); + +/** The items of the `Vec` whose storage and room `s` is a view of, if it is one. */ +function roomItems(s: object): { [index: number]: T } | undefined { + return (s as { [VIEW]?: RoomView })[VIEW]?.s; +} + +/** The traps of a view of the first `length` elements of a `Vec`'s storage: its items, `s`, and then its room. */ +class RoomView implements ProxyHandler { readonly room: Room; + readonly s: T[]; + readonly length: number; - constructor(room: Room, items: T[], start: number, length: number) { - super(items, start, length); + constructor(room: Room, s: T[], length: number) { this.room = room; + this.s = s; + this.length = length; } - override part(start: number, length: number): RoomView { - return new RoomView(this.room, this.s as T[], this.start + start, length); + /** Element `i`, of the items or the room. */ + item(i: number): T { + return i < this.s.length ? this.s[i] : this.room.get(i); } - override item(i: number): T { - return i < (this.s as T[]).length ? this.s[i] : this.room.get(i); + /** Where the element `key` names is, or -1 if it names none. */ + at(key: string | symbol): number { + if (typeof key !== "string") return -1; + const i = Number(key); + return Number.isInteger(i) && i >= 0 && i < this.length && String(i) === key ? i : -1; } - override put(i: number, value: T): void { - if (i < (this.s as T[]).length) this.s[i] = value; + get(target: T[], key: string | symbol): unknown { + if (key === VIEW) return this; + const i = this.at(key); + return i < 0 ? Reflect.get(target, key) : this.item(i); + } + + set(target: T[], key: string | symbol, value: T): boolean { + const i = this.at(key); + if (i < 0) return Reflect.set(target, key, value); + if (i < this.s.length) this.s[i] = value; else this.room.set(i, value); + return true; + } + + has(target: T[], key: string | symbol): boolean { + return this.at(key) >= 0 || Reflect.has(target, key); + } + + ownKeys(target: T[]): (string | symbol)[] { + return [...Array.from({ length: this.length }, (_, i) => String(i)), ...Reflect.ownKeys(target)]; + } + + getOwnPropertyDescriptor(target: T[], key: string | symbol): PropertyDescriptor | undefined { + const i = this.at(key); + if (i < 0) return Reflect.getOwnPropertyDescriptor(target, key); + return { value: this.item(i), writable: true, enumerable: true, configurable: true }; } } /** The first `end` elements of the allocation `room` is past, its items and then itself, as a JS array read and written where they are. */ function roomView(room: Room, end: number): T[] { - return new Proxy(new Array(end), new RoomView(room, room.items, 0, end)); + return new Proxy(new Array(end), new RoomView(room, room.items, end)); } /** `Vec::as_ptr` and `as_mut_ptr` of `size`-byte elements: the pointer to its first, which reaches its room. */ diff --git a/ts/runtime/rs/task.ts b/ts/runtime/rs/task.ts index 019616f4e..772d922b0 100644 --- a/ts/runtime/rs/task.ts +++ b/ts/runtime/rs/task.ts @@ -4,7 +4,7 @@ // A value whose drop JS can observe has `[Symbol.dispose]`, which runs its `Drop` impl // and drops its fields. `None` is `undefined`, which drops as nothing. -import { Abort, arrayAssign, type ByteSlice, type ArrayRef, type LentArray, type ElemCopy, ArraySlice, arraySliceItems, arraySliceCopy, arraySliceSet, type CloneFrom, cloneOver, type Debug, type DebugStruct, debugStructField, debugStructFinish, debugStructFinishNonExhaustive, debugTupleField, debugTupleFinish, Err, type FmtResult, type Formatter, fmtBool, fmtDebugStruct, fmtDebugTuple, fmtDebugTupleFields, fmtPad, fmtStr, type None, NULL, objectCopy, OK, Ok, Panic, panic, type Place, place, ptrErase, ptrHome, ptrNowhere, ptrWrite, type Result, Slice, stringAsBytes, type Vec, assertFailed, fmtOwned } from "../rs.ts"; +import { Abort, arrayAssign, type ByteSlice, type ArrayRef, type LentArray, type ElemCopy, ArraySlice, arraySliceItems, arraySliceCopy, arraySliceSet, type CloneFrom, cloneOver, type Debug, type DebugStruct, debugStructField, debugStructFinish, debugStructFinishNonExhaustive, debugTupleField, debugTupleFinish, Err, type FmtResult, type Formatter, fmtBool, fmtDebugStruct, fmtDebugTuple, fmtDebugTupleFields, fmtPad, fmtStr, type None, NULL, objectCopy, OK, Ok, Panic, panic, type Place, place, ptrErase, ptrHome, ptrNowhere, ptrWrite, type Result, Slice, sliceSet, sliceToArray, stringAsBytes, type Vec, assertFailed, fmtOwned } from "../rs.ts"; import type { Hasher } from "./hash.ts"; import type { Location } from "./location.ts"; @@ -912,12 +912,49 @@ export function cellOfPlace(p: Place): Cell { return p as Cell; } +/** + * A cell `Cell::from_mut` or `UnsafeCell::from_mut` makes of a `&mut [T; N]`, the slice `s`: + * a read is a copy of the array, a write lands where `s` holds it, and a pointer to it is `s`. + */ +class ArrayCell implements Place { + readonly s: S; + readonly #read: () => A; + readonly #write: (value: A) => void; + + constructor(s: S, read: () => A, write: (value: A) => void) { + this.s = s; + this.#read = read; + this.#write = write; + } + + get v(): A { + return this.#read(); + } + + set v(value: A) { + this.#write(value); + } +} + +/** `Cell::from_mut` or `UnsafeCell::from_mut` of a `&mut [T; N]`, which is `s`. */ +export function cellOfSlice(s: Slice): Cell { + return cellOfPlace(new ArrayCell(s, () => sliceToArray(s), (value: T[]) => sliceSet(s, value))); +} + /** * `Cell::from_mut` of a `&mut [[T; N]; M]`, which is the arrays `r`: a read is a copy of * them, each element copied by `copy`, and a write lands where `r` holds them. */ export function cellOfArraySlice(r: ArraySlice, copy?: ElemCopy): Cell[]> { - return cellOfPlace(place(() => arraySliceCopy(r, copy), (value) => arraySliceSet(r, value))); + return cellOfPlace(new ArrayCell(r, () => arraySliceCopy(r, copy), (value: LentArray[]) => arraySliceSet(r, value))); +} + +/** + * The pointer to the array a cell of one, `c`, holds, the slice of it `from` makes: the slice + * `Cell::from_mut` made it of, or else the slice of all of the array. + */ +export function cellArray(c: Cell, from: (array: A) => S): S { + return c instanceof ArrayCell ? (c.s as S) : from(c.v); } /** diff --git a/ts/src/lower/lend.rs b/ts/src/lower/lend.rs index f629db886..2687dbade 100644 --- a/ts/src/lower/lend.rs +++ b/ts/src/lower/lend.rs @@ -77,6 +77,10 @@ pub fn plan<'tcx>(t: &Translator<'_, 'tcx>, def_id: DefId, args: GenericArgsRef< | ("ToOwned", "clone_into") | ("raw" | "array" | "Cell" | "UnsafeCell" | "ptr", "from_mut") | ("Option", "get_or_insert" | "get_or_insert_with" | "get_or_insert_default" | "insert") => true, + // A reference to an array a pointer or a cell points at, which is the slice the pointer is. + ("ptr" | "NonNull", "as_ref" | "as_mut") + | ("UnsafeCell", "get_mut" | "as_ref_unchecked" | "as_mut_unchecked") + | ("Cell", "get_mut") => true, // `Clone::clone`, which takes the slice, and an array as a slice, which it is. ("ToOwned", "to_owned") => true, // An array as a slice, which it is, and what a reference lends, which it is too. @@ -335,10 +339,10 @@ pub fn lend<'tcx>(b: &mut Body<'_, '_, 'tcx>, generic: Ty<'tcx>, ty: Ty<'tcx>, v /// `value`, a `ty` translated code gives std's mapping as an input whose type in std's /// generic code is `generic`, as the mapping reads it: each `&[T; N]` where it takes a /// `&T`, which it reads, copies, and writes through as the array: the `rs.byteSliceView` -/// of an `rs.ByteSlice`, or the `rs.sliceView` of an `rs.Slice` lent mutably, which share -/// the elements for as long as the reference lives, so whatever the mapping keeps of it -/// reads and writes where the reference does, or else the `rs.sliceItems`, which reads -/// them faster than a view where the slice is part of an array. +/// of an `rs.ByteSlice`, which shares the bytes for as long as the reference lives, so +/// whatever the mapping keeps of it reads and writes where the reference does, or else the +/// `rs.sliceItems` of a shared one, which nothing writes through. A mutable one of other +/// elements, which no JS array shares, is refused. pub fn give<'tcx>(b: &mut Body<'_, '_, 'tcx>, generic: Ty<'tcx>, ty: Ty<'tcx>, value: Expr, span: Span) -> Expr { cross(b, generic, ty, value, Way::Given, span) } @@ -395,7 +399,6 @@ fn cross<'tcx>(b: &mut Body<'_, '_, 'tcx>, generic: Ty<'tcx>, ty: Ty<'tcx>, valu // The slice of the elements a slice was read as is that slice. Expr::Rs(f) if f == "sliceFrom" => super::library::slice_from(value), Expr::Rs(f) if f == "sliceItems" => super::library::slice_items(value), - Expr::Rs(f) if f == "sliceView" => super::library::slice_view(value), f => f.call(vec![value]), } } @@ -405,24 +408,27 @@ fn cross_fn<'tcx>(b: &mut Body<'_, '_, 'tcx>, generic: Ty<'tcx>, ty: Ty<'tcx>, w if let ty::Ref(_, inner, mutability) = ty.kind() && let ty::Array(elem, _) = inner.kind() { + // Only bytes have a JS array that is part of another, a `Uint8Array` view, so a mapping + // can't write through any other part of an array as an array. + if way == Way::Given && *mutability == ty::Mutability::Mut && !super::byte(*elem) { + return b.err( + span, + format!("giving std a `{ty}` to write through as an array, which is not supported yet"), + ); + } // An array slice, each array lent as its own `From` lends it, and given as copies, which a `&` reads. if elem.is_array() { - return match (way, mutability) { - (Way::Lent, _) => super::array_fn(*inner, "From"), - (Way::Given, ty::Mutability::Not) => Expr::Rs("arraySliceItems".into()), - (Way::Given, ty::Mutability::Mut) => b.err( - span, - format!("giving std a `{ty}` to write through as an array, which is not supported yet"), - ), + return match way { + Way::Lent => super::array_fn(*inner, "From"), + Way::Given => Expr::Rs("arraySliceItems".into()), }; } return Expr::Rs( - match (way, super::byte(*elem), mutability) { - (Way::Lent, true, _) => "byteSliceFrom", - (Way::Given, true, _) => "byteSliceView", - (Way::Lent, false, _) => "sliceFrom", - (Way::Given, false, ty::Mutability::Mut) => "sliceView", - (Way::Given, false, ty::Mutability::Not) => "sliceItems", + match (way, super::byte(*elem)) { + (Way::Lent, true) => "byteSliceFrom", + (Way::Given, true) => "byteSliceView", + (Way::Lent, false) => "sliceFrom", + (Way::Given, false) => "sliceItems", } .into(), ); diff --git a/ts/src/lower/library.rs b/ts/src/lower/library.rs index ceb6a2325..469a72b93 100644 --- a/ts/src/lower/library.rs +++ b/ts/src/lower/library.rs @@ -4264,12 +4264,6 @@ pub fn items_of(s: Expr, elem: Ty<'_>) -> Expr { } } -/// The array of `s`, an `rs.Slice`, as `rs.sliceView` writes through it: all of an array is -/// the array. -pub fn slice_view(s: Expr) -> Expr { - array_of(s, "sliceView") -} - /// `rs.{read}` of `s`, an `rs.Slice`: the array of an `rs.sliceFrom`. fn array_of(s: Expr, read: &str) -> Expr { match s { @@ -4285,11 +4279,11 @@ fn array_of(s: Expr, read: &str) -> Expr { } /// All of `items`, a JS array, as an `rs.Slice`, as `rs.sliceFrom` makes one: the elements -/// `rs.sliceItems` or `rs.sliceView` read of a slice are that slice. +/// `rs.sliceItems` reads of a slice are that slice. pub fn slice_from(items: Expr) -> Expr { match items { Expr::Call(f, mut args) - if matches!(&*f, Expr::Rs(n) if n == "sliceItems" || n == "sliceView") && args.len() == 1 => + if matches!(&*f, Expr::Rs(n) if n == "sliceItems") && args.len() == 1 => { args.pop().unwrap() } diff --git a/ts/src/lower/mir/call.rs b/ts/src/lower/mir/call.rs index 63d77fda8..fa8fcd6a9 100644 --- a/ts/src/lower/mir/call.rs +++ b/ts/src/lower/mir/call.rs @@ -1659,14 +1659,6 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { if let ty::Array(elem, len) = ty.kind() && (!cell || elem.is_array()) { - if owner == "UnsafeCell" { - return Some(self.err( - span, - format!( - "`UnsafeCell::from_mut` of `{ty}`, an array of arrays, which a cell of it reads a copy of, so a write through its pointer would land in the copy" - ), - )); - } let slice = self.operand(op, span, out); if cell { let copy = self.b.t.elem_copy(ty, span); @@ -1690,9 +1682,23 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { ), )); } + // The bytes a `&mut [u8; N]` views, or a cell of the slice a `&mut` to another array is, + // where its writes land. if self.in_array(deref) { + let inner = self.b.t.uninit_inner(ty); + if crate::lower::byte_array(inner) { + let slice = self.place_expr(deref, span, out); + return Some(of_object(Expr::rs("byteSliceView", vec![slice]))); + } + if !cell || crate::lower::array_slice::of_arrays(inner) { + let path = if owner == "raw" { "slice" } else { owner }; + return Some(self.err( + span, + format!("`{path}::from_mut` of `{ty}`, an array a `MaybeUninit` holds, which is not supported yet"), + )); + } let slice = self.place_expr(deref, span, out); - return Some(of_object(self.b.t.array_rs(ty, "View").call(vec![slice]))); + return Some(Expr::rs("cellOfSlice", vec![slice])); } // A cell of an object is of it wherever it is, as its place may be one a write lands // in, such as an element of a slice of one. @@ -2031,9 +2037,9 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { } Some(p) => { let slice = self.borrowed_slice(place.0, p, span, out); - let mut made = vec![Expr::rs("sliceView", vec![slice]), value]; + let mut made = vec![slice, value]; made.extend(self.b.t.copy_depth(ty)); - Expr::rs("replaceIn", made) + Expr::rs("sliceReplaceAll", made) } None => { let mut made = vec![place.0, value]; diff --git a/ts/src/lower/pointer.rs b/ts/src/lower/pointer.rs index 4c3fc6dbd..424d4d86e 100644 --- a/ts/src/lower/pointer.rs +++ b/ts/src/lower/pointer.rs @@ -580,15 +580,6 @@ pub fn call<'tcx>( ty::Array(elem, _) => super::slice_items_from(e, *elem), _ => super::library::slice_from(e), }; - // The arrays of an array of arrays have no JS array to write through. - let to_reference = |b: &mut Body<'_, '_, 'tcx>, e: Expr| match b.t.uninit_inner(pointee()) { - ty if super::byte_array(ty) => Expr::rs("byteSliceView", vec![e]), - ty if super::array_slice::of_arrays(ty) => b.err( - span, - format!("a reference to `{ty}` from a raw pointer, which is not supported yet"), - ), - _ => super::library::slice_view(e), - }; // A raw pointer to a slice, from a reference to one, and the slice a read through it // makes, shared if nothing writes through it. let raw_of = |ty: Ty<'tcx>, s: Expr| match ty { @@ -664,7 +655,8 @@ pub fn call<'tcx>( ("NonNull", "as_ref" | "as_mut") if kind(b, pointee()) == Some(Pointee::Slice) => { deref(pointee(), arg(), name == "as_ref") } - ("NonNull", "as_mut") if array(b, pointee()) => to_reference(b, arg()), + // A reference to an array is the slice a pointer to it is, which `lend` leaves as it is. + ("NonNull", "as_mut") if array(b, pointee()) => arg(), // A `&mut` to a `MaybeUninit` of a cell of a value JS copies is the place the cell is // kept in, but one to the cell is the cell. ("MaybeUninit", "assume_init_mut") @@ -740,7 +732,6 @@ pub fn call<'tcx>( let shared = name == "as_ref" && kind(b, pointee()) == Some(super::pointer::Pointee::Place); let (some, none) = match shared { true => (p.clone().member("v"), b.t.none(pointee())), - false if array(b, pointee()) => (to_reference(b, p.clone()), Expr::undefined()), false => (p.clone(), Expr::undefined()), }; Expr::Cond( @@ -751,7 +742,6 @@ pub fn call<'tcx>( } ("NonNull", "as_ref") | ("MaybeUninit", "assume_init_ref") => match kind(b, pointee()) { Some(Pointee::Place) if owner == "NonNull" => arg().member("v"), - Some(Pointee::Array) if owner == "NonNull" => to_reference(b, arg()), _ => arg(), }, // An `rs.Arc` is its allocation, which has one place of its value: the pointer to a @@ -823,7 +813,11 @@ pub fn call<'tcx>( ("Box", "from_raw") => match kind(b, pointee()) { Some(Pointee::Slice) => deref(pointee(), arg(), false), Some(Pointee::Place) => arg().member("v"), - Some(Pointee::Array) => to_reference(b, arg()), + // A box of an array is the array, all of which `into_raw` pointed at. + Some(Pointee::Array) => match b.t.uninit_inner(pointee()) { + ty if super::byte_array(ty) => Expr::rs("byteSliceView", vec![arg()]), + _ => Expr::rs("boxArrayFromRaw", vec![arg()]), + }, _ => arg(), }, ("ptr", "read" | "read_unaligned" | "read_volatile") => { @@ -988,6 +982,13 @@ pub fn call<'tcx>( } // What `get` points at, lent as `get_mut` lends it. ("UnsafeCell" | "Cell", "get_mut") | ("UnsafeCell", "as_mut_unchecked") if b.t.needs_place(pointee()) => arg(), + // The pointer `get` gives to an array is the reference to it, which `lend` leaves as it is. + ("UnsafeCell", "get_mut" | "as_ref_unchecked" | "as_mut_unchecked") | ("Cell", "get_mut") + if kind(b, pointee()) == Some(Pointee::Array) => + { + let cell = arg(); + cell_pointer(b, cell, pointee()) + } ("UnsafeCell", "get_mut" | "as_ref_unchecked" | "as_mut_unchecked" | "into_inner") | ("Cell", "get_mut") => { arg().member("v") } @@ -1303,8 +1304,13 @@ pub(super) fn cell_pointer<'tcx>(b: &Body<'_, '_, 'tcx>, cell: Expr, ty: Ty<'tcx if pointee == Pointee::Place { return cell; } + let inner = b.t.uninit_inner(ty); + if pointee == Pointee::Array && !super::byte_array(inner) { + // The slice `Cell::from_mut` made the cell of, or else of all of the array it holds. + return Expr::rs("cellArray", vec![cell, super::array_fn(inner, "From")]); + } let held = cell.member("v"); - match (pointee, b.t.uninit_inner(ty).kind()) { + match (pointee, inner.kind()) { (Pointee::Array, ty::Array(elem, _)) => super::slice_items_from(held, *elem), (Pointee::Slice, _) if slice_of_bytes(ty) => Expr::rs("rawByteSliceOf", vec![held]), (Pointee::Slice, _) if slice_of_arrays(ty) => Expr::rs("rawArraySliceOf", vec![held]), @@ -1351,19 +1357,21 @@ pub(super) fn replace<'tcx>( /// What `p`, a pointer to `ty`, points at, as a value of its own that a whole write there /// after leaves as it was. The write lands in the object or array a pointer is, so one is -/// copied one object deep, an array's elements to the depth `objectCopy` copies them. One +/// copied one object deep, an array's elements to the depth `objectCopy` copies them, and an +/// array of arrays' as [`super::Translator::elem_copy`] says. One /// a pointer is the place of is read as it is, keeping a `Box`'s allocation, as its write /// puts another in the place. fn copied_out<'tcx>(b: &mut Body<'_, '_, 'tcx>, p: Expr, ty: Ty<'tcx>, span: Span, out: &mut Vec) -> Expr { match b.t.pointee(ty) { _ if b.t.zero_sized(ty) || b.t.keeps_cells(ty) => read(b, p, ty, span, out), Pointee::Object => Expr::rs("objectCopy", vec![p]), - Pointee::Array - if !super::byte_array(b.t.uninit_inner(ty)) && !super::array_slice::of_arrays(b.t.uninit_inner(ty)) => - { + Pointee::Array if super::array_slice::of_arrays(b.t.uninit_inner(ty)) => { + let copy = b.t.elem_copy(b.t.uninit_inner(ty), span); + Expr::rs("arraySliceCopy", std::iter::once(p).chain(copy).collect()) + } + Pointee::Array if !super::byte_array(b.t.uninit_inner(ty)) => { let depth = b.t.copy_depth(b.t.uninit_inner(ty)); - let view = super::library::slice_view(p); - Expr::rs("objectCopy", std::iter::once(view).chain(depth).collect()) + Expr::rs("sliceCopy", std::iter::once(p).chain(depth).collect()) } _ => read(b, p, ty, span, out), } diff --git a/ts/src/lower/task.rs b/ts/src/lower/task.rs index 8b6197e5c..8faf39496 100644 --- a/ts/src/lower/task.rs +++ b/ts/src/lower/task.rs @@ -594,12 +594,9 @@ fn cell<'tcx>( let span = call.span; let ty = call.args.type_at(0); // A pointer `as_ptr` gave to an object or an array is it, so a write lands in it, as it - // does in each cell a value keeps. A cell of arrays of arrays may be `Cell::from_mut`'s, - // which reads a copy of them, so it is written whole. - let arrays = super::array_slice::of_arrays(b.t.uninit_inner(ty)); - let in_place = (matches!(b.t.pointee(ty), Pointee::Object | Pointee::Array) || b.t.keeps_cells(ty)) - && !b.t.zero_sized(ty) - && !arrays; + // does in each cell a value keeps. + let in_place = + (matches!(b.t.pointee(ty), Pointee::Object | Pointee::Array) || b.t.keeps_cells(ty)) && !b.t.zero_sized(ty); let default = |b: &mut Body<'_, '_, 'tcx>, out: &mut Vec| { let f = super::collections::trait_fn(tcx, "Default", "default"); b.call_def(f, tcx.mk_args(&[ty.into()]), Vec::new(), span, out) From 4368ff918fc24d373a18df530095ef27eec550ac Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Sat, 7 Nov 2026 14:53:30 -0800 Subject: [PATCH 03/12] style(ts): format, and drop a reject case another refusal already covers Co-Authored-By: Claude Opus 5.5 --- ts/fixtures/reject/census.txt | 3 --- ts/fixtures/reject/expected.txt | 3 --- ts/src/lower/library.rs | 4 +--- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/ts/fixtures/reject/census.txt b/ts/fixtures/reject/census.txt index b4da095f8..b03a983c6 100644 --- a/ts/fixtures/reject/census.txt +++ b/ts/fixtures/reject/census.txt @@ -32,9 +32,6 @@ fixtures/reject/src/alloc.rs:cell_raw_unknown+9:13: `UnsafeCell::raw_get` of a p fixtures/reject/src/alloc.rs:pinned_lent+1:32: `UnsafeCell::get_mut` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:pinned_lent+2:43: `UnsafeCell::as_mut_unchecked` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:reinterpreted+1:27: a cast from a pointer to `u32` to one to `u8`, which reads the bytes of one type as another -fixtures/reject/src/alloc.rs:uninit_array_slice+1:42: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet -fixtures/reject/src/alloc.rs:uninit_array_slice+2:44: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet -fixtures/reject/src/alloc.rs:uninit_array_slice+2:52: an offset of a pointer to `std::mem::MaybeUninit<[u32; 2]>`, which JS keeps as an object that knows no array it is in fixtures/reject/src/alloc.rs:uninit_cell_lent+2:17: `MaybeUninit::assume_init_mut` of `std::cell::UnsafeCell`, whose mutable reference is the object, but the uninitialized value's is the place it is kept in fixtures/reject/src/alloc.rs:vec_pointer+1:10: a raw pointer to `std::vec::Vec` behind a reference, which is the object and not where it is kept fixtures/reject/src/alloc.rs:wrapped_cells+8:19: a whole write of `std::mem::MaybeUninit<(std::cell::UnsafeCell, u32)>`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds diff --git a/ts/fixtures/reject/expected.txt b/ts/fixtures/reject/expected.txt index 02b3a91fb..46f587f99 100644 --- a/ts/fixtures/reject/expected.txt +++ b/ts/fixtures/reject/expected.txt @@ -36,9 +36,6 @@ fixtures/reject/src/alloc.rs:cell_raw_unknown+9:13: `UnsafeCell::raw_get` of a p fixtures/reject/src/alloc.rs:pinned_lent+1:32: `UnsafeCell::get_mut` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:pinned_lent+2:43: `UnsafeCell::as_mut_unchecked` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:reinterpreted+1:27: a cast from a pointer to `u32` to one to `u8`, which reads the bytes of one type as another -fixtures/reject/src/alloc.rs:uninit_array_slice+1:42: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet -fixtures/reject/src/alloc.rs:uninit_array_slice+2:44: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet -fixtures/reject/src/alloc.rs:uninit_array_slice+2:52: an offset of a pointer to `std::mem::MaybeUninit<[u32; 2]>`, which JS keeps as an object that knows no array it is in fixtures/reject/src/alloc.rs:uninit_cell_lent+2:17: `MaybeUninit::assume_init_mut` of `std::cell::UnsafeCell`, whose mutable reference is the object, but the uninitialized value's is the place it is kept in fixtures/reject/src/alloc.rs:vec_pointer+1:10: a raw pointer to `std::vec::Vec` behind a reference, which is the object and not where it is kept fixtures/reject/src/alloc.rs:wrapped_cells+8:19: a whole write of `std::mem::MaybeUninit<(std::cell::UnsafeCell, u32)>`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds diff --git a/ts/src/lower/library.rs b/ts/src/lower/library.rs index 469a72b93..bf94c52d5 100644 --- a/ts/src/lower/library.rs +++ b/ts/src/lower/library.rs @@ -4282,9 +4282,7 @@ fn array_of(s: Expr, read: &str) -> Expr { /// `rs.sliceItems` reads of a slice are that slice. pub fn slice_from(items: Expr) -> Expr { match items { - Expr::Call(f, mut args) - if matches!(&*f, Expr::Rs(n) if n == "sliceItems") && args.len() == 1 => - { + Expr::Call(f, mut args) if matches!(&*f, Expr::Rs(n) if n == "sliceItems") && args.len() == 1 => { args.pop().unwrap() } items => Expr::rs("sliceFrom", vec![items]), From ec4a9ff23c245ae1eeed865535bf16aecc2db7df Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Sat, 7 Nov 2026 15:02:22 -0800 Subject: [PATCH 04/12] test(ts): regenerate the array-part snapshots Co-Authored-By: Claude Opus 5.5 --- .../lang/pointers/expected/pointers.ts | 6 +- ts/fixtures/lang/slices/expected/slices.ts | 191 ++++++++++-------- 2 files changed, 108 insertions(+), 89 deletions(-) diff --git a/ts/fixtures/lang/pointers/expected/pointers.ts b/ts/fixtures/lang/pointers/expected/pointers.ts index ea1f870f7..839b130d7 100644 --- a/ts/fixtures/lang/pointers/expected/pointers.ts +++ b/ts/fixtures/lang/pointers/expected/pointers.ts @@ -4077,9 +4077,9 @@ export function tripled(b: rs.u8): rs.u8 { } /** - * A raw pointer to a `[T; N]` that is part of a slice: lent back as a reference by - * `as_mut`, `NonNull::as_mut`, and `Box::from_raw`, and written whole by `ptr::replace` - * and `ptr::swap`. + * A raw pointer to a `[T; N]` and to a `[[T; N]; M]` that is part of a slice, lent back as + * a reference by `as_mut` and `NonNull::as_mut`, and the first written whole by + * `ptr::replace` and `ptr::swap`; and a box of each taken back by `Box::from_raw`. */ export function arrayParts(data: rs.ByteSlice, out: rs.ByteVec): void { const n: rs.u32 = option_mapOr$1wlsr3s(rs.byteSliceFirst(data), 0, (_2: rs.u8): rs.u32 => { diff --git a/ts/fixtures/lang/slices/expected/slices.ts b/ts/fixtures/lang/slices/expected/slices.ts index 9e39316b6..704f53944 100644 --- a/ts/fixtures/lang/slices/expected/slices.ts +++ b/ts/fixtures/lang/slices/expected/slices.ts @@ -3490,9 +3490,10 @@ export function putWords(words: rs.Slice, out: rs.ByteVec): void { } /** - * A `&mut [T; N]` to part of a slice, of numbers and of strings, written whole: by - * `mem::replace` and `mem::swap`, through a `Cell` and an `UnsafeCell` of it, by std given - * it to write through, and through a raw pointer to it. + * A `&mut [T; N]` to part of a slice, of numbers, of strings, and of arrays, written whole: + * by `mem::replace` and `mem::swap`, and through a `Cell` and an `UnsafeCell` of it, each + * way a cell reads, writes, and points at it; a cell of arrays pointed at before a write; + * and one std holds in an `Option` and a `Vec` and writes through. */ export function arrayParts(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { const words: rs.Vec = rs.iterToVec(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (_2: rs.u8): rs.u32 => { @@ -3507,111 +3508,129 @@ export function arrayParts(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): vo rs.vecResize(names, _17, _20, 12, (a0: rs.String): rs.String => { return rs.stringClone(a0); }); + const rows: rs.Vec = rs.iterToVec(rs.iterMap(rs.sliceChunks(rs.sliceFrom(words.items), 2), (c: rs.Slice): rs.u32[] => { + rs.idx(c, 0); + const _3: rs.u32 = c.data[c.start]; + const _8: rs.usize = rs.usizeSub(c.length, 1); + rs.idx(c, _8); + return [_3, c.data[c.start + _8]]; + }), undefined, 8, true); const n: rs.u32 = kind as rs.u32; - const _22: rs.u8 = rs.u8Rem(kind, 4); - if (_22 === 0) { - const _26: [rs.Slice, rs.Slice] = rs.sliceSplitAt(rs.sliceFrom(words.items), 1); - putWords(rs.sliceFrom(rs.sliceReplaceAll(rs.optionUnwrap(rs.sliceGetRange(_26[1], 0, 2)), [n, rs.u32Add(n, 1)])), out); - const _40: [rs.Slice, rs.Slice] = rs.optionUnwrap(rs.sliceSplitAtChecked(rs.sliceRange(_26[1], 2), 2)); - const y: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(_40[1], 0, 2)); - rs.sliceSet(y, rs.sliceReplaceAll(_40[0], rs.sliceToArray(y))); - rs.idx(_26[0], 0); - _26[0].data[_26[0].start] = n; + const _27: rs.u8 = rs.u8Rem(kind, 4); + if (_27 === 0) { + const _31: [rs.Slice, rs.Slice] = rs.sliceSplitAt(rs.sliceFrom(words.items), 1); + putWords(rs.sliceFrom(rs.sliceReplaceAll(rs.optionUnwrap(rs.sliceGetRange(_31[1], 0, 2)), [n, rs.u32Add(n, 1)])), out); + const _45: [rs.Slice, rs.Slice] = rs.optionUnwrap(rs.sliceSplitAtChecked(rs.sliceRange(_31[1], 2), 2)); + const y: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(_45[1], 0, 2)); + rs.sliceSet(y, rs.sliceReplaceAll(_45[0], rs.sliceToArray(y))); + rs.idx(_31[0], 0); + _31[0].data[_31[0].start] = n; const s: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(rs.sliceFrom(names.items), 1), 0, 2)); - const _57: rs.String[] = [rs.stringFrom("a"), rs.stringFrom("b")]; - rs.iterExtendBytes(out, rs.iterMap(rs.iterMap(rs.iterSlice(rs.sliceReplaceAll(s, _57, 1)), (a02: rs.String): rs.usize => { - return a02.len; - }), (l: rs.usize): rs.u8 => { - return l & 0xff; + const _62: rs.String[] = [rs.stringFrom("a"), rs.stringFrom("b")]; + rs.iterExtendBytes(out, rs.iterMap(rs.iterMap(rs.iterSlice(rs.sliceReplaceAll(s, _62, 1)), (a03: rs.String): rs.usize => { + return a03.len; + }), (l2: rs.usize): rs.u8 => { + return l2 & 0xff; }), undefined, true); - } else if (_22 === 1) { + } else if (_27 === 1) { const cell: rs.Cell = rs.cellOfSlice(rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(rs.sliceFrom(words.items), 1), 0, 2))); - const _73: rs.u32[] = [n, rs.u32Add(n, 2)]; - const pointer = rs.cellArray(cell, rs.sliceFrom); - const old5 = rs.sliceCopy(pointer); - rs.sliceSet(pointer, _73); - putWords(rs.sliceFrom(old5), out); + const _78: rs.u32[] = [n, rs.u32Add(n, 2)]; + const pointer2 = rs.cellArray(cell, rs.sliceFrom); + const old7 = rs.sliceCopy(pointer2); + rs.sliceSet(pointer2, _78); + putWords(rs.sliceFrom(old7), out); putWords(rs.sliceFrom(copy$array_u32(cell.v)), out); - const _84: rs.u32[] = [rs.u32Add(n, 3), rs.u32Add(n, 4)]; - rs.sliceSet(rs.cellArray(cell, rs.sliceFrom), _84); + const _89: rs.u32[] = [rs.u32Add(n, 3), rs.u32Add(n, 4)]; + rs.sliceSet(rs.cellArray(cell, rs.sliceFrom), _89); const p: rs.Slice = rs.cellArray(cell, rs.sliceFrom); p.data[p.start + 1] = rs.u32Add(n, 5); - const pointer2 = rs.cellArray(cell, rs.sliceFrom); - rs.sliceSet(pointer2, ((_24: rs.u32[]): rs.u32[] => { - return [_24[1], _24[0]]; - })(rs.sliceToArray(pointer2))); + const pointer3 = rs.cellArray(cell, rs.sliceFrom); + rs.sliceSet(pointer3, ((_29: rs.u32[]): rs.u32[] => { + return [_29[1], _29[0]]; + })(rs.sliceToArray(pointer3))); const value2 = Array.from({ length: 2 }, (): rs.u32 => { return 0; }); - const pointer3 = rs.cellArray(cell, rs.sliceFrom); - const old6 = rs.sliceCopy(pointer3); - rs.sliceSet(pointer3, value2); - putWords(rs.sliceFrom(old6), out); - const rows: rs.Vec = rs.iterToVec(rs.iterMap(rs.sliceChunks(rs.sliceFrom(words.items), 2), (c: rs.Slice): rs.u32[] => { - rs.idx(c, 0); - const _35: rs.u32 = c.data[c.start]; - const _8: rs.usize = rs.usizeSub(c.length, 1); - rs.idx(c, _8); - return [_35, c.data[c.start + _8]]; - }), undefined, 8, true); - const cell2: rs.Cell = rs.cellOfArraySlice(rs.optionUnwrap(rs.arraySliceGetRange(rs.arraySliceRange(rs.arraySliceFrom(rows.items, rs.sliceFrom), 1), 0, 2))); - const p2: rs.ArraySlice> = rs.cellArray(cell2, rs.arraySliceOf(rs.sliceFrom)); - const _110: rs.u32 = rs.u32Add(n, 6); - const slice5 = rs.arraySliceAt(p2, 0); - slice5.data[slice5.start + 1] = _110; - const _116: rs.u32[][] = [[n, rs.u32Add(n, 7)], [rs.u32Add(n, 8), n]]; - const pointer4 = rs.cellArray(cell2, rs.arraySliceOf(rs.sliceFrom)); - const old7 = rs.arraySliceCopy(pointer4); - rs.arraySliceSet(pointer4, _116); - rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(old7, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_25: rs.u32): rs.u8 => { + const pointer4 = rs.cellArray(cell, rs.sliceFrom); + const old8 = rs.sliceCopy(pointer4); + rs.sliceSet(pointer4, value2); + putWords(rs.sliceFrom(old8), out); + const _109: rs.Cell = rs.cellOfSlice(rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(rs.sliceFrom(names.items), 2), 0, 2))); + const _110: rs.String[] = [rs.stringFrom("abc"), rs.stringNew()]; + const pointer5 = rs.cellArray(_109, rs.sliceFrom); + const old9 = rs.sliceCopy(pointer5, 1); + rs.sliceSet(pointer5, _110); + rs.iterExtendBytes(out, rs.iterMap(rs.iterMap(rs.iterSlice(old9), (a02: rs.String): rs.usize => { + return a02.len; + }), (l: rs.usize): rs.u8 => { + return l & 0xff; + }), undefined, true); + const cell2: rs.Cell = rs.cellOfSlice(rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(rs.sliceFrom(words.items), 2), 0, 2))); + const _125: rs.u32 = rs.u32Add(n, 6); + const _126: rs.Slice = rs.cellArray(cell2, rs.sliceFrom); + _126.data[_126.start] = _125; + const _130: rs.u32 = rs.u32Add(n, 7); + const _131: rs.Slice = rs.cellArray(cell2, rs.sliceFrom); + _131.data[_131.start + 1] = _130; + } else if (_27 === 2) { + const cell3: rs.Cell = rs.cellOfArraySlice(rs.optionUnwrap(rs.arraySliceGetRange(rs.arraySliceRange(rs.arraySliceFrom(rows.items, rs.sliceFrom), 1), 0, 2))); + const p2: rs.ArraySlice> = rs.cellArray(cell3, rs.arraySliceOf(rs.sliceFrom)); + const _141: rs.u32 = rs.u32Add(n, 6); + const slice3 = rs.arraySliceAt(p2, 0); + slice3.data[slice3.start + 1] = _141; + const _147: rs.u32[][] = [[n, rs.u32Add(n, 7)], [rs.u32Add(n, 8), n]]; + const pointer = rs.cellArray(cell3, rs.arraySliceOf(rs.sliceFrom)); + const old6 = rs.arraySliceCopy(pointer); + rs.arraySliceSet(pointer, _147); + rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(old6, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_25: rs.u32): rs.u8 => { return _25 & 0xff; }), undefined, true); - const cell3: rs.Cell = rs.cellOfArraySlice(rs.optionUnwrap(rs.arraySliceGetRange(rs.arraySliceRange(rs.arraySliceFrom(rows.items, rs.sliceFrom), 0, 2), 0, 2))); - const _135: rs.u32 = rs.u32Add(n, 9); - const slice7 = rs.arraySliceAt(rs.cellArray(cell3, rs.arraySliceOf(rs.sliceFrom)), 1); - slice7.data[slice7.start] = _135; - const _142: rs.u32 = rs.u32Add(n, 10); - const slice8 = rs.arraySliceAt(rs.cellArray(cell3, rs.arraySliceOf(rs.sliceFrom)), 0); - slice8.data[slice8.start] = _142; - rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rows.items, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_28: rs.u32): rs.u8 => { - return _28 & 0xff; + const cell4: rs.Cell = rs.cellOfArraySlice(rs.optionUnwrap(rs.arraySliceGetRange(rs.arraySliceRange(rs.arraySliceFrom(rows.items, rs.sliceFrom), 0, 2), 0, 2))); + const _166: rs.u32 = rs.u32Add(n, 9); + const slice5 = rs.arraySliceAt(rs.cellArray(cell4, rs.arraySliceOf(rs.sliceFrom)), 1); + slice5.data[slice5.start] = _166; + const _173: rs.u32 = rs.u32Add(n, 10); + const slice6 = rs.arraySliceAt(rs.cellArray(cell4, rs.arraySliceOf(rs.sliceFrom)), 0); + slice6.data[slice6.start] = _173; + const held: rs.Cell = new rs.Cell([[n, 1], [2, n]]); + const p3: rs.ArraySlice> = rs.cellArray(held, rs.arraySliceOf(rs.sliceFrom)); + const _187: rs.u32[][] = [[3, n], [n, 4]]; + rs.arraySliceSet(rs.cellArray(held, rs.arraySliceOf(rs.sliceFrom)), _187); + rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rs.arraySliceToArray(p3, rs.sliceToArray), rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_26: rs.u32): rs.u8 => { + return _26 & 0xff; }), undefined, true); - } else if (_22 === 2) { - const cell4: rs.Cell = rs.cellOfSlice(rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(rs.sliceFrom(words.items), 2), 0, 2))); - const _160: rs.Slice = rs.cellArray(cell4, rs.sliceFrom); - _160.data[_160.start] = n; - const _164: rs.u32 = rs.u32Add(n, 1); - const _165: rs.Slice = rs.cellArray(cell4, rs.sliceFrom); - _165.data[_165.start + 1] = _164; } else { - const _170: [rs.Slice, rs.Slice] = rs.optionUnwrap(rs.sliceSplitAtChecked(rs.sliceRange(rs.sliceFrom(words.items), 1), 2)); - rs.idx(_170[1], 0); - _170[1].data[_170[1].start] = n; - let kept: rs.Slice | undefined = _170[0]; - const _180: rs.Place> | undefined = kept === undefined ? undefined : rs.place(() => kept as rs.Slice, (value) => kept = value); - if (_180 !== undefined) { - const _184: rs.u32 = rs.u32Add(n, 1); - const _223: rs.Slice = _180.v; - _223.data[_223.start] = _184; + const _199: [rs.Slice, rs.Slice] = rs.optionUnwrap(rs.sliceSplitAtChecked(rs.sliceRange(rs.sliceFrom(words.items), 1), 2)); + rs.idx(_199[1], 0); + _199[1].data[_199[1].start] = n; + let kept: rs.Slice | undefined = _199[0]; + const _209: rs.Place> | undefined = kept === undefined ? undefined : rs.place(() => kept as rs.Slice, (value) => kept = value); + if (_209 !== undefined) { + const _213: rs.u32 = rs.u32Add(n, 1); + const _258: rs.Slice = _209.v; + _258.data[_258.start] = _213; } option_map$0cigbgc(kept, (a4: rs.Slice): undefined => { a4.data[a4.start + 1] = rs.u32Add(n, 2); }); const v: rs.Vec> = new rs.Vec(); - const _194: [rs.Slice, rs.Slice] = rs.sliceSplitAt(rs.sliceFrom(words.items), 2); - const _199: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(_194[1], 0, 2)); - v.items.push(_199); - const _203: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(_194[0], 0, 2)); - v.items.push(_203); - for (const _208 of v.items) { - rs.sliceSwap(_208, 0, 1); + const _223: [rs.Slice, rs.Slice] = rs.sliceSplitAt(rs.sliceFrom(words.items), 2); + const _228: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(_223[1], 0, 2)); + v.items.push(_228); + const _232: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(_223[0], 0, 2)); + v.items.push(_232); + for (const _237 of v.items) { + rs.sliceSwap(_237, 0, 1); } } putWords(rs.sliceFrom(words.items), out); - rs.iterExtendBytes(out, rs.iterMap(rs.iterMap(rs.iterSlice(names.items), (a03: rs.String): rs.usize => { - return a03.len; - }), (l2: rs.usize): rs.u8 => { - return l2 & 0xff; + rs.iterExtendBytes(out, rs.iterMap(rs.iterMap(rs.iterSlice(names.items), (a04: rs.String): rs.usize => { + return a04.len; + }), (l3: rs.usize): rs.u8 => { + return l3 & 0xff; + }), undefined, true); + rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rows.items, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_210: rs.u32): rs.u8 => { + return _210 & 0xff; }), undefined, true); } From 22833d99f854d6302f4f39ddee3c7dd32ebd8949 Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Sat, 7 Nov 2026 15:21:55 -0800 Subject: [PATCH 05/12] fix(ts): wrapped arrays lent as arrays, pinned boxes kept, and flat boxes taken back A reference from a raw pointer or a cell to an array a `MaybeUninit` holds is the array, as a reborrow makes it, with a mutable one through a raw pointer refused; an array of arrays' copy copies objects a write lands in only where one does; and `Box::from_raw` takes back arrays `as_chunks` split from all of a box's array. Co-Authored-By: Claude Opus 5.5 --- .../lang/pointers/expected/core/option.ts | 7 ++ .../lang/pointers/expected/pointers.ts | 47 +++++++++-- ts/fixtures/lang/pointers/src/pointers.rs | 29 ++++++- ts/fixtures/lang/slices/expected/slices.ts | 83 ++++++++++--------- ts/fixtures/lang/slices/src/slices.rs | 9 +- ts/fixtures/reject/census.txt | 2 + ts/fixtures/reject/expected.txt | 2 + ts/fixtures/reject/src/alloc.rs | 8 ++ ts/fixtures/reject/ts.toml | 1 + ts/runtime/rs.ts | 27 ++++-- ts/src/lower/pointer.rs | 42 +++++++++- 11 files changed, 200 insertions(+), 57 deletions(-) diff --git a/ts/fixtures/lang/pointers/expected/core/option.ts b/ts/fixtures/lang/pointers/expected/core/option.ts index 2bdef468d..13623916b 100644 --- a/ts/fixtures/lang/pointers/expected/core/option.ts +++ b/ts/fixtures/lang/pointers/expected/core/option.ts @@ -69,6 +69,13 @@ export function mapOr$00zno7m(self: Spot.Spot | undefined, default_: Spot.Spot, return f(copy$pointers_Spot(self)); } +export function mapOr$0m14xib(self: Uint8Array | rs.None, default_: Uint8Array, f: (a0: Uint8Array) => Uint8Array): Uint8Array { + if (self === rs.None) { + return default_; + } + return f(self); +} + export function mapOr$1wlsr3s(self: rs.u8 | undefined, default_: rs.u32, f: (a0: rs.u8) => rs.u32): rs.u32 { if (self === undefined) { return default_; diff --git a/ts/fixtures/lang/pointers/expected/pointers.ts b/ts/fixtures/lang/pointers/expected/pointers.ts index 839b130d7..91bd759df 100644 --- a/ts/fixtures/lang/pointers/expected/pointers.ts +++ b/ts/fixtures/lang/pointers/expected/pointers.ts @@ -3,7 +3,7 @@ import * as rs from "./rs.ts"; import { copy$Option_pointers_Pair, copy$Option_tuple2_u16_u8, copy$array_array2_u32, copy$array_ptr_array4_u8, copy$array_tuple2_u8_u8, copy$array_u16, copy$array_u32, copy$array_u8, copy$mem_MaybeUninit_array_u32, copy$mem_MaybeUninit_array_u8, copy$mem_MaybeUninit_tuple2_u8_u8, copy$pointers_Aimed_Cell_u8, copy$pointers_Aimed_array2_u16, copy$pointers_Aimed_array4_u8, copy$pointers_Aimed_pointers_Housed_u8, copy$pointers_Aimed_pointers_Leaning, copy$pointers_Aimed_pointers_Paired, copy$pointers_Aimed_u8, copy$pointers_ByCall, copy$pointers_ByClosure, copy$pointers_ByObject, copy$pointers_Duo, copy$pointers_Either_u32, copy$pointers_Either_u8, copy$pointers_Halves, copy$pointers_Outer, copy$pointers_Pair, copy$pointers_Reentrant, copy$pointers_Spot, copy$pointers_Twin, copy$tuple2_array2_u32_u8, copy$tuple2_u16_u8, copy$tuple2_u32_u32, copy$tuple2_u8_u16, copy$tuple2_u8_u8, drop$pointers_List_String, drop$pointers_List_sync_Arc_u8, drop$tuple2_sync_Arc_pointers_Twin_Rc_pointers_Twin, drop$tuple3_sync_Arc_u32_Rc_pointers_Duo_sync_Arc_unit, drop$tuple4_sync_Arc_pointers_Twin_sync_Arc_pointers_Twin_Rc_pointers_Twin_Rc_pointers_Twin, of$pointers_Bin_pointers_ByObject } from "./lib.ts"; import { then$0bgt67i, then$1a5xgoh, then$0jw3xip } from "./core/bool.ts"; -import { isSomeAnd$1s2u5lz, isSomeAnd$1nosv3e, isSomeAnd$07atiew, unwrapOr$0mkoact as option_unwrapOr$0mkoact, unwrapOr$179xo1w as option_unwrapOr$179xo1w, unwrapOr$1fr498u as option_unwrapOr$1fr498u, map$1cfrse5 as option_map$1cfrse5, mapOr$078vnqn as option_mapOr$078vnqn, mapOr$00zno7m as option_mapOr$00zno7m, mapOr$1wlsr3s as option_mapOr$1wlsr3s, mapOr$173j2gr as option_mapOr$173j2gr, filter$0wvwd70 } from "./core/option.ts"; +import { isSomeAnd$1s2u5lz, isSomeAnd$1nosv3e, isSomeAnd$07atiew, unwrapOr$0mkoact as option_unwrapOr$0mkoact, unwrapOr$179xo1w as option_unwrapOr$179xo1w, unwrapOr$1fr498u as option_unwrapOr$1fr498u, map$1cfrse5 as option_map$1cfrse5, mapOr$078vnqn as option_mapOr$078vnqn, mapOr$00zno7m as option_mapOr$00zno7m, mapOr$0m14xib as option_mapOr$0m14xib, mapOr$1wlsr3s as option_mapOr$1wlsr3s, mapOr$173j2gr as option_mapOr$173j2gr, filter$0wvwd70 } from "./core/option.ts"; import type * as Aimed from "./pointers.Aimed.ts"; import * as Bin from "./pointers.Bin.ts"; import type * as ByCall from "./pointers.ByCall.ts"; @@ -4079,7 +4079,9 @@ export function tripled(b: rs.u8): rs.u8 { /** * A raw pointer to a `[T; N]` and to a `[[T; N]; M]` that is part of a slice, lent back as * a reference by `as_mut` and `NonNull::as_mut`, and the first written whole by - * `ptr::replace` and `ptr::swap`; and a box of each taken back by `Box::from_raw`. + * `ptr::replace` and `ptr::swap`; a box of each taken back by `Box::from_raw`, and of arrays + * `as_chunks_mut` split from all of a box's array; and arrays a + * `MaybeUninit` holds, lent by `as_ref` and by a cell's `get_mut` and `as_mut_unchecked`. */ export function arrayParts(data: rs.ByteSlice, out: rs.ByteVec): void { const n: rs.u32 = option_mapOr$1wlsr3s(rs.byteSliceFirst(data), 0, (_2: rs.u8): rs.u32 => { @@ -4140,15 +4142,48 @@ export function arrayParts(data: rs.ByteSlice, out: rs.ByteVec): void { const _100: rs.u32 = rs.u32Add(n, 5); const slice7 = rs.arraySliceAt(nn2, 0); slice7.data[slice7.start + 1] = _100; - rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rows.items, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_212: rs.u32): rs.u8 => { - return _212 & 0xff; + rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rows.items, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_213: rs.u32): rs.u8 => { + return _213 & 0xff; }), undefined, true); const raw2: rs.ArraySlice> = rs.arraySliceFrom([[n, 1], [2, n]], rs.sliceFrom); const slice8 = rs.arraySliceAt(raw2, 1); slice8.data[slice8.start + 1] = 8; - rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rs.boxArrayFromRaw(raw2), rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_213: rs.u32): rs.u8 => { - return _213 & 0xff; + rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rs.boxArrayFromRaw(raw2), rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_218: rs.u32): rs.u8 => { + return _218 & 0xff; + }), undefined, true); + const back3: rs.u32[][] = rs.boxArrayFromRaw(rs.optionUnwrap(rs.arraySliceGetRange(rs.sliceAsChunks(rs.sliceFrom([n, 1, 2, rs.u32Add(n, 3)]), 2)[0], 0, 2))); + back3[1][0] = 9; + rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(back3, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_219: rs.u32): rs.u8 => { + return _219 & 0xff; }), undefined, true); + const p4: rs.Slice = rs.sliceFrom([n, 1]); + const pointer5 = p4; + const _156: rs.u32[] | rs.None = pointer5 === rs.NULL ? rs.None : rs.sliceItems(pointer5); + if (_156 !== rs.None) { + const _162: rs.Slice = rs.sliceFrom(_156); + rs.byteVecPush(out, _162.data[_162.start] & 0xff); + } + const pointer6 = p4; + const _171: rs.Slice = rs.sliceFrom(rs.sliceItems(rs.optionUnwrap(pointer6 === rs.NULL ? undefined : pointer6))); + rs.byteVecPush(out, _171.data[_171.start + 1] & 0xff); + const pointer7 = rs.byteSliceFrom(Uint8Array.of(n & 0xff, 5)); + rs.iterExtendBytes(out, rs.iterSlice(option_mapOr$0m14xib(pointer7 === rs.NULL ? rs.None : rs.byteSliceView(pointer7), rs.bytes(2), (m: Uint8Array): Uint8Array => { + return copy$mem_MaybeUninit_array_u8(m); + })), undefined, true); + const cell: rs.Cell = new rs.Cell(copy$mem_MaybeUninit_array_u8(Uint8Array.of(n & 0xff, 2))); + const _189: rs.ByteSlice = rs.byteSliceFrom(cell.v); + _189.data[_189.start + 1] = 9; + rs.iterExtendBytes(out, rs.iterSlice(cell.v), undefined, true); + const uc: rs.Cell = new rs.Cell(copy$mem_MaybeUninit_array_u32([n, 3])); + const _201: rs.u32 = rs.u32Add(n, 8); + const _202: rs.Slice = rs.sliceFrom(uc.v); + _202.data[_202.start] = _201; + const _207: rs.u32 = rs.u32Add(n, 9); + const _208: rs.Slice = rs.sliceFrom(uc.v); + _208.data[_208.start + 1] = _207; + rs.iterExtendBytes(out, rs.iterSlice(rs.bytesMap(uc.v, (w7: rs.u32): rs.u8 => { + return w7 & 0xff; + })), undefined, true); } //# sourceMappingURL=pointers.ts.map diff --git a/ts/fixtures/lang/pointers/src/pointers.rs b/ts/fixtures/lang/pointers/src/pointers.rs index 3b9ebd485..c09da2ea0 100644 --- a/ts/fixtures/lang/pointers/src/pointers.rs +++ b/ts/fixtures/lang/pointers/src/pointers.rs @@ -3037,7 +3037,9 @@ fn tripled(mut b: u8) -> u8 { /// A raw pointer to a `[T; N]` and to a `[[T; N]; M]` that is part of a slice, lent back as /// a reference by `as_mut` and `NonNull::as_mut`, and the first written whole by -/// `ptr::replace` and `ptr::swap`; and a box of each taken back by `Box::from_raw`. +/// `ptr::replace` and `ptr::swap`; a box of each taken back by `Box::from_raw`, and of arrays +/// `as_chunks_mut` split from all of a box's array; and arrays a +/// `MaybeUninit` holds, lent by `as_ref` and by a cell's `get_mut` and `as_mut_unchecked`. pub fn array_parts(data: &[u8], out: &mut Vec) { let n = data.first().map_or(0, |&b| u32::from(b)); let mut words: Vec = data.iter().map(|&b| u32::from(b)).collect(); @@ -3073,4 +3075,29 @@ pub fn array_parts(data: &[u8], out: &mut Vec) { unsafe { (*raw)[1][1] = 8 }; let back = unsafe { Box::from_raw(raw) }; out.extend(back.iter().flatten().map(|&w| w as u8)); + // Arrays `as_chunks_mut` split from all of a box's array, which has their layout. + let flat = Box::into_raw(Box::new([n, 1, 2, n + 3])); + let (runs, _) = unsafe { (*flat).as_chunks_mut::<2>() }; + let whole: *mut [[u32; 2]; 2] = runs.first_chunk_mut().unwrap(); + let mut back = unsafe { Box::from_raw(whole) }; + back[1][0] = 9; + out.extend(back.iter().flatten().map(|&w| w as u8)); + // Of arrays a `MaybeUninit` holds, whose reference is the array. + let mu = MaybeUninit::new([n, 1]); + let p: *const MaybeUninit<[u32; 2]> = μ + if let Some(m) = unsafe { p.as_ref() } { + out.push(unsafe { m.assume_init_ref()[0] } as u8); + } + let nn = NonNull::new(p.cast_mut()).unwrap(); + out.push(unsafe { nn.as_ref().assume_init_ref()[1] } as u8); + let bytes = MaybeUninit::new([n as u8, 5]); + let p: *const MaybeUninit<[u8; 2]> = &bytes; + out.extend(unsafe { p.as_ref() }.map_or([0; 2], |m| unsafe { m.assume_init() })); + let mut cell = Cell::new(MaybeUninit::new([n as u8, 2])); + unsafe { cell.get_mut().assume_init_mut()[1] = 9 }; + out.extend(unsafe { cell.into_inner().assume_init() }); + let mut uc = UnsafeCell::new(MaybeUninit::new([n, 3])); + unsafe { uc.get_mut().assume_init_mut()[0] = n + 8 }; + unsafe { uc.as_mut_unchecked().assume_init_mut()[1] = n + 9 }; + out.extend(unsafe { uc.into_inner().assume_init() }.map(|w| w as u8)); } diff --git a/ts/fixtures/lang/slices/expected/slices.ts b/ts/fixtures/lang/slices/expected/slices.ts index 704f53944..ce6778ab1 100644 --- a/ts/fixtures/lang/slices/expected/slices.ts +++ b/ts/fixtures/lang/slices/expected/slices.ts @@ -3492,8 +3492,8 @@ export function putWords(words: rs.Slice, out: rs.ByteVec): void { /** * A `&mut [T; N]` to part of a slice, of numbers, of strings, and of arrays, written whole: * by `mem::replace` and `mem::swap`, and through a `Cell` and an `UnsafeCell` of it, each - * way a cell reads, writes, and points at it; a cell of arrays pointed at before a write; - * and one std holds in an `Option` and a `Vec` and writes through. + * way a cell reads, writes, and points at it; a cell of arrays pointed at before a write, + * and of pinned boxes, whose replacement keeps their allocations; and one std holds in an `Option` and a `Vec` and writes through. */ export function arrayParts(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void { const words: rs.Vec = rs.iterToVec(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (_2: rs.u8): rs.u32 => { @@ -3535,32 +3535,32 @@ export function arrayParts(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): vo } else if (_27 === 1) { const cell: rs.Cell = rs.cellOfSlice(rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(rs.sliceFrom(words.items), 1), 0, 2))); const _78: rs.u32[] = [n, rs.u32Add(n, 2)]; - const pointer2 = rs.cellArray(cell, rs.sliceFrom); - const old7 = rs.sliceCopy(pointer2); - rs.sliceSet(pointer2, _78); - putWords(rs.sliceFrom(old7), out); + const pointer3 = rs.cellArray(cell, rs.sliceFrom); + const old9 = rs.sliceCopy(pointer3); + rs.sliceSet(pointer3, _78); + putWords(rs.sliceFrom(old9), out); putWords(rs.sliceFrom(copy$array_u32(cell.v)), out); const _89: rs.u32[] = [rs.u32Add(n, 3), rs.u32Add(n, 4)]; rs.sliceSet(rs.cellArray(cell, rs.sliceFrom), _89); const p: rs.Slice = rs.cellArray(cell, rs.sliceFrom); p.data[p.start + 1] = rs.u32Add(n, 5); - const pointer3 = rs.cellArray(cell, rs.sliceFrom); - rs.sliceSet(pointer3, ((_29: rs.u32[]): rs.u32[] => { + const pointer4 = rs.cellArray(cell, rs.sliceFrom); + rs.sliceSet(pointer4, ((_29: rs.u32[]): rs.u32[] => { return [_29[1], _29[0]]; - })(rs.sliceToArray(pointer3))); + })(rs.sliceToArray(pointer4))); const value2 = Array.from({ length: 2 }, (): rs.u32 => { return 0; }); - const pointer4 = rs.cellArray(cell, rs.sliceFrom); - const old8 = rs.sliceCopy(pointer4); - rs.sliceSet(pointer4, value2); - putWords(rs.sliceFrom(old8), out); + const pointer5 = rs.cellArray(cell, rs.sliceFrom); + const old10 = rs.sliceCopy(pointer5); + rs.sliceSet(pointer5, value2); + putWords(rs.sliceFrom(old10), out); const _109: rs.Cell = rs.cellOfSlice(rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(rs.sliceFrom(names.items), 2), 0, 2))); const _110: rs.String[] = [rs.stringFrom("abc"), rs.stringNew()]; - const pointer5 = rs.cellArray(_109, rs.sliceFrom); - const old9 = rs.sliceCopy(pointer5, 1); - rs.sliceSet(pointer5, _110); - rs.iterExtendBytes(out, rs.iterMap(rs.iterMap(rs.iterSlice(old9), (a02: rs.String): rs.usize => { + const pointer6 = rs.cellArray(_109, rs.sliceFrom); + const old11 = rs.sliceCopy(pointer6, 1); + rs.sliceSet(pointer6, _110); + rs.iterExtendBytes(out, rs.iterMap(rs.iterMap(rs.iterSlice(old11), (a02: rs.String): rs.usize => { return a02.len; }), (l: rs.usize): rs.u8 => { return l & 0xff; @@ -3580,9 +3580,9 @@ export function arrayParts(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): vo slice3.data[slice3.start + 1] = _141; const _147: rs.u32[][] = [[n, rs.u32Add(n, 7)], [rs.u32Add(n, 8), n]]; const pointer = rs.cellArray(cell3, rs.arraySliceOf(rs.sliceFrom)); - const old6 = rs.arraySliceCopy(pointer); + const old7 = rs.arraySliceCopy(pointer); rs.arraySliceSet(pointer, _147); - rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(old6, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_25: rs.u32): rs.u8 => { + rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(old7, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_25: rs.u32): rs.u8 => { return _25 & 0xff; }), undefined, true); const cell4: rs.Cell = rs.cellOfArraySlice(rs.optionUnwrap(rs.arraySliceGetRange(rs.arraySliceRange(rs.arraySliceFrom(rows.items, rs.sliceFrom), 0, 2), 0, 2))); @@ -3599,28 +3599,37 @@ export function arrayParts(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): vo rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rs.arraySliceToArray(p3, rs.sliceToArray), rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_26: rs.u32): rs.u8 => { return _26 & 0xff; }), undefined, true); + const pinned: [rs.u8, rs.u8] = [n & 0xff, 1]; + const at: [rs.u8, rs.u8] = pinned; + const boxes: rs.Cell<[rs.u8, rs.u8][][]> = new rs.Cell([[pinned]]); + const _209: [rs.u8, rs.u8][][] = [[[2, n & 0xff] as [rs.u8, rs.u8]]]; + const pointer2 = rs.cellArray(boxes, rs.arraySliceOf(rs.sliceFrom)); + const old8 = rs.arraySliceCopy(pointer2, rs.objectCopy); + rs.arraySliceSet(pointer2, _209); + const old6: [rs.u8, rs.u8] = old8[0][0]; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(at === old6 ? 1 : 0, old6[0])), undefined, true); } else { - const _199: [rs.Slice, rs.Slice] = rs.optionUnwrap(rs.sliceSplitAtChecked(rs.sliceRange(rs.sliceFrom(words.items), 1), 2)); - rs.idx(_199[1], 0); - _199[1].data[_199[1].start] = n; - let kept: rs.Slice | undefined = _199[0]; - const _209: rs.Place> | undefined = kept === undefined ? undefined : rs.place(() => kept as rs.Slice, (value) => kept = value); - if (_209 !== undefined) { - const _213: rs.u32 = rs.u32Add(n, 1); - const _258: rs.Slice = _209.v; - _258.data[_258.start] = _213; + const _226: [rs.Slice, rs.Slice] = rs.optionUnwrap(rs.sliceSplitAtChecked(rs.sliceRange(rs.sliceFrom(words.items), 1), 2)); + rs.idx(_226[1], 0); + _226[1].data[_226[1].start] = n; + let kept: rs.Slice | undefined = _226[0]; + const _236: rs.Place> | undefined = kept === undefined ? undefined : rs.place(() => kept as rs.Slice, (value) => kept = value); + if (_236 !== undefined) { + const _240: rs.u32 = rs.u32Add(n, 1); + const _285: rs.Slice = _236.v; + _285.data[_285.start] = _240; } option_map$0cigbgc(kept, (a4: rs.Slice): undefined => { a4.data[a4.start + 1] = rs.u32Add(n, 2); }); const v: rs.Vec> = new rs.Vec(); - const _223: [rs.Slice, rs.Slice] = rs.sliceSplitAt(rs.sliceFrom(words.items), 2); - const _228: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(_223[1], 0, 2)); - v.items.push(_228); - const _232: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(_223[0], 0, 2)); - v.items.push(_232); - for (const _237 of v.items) { - rs.sliceSwap(_237, 0, 1); + const _250: [rs.Slice, rs.Slice] = rs.sliceSplitAt(rs.sliceFrom(words.items), 2); + const _255: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(_250[1], 0, 2)); + v.items.push(_255); + const _259: rs.Slice = rs.optionUnwrap(rs.sliceGetRange(_250[0], 0, 2)); + v.items.push(_259); + for (const _264 of v.items) { + rs.sliceSwap(_264, 0, 1); } } putWords(rs.sliceFrom(words.items), out); @@ -3629,8 +3638,8 @@ export function arrayParts(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): vo }), (l3: rs.usize): rs.u8 => { return l3 & 0xff; }), undefined, true); - rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rows.items, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_210: rs.u32): rs.u8 => { - return _210 & 0xff; + rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rows.items, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_214: rs.u32): rs.u8 => { + return _214 & 0xff; }), undefined, true); } diff --git a/ts/fixtures/lang/slices/src/slices.rs b/ts/fixtures/lang/slices/src/slices.rs index ba7e753b3..614147fee 100644 --- a/ts/fixtures/lang/slices/src/slices.rs +++ b/ts/fixtures/lang/slices/src/slices.rs @@ -1814,8 +1814,8 @@ fn put_words(words: &[u32], out: &mut Vec) { /// A `&mut [T; N]` to part of a slice, of numbers, of strings, and of arrays, written whole: /// by `mem::replace` and `mem::swap`, and through a `Cell` and an `UnsafeCell` of it, each -/// way a cell reads, writes, and points at it; a cell of arrays pointed at before a write; -/// and one std holds in an `Option` and a `Vec` and writes through. +/// way a cell reads, writes, and points at it; a cell of arrays pointed at before a write, +/// and of pinned boxes, whose replacement keeps their allocations; and one std holds in an `Option` and a `Vec` and writes through. pub fn array_parts(kind: u8, data: &[u8], out: &mut Vec) { use std::cell::{Cell, UnsafeCell}; let mut words: Vec = data.iter().map(|&b| u32::from(b)).collect(); @@ -1872,6 +1872,11 @@ pub fn array_parts(kind: u8, data: &[u8], out: &mut Vec) { let p = held.as_ptr(); held.set([[3, n], [n, 4]]); out.extend(unsafe { *p }.iter().flatten().map(|&w| w as u8)); + let pinned = Box::pin((n as u8, 1)); + let at: *const (u8, u8) = &*pinned; + let boxes = Cell::new([[pinned]]); + let [[old]] = boxes.replace([[Box::pin((2, n as u8))]]); + out.extend([u8::from(std::ptr::eq(at, &*old)), old.0]); } _ => { let (a, b) = words[1..].split_first_chunk_mut::<2>().unwrap(); diff --git a/ts/fixtures/reject/census.txt b/ts/fixtures/reject/census.txt index b03a983c6..c5cd573e3 100644 --- a/ts/fixtures/reject/census.txt +++ b/ts/fixtures/reject/census.txt @@ -32,6 +32,8 @@ fixtures/reject/src/alloc.rs:cell_raw_unknown+9:13: `UnsafeCell::raw_get` of a p fixtures/reject/src/alloc.rs:pinned_lent+1:32: `UnsafeCell::get_mut` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:pinned_lent+2:43: `UnsafeCell::as_mut_unchecked` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:reinterpreted+1:27: a cast from a pointer to `u32` to one to `u8`, which reads the bytes of one type as another +fixtures/reject/src/alloc.rs:uninit_array_lent+1:25: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_lent+2:59: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet fixtures/reject/src/alloc.rs:uninit_cell_lent+2:17: `MaybeUninit::assume_init_mut` of `std::cell::UnsafeCell`, whose mutable reference is the object, but the uninitialized value's is the place it is kept in fixtures/reject/src/alloc.rs:vec_pointer+1:10: a raw pointer to `std::vec::Vec` behind a reference, which is the object and not where it is kept fixtures/reject/src/alloc.rs:wrapped_cells+8:19: a whole write of `std::mem::MaybeUninit<(std::cell::UnsafeCell, u32)>`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds diff --git a/ts/fixtures/reject/expected.txt b/ts/fixtures/reject/expected.txt index 46f587f99..9e571ff08 100644 --- a/ts/fixtures/reject/expected.txt +++ b/ts/fixtures/reject/expected.txt @@ -36,6 +36,8 @@ fixtures/reject/src/alloc.rs:cell_raw_unknown+9:13: `UnsafeCell::raw_get` of a p fixtures/reject/src/alloc.rs:pinned_lent+1:32: `UnsafeCell::get_mut` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:pinned_lent+2:43: `UnsafeCell::as_mut_unchecked` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:reinterpreted+1:27: a cast from a pointer to `u32` to one to `u8`, which reads the bytes of one type as another +fixtures/reject/src/alloc.rs:uninit_array_lent+1:25: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_lent+2:59: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet fixtures/reject/src/alloc.rs:uninit_cell_lent+2:17: `MaybeUninit::assume_init_mut` of `std::cell::UnsafeCell`, whose mutable reference is the object, but the uninitialized value's is the place it is kept in fixtures/reject/src/alloc.rs:vec_pointer+1:10: a raw pointer to `std::vec::Vec` behind a reference, which is the object and not where it is kept fixtures/reject/src/alloc.rs:wrapped_cells+8:19: a whole write of `std::mem::MaybeUninit<(std::cell::UnsafeCell, u32)>`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds diff --git a/ts/fixtures/reject/src/alloc.rs b/ts/fixtures/reject/src/alloc.rs index dd8887296..454179a52 100644 --- a/ts/fixtures/reject/src/alloc.rs +++ b/ts/fixtures/reject/src/alloc.rs @@ -146,6 +146,14 @@ pub fn cell_of_arrays() -> u16 { x.into_inner()[0][0] ^ v.into_inner()[0] as u16 } +/// `as_mut` and `NonNull::as_mut` of a pointer to an array a `MaybeUninit` holds, whose +/// mutable reference is the array, which part of an array has none of its own. +pub fn uninit_array_lent(p: *mut std::mem::MaybeUninit<[u32; 2]>) -> u32 { + let first = unsafe { p.as_mut() }.map_or(0, |m| unsafe { m.assume_init_mut()[0] }); + let second = unsafe { std::ptr::NonNull::new(p).unwrap().as_mut().assume_init_mut()[1] }; + first ^ second +} + /// A `get_mut` and an `as_mut_unchecked` of a cell of a pinned `Box`, whose old value /// `mem::replace` would give back as a copy. pub fn pinned_lent(c: &mut std::cell::UnsafeCell>>) -> u8 { diff --git a/ts/fixtures/reject/ts.toml b/ts/fixtures/reject/ts.toml index 349e707a4..7f1ea5216 100644 --- a/ts/fixtures/reject/ts.toml +++ b/ts/fixtures/reject/ts.toml @@ -12,6 +12,7 @@ roots = [ "alloc::cell_raw_unknown", "alloc::pinned_lent", "alloc::reinterpreted", + "alloc::uninit_array_lent", "alloc::uninit_cell_lent", "alloc::vec_pointer", "alloc::wrapped_cells", diff --git a/ts/runtime/rs.ts b/ts/runtime/rs.ts index 4217d00d1..c29a4f97d 100644 --- a/ts/runtime/rs.ts +++ b/ts/runtime/rs.ts @@ -915,15 +915,23 @@ export function sliceReplaceAll(s: Slice, items: ArrayLike, depth = 0): } /** - * `Box::from_raw` of a `*mut [T; N]`, `s`, the slice of its elements or of its arrays: the - * array `Box::into_raw` made all of it of, since a box owns all of its allocation. + * `Box::from_raw` of a `*mut [T; N]`, `s`, the slice of its elements or of its arrays, which + * must point at all of an allocation, as a box owns all of its own: the array it is, or the + * arrays of one `as_chunks` split, each made an array of its own, which the box alone holds. */ export function boxArrayFromRaw(s: Slice): T[]; export function boxArrayFromRaw(s: ArraySlice): LentArray[]; export function boxArrayFromRaw(s: Slice | ArraySlice): unknown[] { - const items = s instanceof Slice ? s.data : s instanceof ArraySlice ? s.items : undefined; - const all = items !== undefined && s.start === 0 && s.length === items.length; - return precondition(all ? (items as unknown[]) : undefined, "Box::from_raw requires a pointer Box::into_raw gave"); + precondition(s instanceof Slice || s instanceof ArraySlice ? arrayRefAll(s) || undefined : undefined, "Box::from_raw requires a pointer Box::into_raw gave"); + if (s instanceof Slice) return s.data; + return s.items !== undefined ? (s.items as unknown[]) : arraySliceCopy(s); +} + +/** Whether `s`, a slice a pointer to an array is, spans all of the storage it is of. */ +function arrayRefAll(s: ArrayRef): boolean { + if (!(s instanceof ArraySlice)) return s.start === 0 && s.length === s.data.length; + if (s.items !== undefined) return s.start === 0 && s.length === s.items.length; + return arrayRefAll(arrayRefPart(s.flat as ArrayRef, s.start * s.n, s.length * s.n)); } /** @@ -1215,11 +1223,16 @@ function arrayRefSet(s: ArrayRef, value: unknown): void { /** * The array `s` as a `[T; N]` of its own: a copy of its elements, and of the arrays it holds at * any depth, but not of the objects its elements are, which a write of it moves, unless - * `copy` copies them. + * `copy` copies them. `objectCopy`, of an object a write lands in, copies only where one does, + * in an array of one `sliceIn` or `sliceOfPlace` made, as a write elsewhere puts another + * object in the element's place and leaves the old one, such as a pinned `Box`, where it is. */ function arrayRefCopy(s: S, copy?: ElemCopy): LentArray { if (s instanceof ByteSlice) return byteSliceToArray(s) as LentArray; - if (s instanceof Slice) return sliceToArray(s, copy as ((value: unknown) => unknown) | undefined) as LentArray; + if (s instanceof Slice) { + const each = copy === objectCopy && !ONE.has(s.data) ? undefined : copy; + return sliceToArray(s, each as ((value: unknown) => unknown) | undefined) as LentArray; + } return arraySliceCopy(s as ArraySlice, copy) as LentArray; } diff --git a/ts/src/lower/pointer.rs b/ts/src/lower/pointer.rs index 424d4d86e..4bfe49cfe 100644 --- a/ts/src/lower/pointer.rs +++ b/ts/src/lower/pointer.rs @@ -580,6 +580,23 @@ pub fn call<'tcx>( ty::Array(elem, _) => super::slice_items_from(e, *elem), _ => super::library::slice_from(e), }; + // A reference to the array a pointer points at: the slice the pointer is, or for one a + // `MaybeUninit` or `ManuallyDrop` holds, whose reference is the array, as a reborrow of + // `*p` makes it: a view of bytes, a shared one the array where the slice is all of it, and + // a mutable one refused, as part of an array has no JS array of its own to write through. + let to_reference = |b: &mut Body<'_, '_, 'tcx>, p: Expr, shared: bool| { + let ty = pointee(); + let inner = b.t.uninit_inner(ty); + match inner.kind() { + _ if inner == ty => p, + _ if super::byte_array(inner) => Expr::rs("byteSliceView", vec![p]), + ty::Array(elem, _) if shared => super::library::items_of(p, *elem), + _ => b.err( + span, + format!("a mutable reborrow of `{ty}` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet"), + ), + } + }; // A raw pointer to a slice, from a reference to one, and the slice a read through it // makes, shared if nothing writes through it. let raw_of = |ty: Ty<'tcx>, s: Expr| match ty { @@ -655,8 +672,10 @@ pub fn call<'tcx>( ("NonNull", "as_ref" | "as_mut") if kind(b, pointee()) == Some(Pointee::Slice) => { deref(pointee(), arg(), name == "as_ref") } - // A reference to an array is the slice a pointer to it is, which `lend` leaves as it is. - ("NonNull", "as_mut") if array(b, pointee()) => arg(), + ("NonNull", "as_mut") if array(b, pointee()) => { + let p = arg(); + to_reference(b, p, false) + } // A `&mut` to a `MaybeUninit` of a cell of a value JS copies is the place the cell is // kept in, but one to the cell is the cell. ("MaybeUninit", "assume_init_mut") @@ -732,6 +751,16 @@ pub fn call<'tcx>( let shared = name == "as_ref" && kind(b, pointee()) == Some(super::pointer::Pointee::Place); let (some, none) = match shared { true => (p.clone().member("v"), b.t.none(pointee())), + // The `None` of an `Option` of the reference, which may be `rs.None` where the + // reference is the array a `MaybeUninit` holds. + false if array(b, pointee()) => { + let lent = b.t.sig(call.def_id, gargs).output(); + let none = match lent.kind() { + ty::Adt(_, args) => b.t.none(args.type_at(0)), + _ => Expr::undefined(), + }; + (to_reference(b, p.clone(), name == "as_ref"), none) + } false => (p.clone(), Expr::undefined()), }; Expr::Cond( @@ -742,6 +771,10 @@ pub fn call<'tcx>( } ("NonNull", "as_ref") | ("MaybeUninit", "assume_init_ref") => match kind(b, pointee()) { Some(Pointee::Place) if owner == "NonNull" => arg().member("v"), + Some(Pointee::Array) if owner == "NonNull" => { + let p = arg(); + to_reference(b, p, true) + } _ => arg(), }, // An `rs.Arc` is its allocation, which has one place of its value: the pointer to a @@ -982,9 +1015,10 @@ pub fn call<'tcx>( } // What `get` points at, lent as `get_mut` lends it. ("UnsafeCell" | "Cell", "get_mut") | ("UnsafeCell", "as_mut_unchecked") if b.t.needs_place(pointee()) => arg(), - // The pointer `get` gives to an array is the reference to it, which `lend` leaves as it is. + // The pointer `get` gives to an array is the reference to it, which `lend` leaves as it + // is; one a `MaybeUninit` holds is the array, which the cell holds. ("UnsafeCell", "get_mut" | "as_ref_unchecked" | "as_mut_unchecked") | ("Cell", "get_mut") - if kind(b, pointee()) == Some(Pointee::Array) => + if pointee().is_array() => { let cell = arg(); cell_pointer(b, cell, pointee()) From 7c8cff13cba6ae3663d2c79a7fdf390c0992ba29 Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Sat, 7 Nov 2026 15:28:59 -0800 Subject: [PATCH 06/12] fix(ts): refuse comparing wrapped array pointers and boxing arrays of arrays A shared reference through a raw pointer to part of an array a `MaybeUninit` holds is a copy, so comparing pointers to such arrays is refused; and `Box::from_raw` of arrays of arrays stays refused, as arrays `as_chunks` split from one flat array have none of their own to box. Co-Authored-By: Claude Opus 5.5 --- .../lang/pointers/expected/pointers.ts | 50 +++++++------------ ts/fixtures/lang/pointers/src/pointers.rs | 14 +----- ts/fixtures/reject/census.txt | 2 + ts/fixtures/reject/expected.txt | 2 + ts/fixtures/reject/src/alloc.rs | 12 +++++ ts/fixtures/reject/ts.toml | 1 + ts/runtime/rs.ts | 21 ++------ ts/src/lower/pointer.rs | 13 ++++- 8 files changed, 54 insertions(+), 61 deletions(-) diff --git a/ts/fixtures/lang/pointers/expected/pointers.ts b/ts/fixtures/lang/pointers/expected/pointers.ts index 91bd759df..dacc53473 100644 --- a/ts/fixtures/lang/pointers/expected/pointers.ts +++ b/ts/fixtures/lang/pointers/expected/pointers.ts @@ -4079,8 +4079,7 @@ export function tripled(b: rs.u8): rs.u8 { /** * A raw pointer to a `[T; N]` and to a `[[T; N]; M]` that is part of a slice, lent back as * a reference by `as_mut` and `NonNull::as_mut`, and the first written whole by - * `ptr::replace` and `ptr::swap`; a box of each taken back by `Box::from_raw`, and of arrays - * `as_chunks_mut` split from all of a box's array; and arrays a + * `ptr::replace` and `ptr::swap` and taken back as a box by `Box::from_raw`; and arrays a * `MaybeUninit` holds, lent by `as_ref` and by a cell's `get_mut` and `as_mut_unchecked`. */ export function arrayParts(data: rs.ByteSlice, out: rs.ByteVec): void { @@ -4142,47 +4141,36 @@ export function arrayParts(data: rs.ByteSlice, out: rs.ByteVec): void { const _100: rs.u32 = rs.u32Add(n, 5); const slice7 = rs.arraySliceAt(nn2, 0); slice7.data[slice7.start + 1] = _100; - rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rows.items, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_213: rs.u32): rs.u8 => { - return _213 & 0xff; - }), undefined, true); - const raw2: rs.ArraySlice> = rs.arraySliceFrom([[n, 1], [2, n]], rs.sliceFrom); - const slice8 = rs.arraySliceAt(raw2, 1); - slice8.data[slice8.start + 1] = 8; - rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rs.boxArrayFromRaw(raw2), rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_218: rs.u32): rs.u8 => { - return _218 & 0xff; - }), undefined, true); - const back3: rs.u32[][] = rs.boxArrayFromRaw(rs.optionUnwrap(rs.arraySliceGetRange(rs.sliceAsChunks(rs.sliceFrom([n, 1, 2, rs.u32Add(n, 3)]), 2)[0], 0, 2))); - back3[1][0] = 9; - rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(back3, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_219: rs.u32): rs.u8 => { - return _219 & 0xff; + rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rows.items, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_212: rs.u32): rs.u8 => { + return _212 & 0xff; }), undefined, true); const p4: rs.Slice = rs.sliceFrom([n, 1]); const pointer5 = p4; - const _156: rs.u32[] | rs.None = pointer5 === rs.NULL ? rs.None : rs.sliceItems(pointer5); - if (_156 !== rs.None) { - const _162: rs.Slice = rs.sliceFrom(_156); - rs.byteVecPush(out, _162.data[_162.start] & 0xff); + const _117: rs.u32[] | rs.None = pointer5 === rs.NULL ? rs.None : rs.sliceItems(pointer5); + if (_117 !== rs.None) { + const _123: rs.Slice = rs.sliceFrom(_117); + rs.byteVecPush(out, _123.data[_123.start] & 0xff); } const pointer6 = p4; - const _171: rs.Slice = rs.sliceFrom(rs.sliceItems(rs.optionUnwrap(pointer6 === rs.NULL ? undefined : pointer6))); - rs.byteVecPush(out, _171.data[_171.start + 1] & 0xff); + const _132: rs.Slice = rs.sliceFrom(rs.sliceItems(rs.optionUnwrap(pointer6 === rs.NULL ? undefined : pointer6))); + rs.byteVecPush(out, _132.data[_132.start + 1] & 0xff); const pointer7 = rs.byteSliceFrom(Uint8Array.of(n & 0xff, 5)); rs.iterExtendBytes(out, rs.iterSlice(option_mapOr$0m14xib(pointer7 === rs.NULL ? rs.None : rs.byteSliceView(pointer7), rs.bytes(2), (m: Uint8Array): Uint8Array => { return copy$mem_MaybeUninit_array_u8(m); })), undefined, true); const cell: rs.Cell = new rs.Cell(copy$mem_MaybeUninit_array_u8(Uint8Array.of(n & 0xff, 2))); - const _189: rs.ByteSlice = rs.byteSliceFrom(cell.v); - _189.data[_189.start + 1] = 9; + const _150: rs.ByteSlice = rs.byteSliceFrom(cell.v); + _150.data[_150.start + 1] = 9; rs.iterExtendBytes(out, rs.iterSlice(cell.v), undefined, true); const uc: rs.Cell = new rs.Cell(copy$mem_MaybeUninit_array_u32([n, 3])); - const _201: rs.u32 = rs.u32Add(n, 8); - const _202: rs.Slice = rs.sliceFrom(uc.v); - _202.data[_202.start] = _201; - const _207: rs.u32 = rs.u32Add(n, 9); - const _208: rs.Slice = rs.sliceFrom(uc.v); - _208.data[_208.start + 1] = _207; - rs.iterExtendBytes(out, rs.iterSlice(rs.bytesMap(uc.v, (w7: rs.u32): rs.u8 => { - return w7 & 0xff; + const _162: rs.u32 = rs.u32Add(n, 8); + const _163: rs.Slice = rs.sliceFrom(uc.v); + _163.data[_163.start] = _162; + const _168: rs.u32 = rs.u32Add(n, 9); + const _169: rs.Slice = rs.sliceFrom(uc.v); + _169.data[_169.start + 1] = _168; + rs.iterExtendBytes(out, rs.iterSlice(rs.bytesMap(uc.v, (w5: rs.u32): rs.u8 => { + return w5 & 0xff; })), undefined, true); } diff --git a/ts/fixtures/lang/pointers/src/pointers.rs b/ts/fixtures/lang/pointers/src/pointers.rs index c09da2ea0..dbe17b349 100644 --- a/ts/fixtures/lang/pointers/src/pointers.rs +++ b/ts/fixtures/lang/pointers/src/pointers.rs @@ -3037,8 +3037,7 @@ fn tripled(mut b: u8) -> u8 { /// A raw pointer to a `[T; N]` and to a `[[T; N]; M]` that is part of a slice, lent back as /// a reference by `as_mut` and `NonNull::as_mut`, and the first written whole by -/// `ptr::replace` and `ptr::swap`; a box of each taken back by `Box::from_raw`, and of arrays -/// `as_chunks_mut` split from all of a box's array; and arrays a +/// `ptr::replace` and `ptr::swap` and taken back as a box by `Box::from_raw`; and arrays a /// `MaybeUninit` holds, lent by `as_ref` and by a cell's `get_mut` and `as_mut_unchecked`. pub fn array_parts(data: &[u8], out: &mut Vec) { let n = data.first().map_or(0, |&b| u32::from(b)); @@ -3071,17 +3070,6 @@ pub fn array_parts(data: &[u8], out: &mut Vec) { let mut nn = NonNull::new(p).unwrap(); unsafe { nn.as_mut()[0][1] = n + 5 }; out.extend(rows.iter().flatten().map(|&w| w as u8)); - let raw = Box::into_raw(Box::new([[n, 1], [2, n]])); - unsafe { (*raw)[1][1] = 8 }; - let back = unsafe { Box::from_raw(raw) }; - out.extend(back.iter().flatten().map(|&w| w as u8)); - // Arrays `as_chunks_mut` split from all of a box's array, which has their layout. - let flat = Box::into_raw(Box::new([n, 1, 2, n + 3])); - let (runs, _) = unsafe { (*flat).as_chunks_mut::<2>() }; - let whole: *mut [[u32; 2]; 2] = runs.first_chunk_mut().unwrap(); - let mut back = unsafe { Box::from_raw(whole) }; - back[1][0] = 9; - out.extend(back.iter().flatten().map(|&w| w as u8)); // Of arrays a `MaybeUninit` holds, whose reference is the array. let mu = MaybeUninit::new([n, 1]); let p: *const MaybeUninit<[u32; 2]> = μ diff --git a/ts/fixtures/reject/census.txt b/ts/fixtures/reject/census.txt index c5cd573e3..fffa616d7 100644 --- a/ts/fixtures/reject/census.txt +++ b/ts/fixtures/reject/census.txt @@ -32,6 +32,8 @@ fixtures/reject/src/alloc.rs:cell_raw_unknown+9:13: `UnsafeCell::raw_get` of a p fixtures/reject/src/alloc.rs:pinned_lent+1:32: `UnsafeCell::get_mut` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:pinned_lent+2:43: `UnsafeCell::as_mut_unchecked` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:reinterpreted+1:27: a cast from a pointer to `u32` to one to `u8`, which reads the bytes of one type as another +fixtures/reject/src/alloc.rs:uninit_array_compared+5:22: `Box::from_raw` of `[[u32; 2]; 2]`, which may be arrays `as_chunks` split from one flat array, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_compared+6:2: comparing pointers to `std::mem::MaybeUninit<[u32; 2]>`, an array a `MaybeUninit` or `ManuallyDrop` holds, whose shared reference through a raw pointer to part of an array is a copy fixtures/reject/src/alloc.rs:uninit_array_lent+1:25: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet fixtures/reject/src/alloc.rs:uninit_array_lent+2:59: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet fixtures/reject/src/alloc.rs:uninit_cell_lent+2:17: `MaybeUninit::assume_init_mut` of `std::cell::UnsafeCell`, whose mutable reference is the object, but the uninitialized value's is the place it is kept in diff --git a/ts/fixtures/reject/expected.txt b/ts/fixtures/reject/expected.txt index 9e571ff08..020665ada 100644 --- a/ts/fixtures/reject/expected.txt +++ b/ts/fixtures/reject/expected.txt @@ -36,6 +36,8 @@ fixtures/reject/src/alloc.rs:cell_raw_unknown+9:13: `UnsafeCell::raw_get` of a p fixtures/reject/src/alloc.rs:pinned_lent+1:32: `UnsafeCell::get_mut` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:pinned_lent+2:43: `UnsafeCell::as_mut_unchecked` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:reinterpreted+1:27: a cast from a pointer to `u32` to one to `u8`, which reads the bytes of one type as another +fixtures/reject/src/alloc.rs:uninit_array_compared+5:22: `Box::from_raw` of `[[u32; 2]; 2]`, which may be arrays `as_chunks` split from one flat array, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_compared+6:2: comparing pointers to `std::mem::MaybeUninit<[u32; 2]>`, an array a `MaybeUninit` or `ManuallyDrop` holds, whose shared reference through a raw pointer to part of an array is a copy fixtures/reject/src/alloc.rs:uninit_array_lent+1:25: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet fixtures/reject/src/alloc.rs:uninit_array_lent+2:59: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet fixtures/reject/src/alloc.rs:uninit_cell_lent+2:17: `MaybeUninit::assume_init_mut` of `std::cell::UnsafeCell`, whose mutable reference is the object, but the uninitialized value's is the place it is kept in diff --git a/ts/fixtures/reject/src/alloc.rs b/ts/fixtures/reject/src/alloc.rs index 454179a52..6f9544799 100644 --- a/ts/fixtures/reject/src/alloc.rs +++ b/ts/fixtures/reject/src/alloc.rs @@ -154,6 +154,18 @@ pub fn uninit_array_lent(p: *mut std::mem::MaybeUninit<[u32; 2]>) -> u32 { first ^ second } +/// Pointers to an array a `MaybeUninit` holds compared, one a shared reference through a +/// raw pointer may make a copy of; and `Box::from_raw` of arrays `as_chunks_mut` split from +/// one flat array, which a box of arrays of their own can't share. +pub fn uninit_array_compared(p: *const std::mem::MaybeUninit<[u32; 2]>) -> bool { + let r = unsafe { p.as_ref() }.unwrap(); + let flat = Box::into_raw(Box::new([1u32, 2, 3, 4])); + let (runs, _) = unsafe { (*flat).as_chunks_mut::<2>() }; + let whole: *mut [[u32; 2]; 2] = runs.first_chunk_mut().unwrap(); + let back = unsafe { Box::from_raw(whole) }; + std::ptr::eq(p, r) && back[0][0] == 1 +} + /// A `get_mut` and an `as_mut_unchecked` of a cell of a pinned `Box`, whose old value /// `mem::replace` would give back as a copy. pub fn pinned_lent(c: &mut std::cell::UnsafeCell>>) -> u8 { diff --git a/ts/fixtures/reject/ts.toml b/ts/fixtures/reject/ts.toml index 7f1ea5216..c74ea12c0 100644 --- a/ts/fixtures/reject/ts.toml +++ b/ts/fixtures/reject/ts.toml @@ -12,6 +12,7 @@ roots = [ "alloc::cell_raw_unknown", "alloc::pinned_lent", "alloc::reinterpreted", + "alloc::uninit_array_compared", "alloc::uninit_array_lent", "alloc::uninit_cell_lent", "alloc::vec_pointer", diff --git a/ts/runtime/rs.ts b/ts/runtime/rs.ts index c29a4f97d..177a9c031 100644 --- a/ts/runtime/rs.ts +++ b/ts/runtime/rs.ts @@ -915,23 +915,12 @@ export function sliceReplaceAll(s: Slice, items: ArrayLike, depth = 0): } /** - * `Box::from_raw` of a `*mut [T; N]`, `s`, the slice of its elements or of its arrays, which - * must point at all of an allocation, as a box owns all of its own: the array it is, or the - * arrays of one `as_chunks` split, each made an array of its own, which the box alone holds. + * `Box::from_raw` of a `*mut [T; N]`, `s`: the array `Box::into_raw` pointed at all of, as a + * box owns all of its allocation. */ -export function boxArrayFromRaw(s: Slice): T[]; -export function boxArrayFromRaw(s: ArraySlice): LentArray[]; -export function boxArrayFromRaw(s: Slice | ArraySlice): unknown[] { - precondition(s instanceof Slice || s instanceof ArraySlice ? arrayRefAll(s) || undefined : undefined, "Box::from_raw requires a pointer Box::into_raw gave"); - if (s instanceof Slice) return s.data; - return s.items !== undefined ? (s.items as unknown[]) : arraySliceCopy(s); -} - -/** Whether `s`, a slice a pointer to an array is, spans all of the storage it is of. */ -function arrayRefAll(s: ArrayRef): boolean { - if (!(s instanceof ArraySlice)) return s.start === 0 && s.length === s.data.length; - if (s.items !== undefined) return s.start === 0 && s.length === s.items.length; - return arrayRefAll(arrayRefPart(s.flat as ArrayRef, s.start * s.n, s.length * s.n)); +export function boxArrayFromRaw(s: Slice): T[] { + const all = s instanceof Slice && s.start === 0 && s.length === s.data.length; + return precondition(all ? s.data : undefined, "Box::from_raw requires a pointer Box::into_raw gave"); } /** diff --git a/ts/src/lower/pointer.rs b/ts/src/lower/pointer.rs index 4bfe49cfe..ced150d85 100644 --- a/ts/src/lower/pointer.rs +++ b/ts/src/lower/pointer.rs @@ -122,6 +122,12 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { "comparing pointers to `{ty}`, each an object JS makes of its own as it unsizes" )); } + let inner = self.uninit_inner(ty); + if self.pointee(ty) == Pointee::Array && inner != ty && !super::byte_array(inner) { + return Some(format!( + "comparing pointers to `{ty}`, an array a `MaybeUninit` or `ManuallyDrop` holds, whose shared reference through a raw pointer to part of an array is a copy" + )); + } match self.pointee(ty) { // `from_ref`, `from_mut` of a variable, and `Option::as_slice` make an array of // one of their own for a value, so only longer arrays are always where Rust's are. @@ -846,9 +852,14 @@ pub fn call<'tcx>( ("Box", "from_raw") => match kind(b, pointee()) { Some(Pointee::Slice) => deref(pointee(), arg(), false), Some(Pointee::Place) => arg().member("v"), - // A box of an array is the array, all of which `into_raw` pointed at. + // A box of an array is the array, all of which `into_raw` pointed at. Arrays + // `as_chunks` split from one flat array have no array of their own to box. Some(Pointee::Array) => match b.t.uninit_inner(pointee()) { ty if super::byte_array(ty) => Expr::rs("byteSliceView", vec![arg()]), + ty if super::array_slice::of_arrays(ty) => b.err( + span, + format!("`Box::from_raw` of `{ty}`, which may be arrays `as_chunks` split from one flat array, which is not supported yet"), + ), _ => Expr::rs("boxArrayFromRaw", vec![arg()]), }, _ => arg(), From af5980dc4cf72f92e6ef438a2e35a628ae8cfd8a Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Sat, 7 Nov 2026 15:29:37 -0800 Subject: [PATCH 07/12] style(ts): format Co-Authored-By: Claude Opus 5.5 --- ts/src/lower/pointer.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ts/src/lower/pointer.rs b/ts/src/lower/pointer.rs index ced150d85..5a258e7ec 100644 --- a/ts/src/lower/pointer.rs +++ b/ts/src/lower/pointer.rs @@ -858,7 +858,9 @@ pub fn call<'tcx>( ty if super::byte_array(ty) => Expr::rs("byteSliceView", vec![arg()]), ty if super::array_slice::of_arrays(ty) => b.err( span, - format!("`Box::from_raw` of `{ty}`, which may be arrays `as_chunks` split from one flat array, which is not supported yet"), + format!( + "`Box::from_raw` of `{ty}`, which may be arrays `as_chunks` split from one flat array, which is not supported yet" + ), ), _ => Expr::rs("boxArrayFromRaw", vec![arg()]), }, From ed05c66244a690b4f2bc7bf49f78e94dd1f3625e Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Sat, 7 Nov 2026 15:30:37 -0800 Subject: [PATCH 08/12] fix(ts): census the Box::from_raw refusal verbatim Co-Authored-By: Claude Opus 5.5 --- ts/src/census.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ts/src/census.rs b/ts/src/census.rs index 958b34085..9a0c8c44b 100644 --- a/ts/src/census.rs +++ b/ts/src/census.rs @@ -144,6 +144,7 @@ const VERBATIM: &[&str] = &[ "?", "Arc", "Binary", + "Box::from_raw", "Buf::copy_to_bytes", "BufMut::put", "BytesMut", From 6109d021d3e2241c9d6dfb25a74c89d77c4d709d Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Sat, 7 Nov 2026 15:31:46 -0800 Subject: [PATCH 09/12] fix(ts): census as_chunks verbatim Co-Authored-By: Claude Opus 5.5 --- ts/src/census.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ts/src/census.rs b/ts/src/census.rs index 9a0c8c44b..4c2ea8b3e 100644 --- a/ts/src/census.rs +++ b/ts/src/census.rs @@ -182,6 +182,7 @@ const VERBATIM: &[&str] = &[ "Vec::splice", "alloc", "array::from_ref", + "as_chunks", "async", "async fn", "become", From 88d9999969a5b232e435953e0aea48b12a364c20 Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Sat, 7 Nov 2026 16:45:26 -0800 Subject: [PATCH 10/12] fix(ts)!: refuse reborrows of wrapped arrays through raw pointers A shared reference or as_ref through a raw pointer to an array a MaybeUninit or ManuallyDrop holds, of other than bytes, was a copy where the pointer points into part of an array, so assume_init_ref compared unequal where Rust's is equal. It is now refused, as the mutable one is, and pointer comparisons of such arrays are no longer refused. Co-Authored-By: Claude Opus 5.5 --- .../lang/pointers/expected/pointers.ts | 33 +++++++----------- ts/fixtures/lang/pointers/src/pointers.rs | 10 ++---- ts/fixtures/lang/slices/expected/slices.ts | 25 ++++++-------- ts/fixtures/lang/slices/src/slices.rs | 14 +------- ts/fixtures/reject/census.txt | 15 ++++---- ts/fixtures/reject/expected.txt | 11 +++--- ts/fixtures/reject/src/alloc.rs | 21 +++++++----- ts/fixtures/reject/ts.toml | 2 +- ts/src/lower/mir/rvalue.rs | 18 +++------- ts/src/lower/pointer.rs | 34 +++++++++---------- 10 files changed, 76 insertions(+), 107 deletions(-) diff --git a/ts/fixtures/lang/pointers/expected/pointers.ts b/ts/fixtures/lang/pointers/expected/pointers.ts index dacc53473..d5c373bf0 100644 --- a/ts/fixtures/lang/pointers/expected/pointers.ts +++ b/ts/fixtures/lang/pointers/expected/pointers.ts @@ -4080,7 +4080,8 @@ export function tripled(b: rs.u8): rs.u8 { * A raw pointer to a `[T; N]` and to a `[[T; N]; M]` that is part of a slice, lent back as * a reference by `as_mut` and `NonNull::as_mut`, and the first written whole by * `ptr::replace` and `ptr::swap` and taken back as a box by `Box::from_raw`; and arrays a - * `MaybeUninit` holds, lent by `as_ref` and by a cell's `get_mut` and `as_mut_unchecked`. + * `MaybeUninit` holds, lent by `as_ref` of bytes and by a cell's `get_mut` and + * `as_mut_unchecked`. */ export function arrayParts(data: rs.ByteSlice, out: rs.ByteVec): void { const n: rs.u32 = option_mapOr$1wlsr3s(rs.byteSliceFirst(data), 0, (_2: rs.u8): rs.u32 => { @@ -4144,31 +4145,21 @@ export function arrayParts(data: rs.ByteSlice, out: rs.ByteVec): void { rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rows.items, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_212: rs.u32): rs.u8 => { return _212 & 0xff; }), undefined, true); - const p4: rs.Slice = rs.sliceFrom([n, 1]); - const pointer5 = p4; - const _117: rs.u32[] | rs.None = pointer5 === rs.NULL ? rs.None : rs.sliceItems(pointer5); - if (_117 !== rs.None) { - const _123: rs.Slice = rs.sliceFrom(_117); - rs.byteVecPush(out, _123.data[_123.start] & 0xff); - } - const pointer6 = p4; - const _132: rs.Slice = rs.sliceFrom(rs.sliceItems(rs.optionUnwrap(pointer6 === rs.NULL ? undefined : pointer6))); - rs.byteVecPush(out, _132.data[_132.start + 1] & 0xff); - const pointer7 = rs.byteSliceFrom(Uint8Array.of(n & 0xff, 5)); - rs.iterExtendBytes(out, rs.iterSlice(option_mapOr$0m14xib(pointer7 === rs.NULL ? rs.None : rs.byteSliceView(pointer7), rs.bytes(2), (m: Uint8Array): Uint8Array => { + const pointer5 = rs.byteSliceFrom(Uint8Array.of(n & 0xff, 5)); + rs.iterExtendBytes(out, rs.iterSlice(option_mapOr$0m14xib(pointer5 === rs.NULL ? rs.None : rs.byteSliceView(pointer5), rs.bytes(2), (m: Uint8Array): Uint8Array => { return copy$mem_MaybeUninit_array_u8(m); })), undefined, true); const cell: rs.Cell = new rs.Cell(copy$mem_MaybeUninit_array_u8(Uint8Array.of(n & 0xff, 2))); - const _150: rs.ByteSlice = rs.byteSliceFrom(cell.v); - _150.data[_150.start + 1] = 9; + const _126: rs.ByteSlice = rs.byteSliceFrom(cell.v); + _126.data[_126.start + 1] = 9; rs.iterExtendBytes(out, rs.iterSlice(cell.v), undefined, true); const uc: rs.Cell = new rs.Cell(copy$mem_MaybeUninit_array_u32([n, 3])); - const _162: rs.u32 = rs.u32Add(n, 8); - const _163: rs.Slice = rs.sliceFrom(uc.v); - _163.data[_163.start] = _162; - const _168: rs.u32 = rs.u32Add(n, 9); - const _169: rs.Slice = rs.sliceFrom(uc.v); - _169.data[_169.start + 1] = _168; + const _138: rs.u32 = rs.u32Add(n, 8); + const _139: rs.Slice = rs.sliceFrom(uc.v); + _139.data[_139.start] = _138; + const _144: rs.u32 = rs.u32Add(n, 9); + const _145: rs.Slice = rs.sliceFrom(uc.v); + _145.data[_145.start + 1] = _144; rs.iterExtendBytes(out, rs.iterSlice(rs.bytesMap(uc.v, (w5: rs.u32): rs.u8 => { return w5 & 0xff; })), undefined, true); diff --git a/ts/fixtures/lang/pointers/src/pointers.rs b/ts/fixtures/lang/pointers/src/pointers.rs index dbe17b349..dde51b426 100644 --- a/ts/fixtures/lang/pointers/src/pointers.rs +++ b/ts/fixtures/lang/pointers/src/pointers.rs @@ -3038,7 +3038,8 @@ fn tripled(mut b: u8) -> u8 { /// A raw pointer to a `[T; N]` and to a `[[T; N]; M]` that is part of a slice, lent back as /// a reference by `as_mut` and `NonNull::as_mut`, and the first written whole by /// `ptr::replace` and `ptr::swap` and taken back as a box by `Box::from_raw`; and arrays a -/// `MaybeUninit` holds, lent by `as_ref` and by a cell's `get_mut` and `as_mut_unchecked`. +/// `MaybeUninit` holds, lent by `as_ref` of bytes and by a cell's `get_mut` and +/// `as_mut_unchecked`. pub fn array_parts(data: &[u8], out: &mut Vec) { let n = data.first().map_or(0, |&b| u32::from(b)); let mut words: Vec = data.iter().map(|&b| u32::from(b)).collect(); @@ -3071,13 +3072,6 @@ pub fn array_parts(data: &[u8], out: &mut Vec) { unsafe { nn.as_mut()[0][1] = n + 5 }; out.extend(rows.iter().flatten().map(|&w| w as u8)); // Of arrays a `MaybeUninit` holds, whose reference is the array. - let mu = MaybeUninit::new([n, 1]); - let p: *const MaybeUninit<[u32; 2]> = μ - if let Some(m) = unsafe { p.as_ref() } { - out.push(unsafe { m.assume_init_ref()[0] } as u8); - } - let nn = NonNull::new(p.cast_mut()).unwrap(); - out.push(unsafe { nn.as_ref().assume_init_ref()[1] } as u8); let bytes = MaybeUninit::new([n as u8, 5]); let p: *const MaybeUninit<[u8; 2]> = &bytes; out.extend(unsafe { p.as_ref() }.map_or([0; 2], |m| unsafe { m.assume_init() })); diff --git a/ts/fixtures/lang/slices/expected/slices.ts b/ts/fixtures/lang/slices/expected/slices.ts index ce6778ab1..ab1bb1ea1 100644 --- a/ts/fixtures/lang/slices/expected/slices.ts +++ b/ts/fixtures/lang/slices/expected/slices.ts @@ -3156,28 +3156,25 @@ export function arraySources(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): const row: (a0: rs.usize) => Uint8Array = (at: rs.usize): Uint8Array => { return option_unwrapOr$1la41a6(copy$Option_array2_u8(rs.optionMap(rs.arraySliceGet(rs.arraySliceFrom(rows.items, rs.byteSliceFrom), at), rs.byteSliceView)), rs.bytes(2).fill(at & 0xff)); }; - const grid: Uint8Array[] = [row(0), row(1), row(2)]; - const wrapped: Uint8Array[] = rs.arraySliceItems(rs.arraySliceFrom([Uint8Array.of(grid[2][1], grid[0][0]), Uint8Array.of(grid[1][0], grid[2][0]), Uint8Array.of(grid[0][1], grid[1][1]), copy$array_u8(grid[2])], rs.byteSliceFrom)); - rs.iterExtendBytes(out, rs.iterFlatten(rs.arraySliceIter(rs.arraySliceOf(rs.byteSliceFrom)(wrapped)), (value: rs.ByteSlice) => rs.iterSlice(rs.byteSliceView(value)), true, 2), undefined, true); - const cow: rs.Cow> = new rs.Borrowed(rs.arraySliceRange(rs.arraySliceFrom(grid, rs.byteSliceFrom), 1)); + const cow: rs.Cow> = new rs.Borrowed(rs.arraySliceRange(rs.arraySliceFrom([row(0), row(1), row(2)], rs.byteSliceFrom), 1)); if (cow instanceof rs.Borrowed) { - const _217: rs.u8 = (cow as rs.Borrowed>).slice.length & 0xff; + const _171: rs.u8 = (cow as rs.Borrowed>).slice.length & 0xff; rs.idx((cow as rs.Borrowed>).slice, 0); const slice2 = rs.arraySliceAt((cow as rs.Borrowed>).slice, 0); - const _219: rs.u8 = slice2.data[slice2.start]; - const _226: rs.usize = rs.usizeSub((cow as rs.Borrowed>).slice.length, 1); - rs.idx((cow as rs.Borrowed>).slice, _226); - const slice4 = rs.arraySliceAt((cow as rs.Borrowed>).slice, _226); - rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(_217, _219, slice4.data[slice4.start + 1])), undefined, true); + const _173: rs.u8 = slice2.data[slice2.start]; + const _180: rs.usize = rs.usizeSub((cow as rs.Borrowed>).slice.length, 1); + rs.idx((cow as rs.Borrowed>).slice, _180); + const slice4 = rs.arraySliceAt((cow as rs.Borrowed>).slice, _180); + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(_171, _173, slice4.data[slice4.start + 1])), undefined, true); } else { rs.byteVecPush(out, (cow as rs.Vec).items.length & 0xff); } } else { const leaked: rs.ArraySlice = rs.arraySliceFrom(rs.vecFrom(rows.items.map(copy$array_u8)).items, rs.byteSliceFrom); - const _240: rs.ByteSlice | undefined = rs.arraySliceFirst(leaked); - if (_240 !== undefined) { - const _243: rs.u8 = rs.u8WrappingAdd(_240.data[_240.start], 1); - _240.data[_240.start] = _243; + const _194: rs.ByteSlice | undefined = rs.arraySliceFirst(leaked); + if (_194 !== undefined) { + const _197: rs.u8 = rs.u8WrappingAdd(_194.data[_194.start], 1); + _194.data[_194.start] = _197; } rs.iterExtendBytes(out, rs.iterFlatten(rs.arraySliceIter(leaked), (value: rs.ByteSlice) => rs.iterSlice(rs.byteSliceView(value)), true, 2), undefined, true); } diff --git a/ts/fixtures/lang/slices/src/slices.rs b/ts/fixtures/lang/slices/src/slices.rs index 614147fee..302505b37 100644 --- a/ts/fixtures/lang/slices/src/slices.rs +++ b/ts/fixtures/lang/slices/src/slices.rs @@ -1613,22 +1613,10 @@ pub fn array_sources(kind: u8, data: &[u8], out: &mut Vec) { let shared: std::rc::Rc<[[u8; 2]]> = rows.clone().into(); out.extend(shared.iter().rev().flatten()); } - // A reborrow of a `MaybeUninit` of an array of arrays through a raw pointer, and a - // borrowed `Cow`'s, matched. + // A borrowed `Cow`'s, matched. 3 => { let row = |at: usize| rows.get(at).copied().unwrap_or([at as u8; 2]); let grid = [row(0), row(1), row(2)]; - let pairs = [ - [grid[2][1], grid[0][0]], - [grid[1][0], grid[2][0]], - [grid[0][1], grid[1][1]], - grid[2], - ]; - let p = (&pairs as *const [[u8; 2]; 4]).cast::>(); - // SAFETY: `p` points at `pairs`, which is initialized and outlives the borrow. - let wrapped = unsafe { &*p }; - // SAFETY: as above. - out.extend(unsafe { wrapped.assume_init_ref() }.iter().flatten()); let cow: std::borrow::Cow<'_, [[u8; 2]]> = std::borrow::Cow::Borrowed(&grid[1..]); match cow { std::borrow::Cow::Borrowed(rows) => out.extend([rows.len() as u8, rows[0][0], rows[rows.len() - 1][1]]), diff --git a/ts/fixtures/reject/census.txt b/ts/fixtures/reject/census.txt index fffa616d7..6e9570228 100644 --- a/ts/fixtures/reject/census.txt +++ b/ts/fixtures/reject/census.txt @@ -29,13 +29,16 @@ fixtures/reject/src/alloc.rs:cell_raw_unknown+5:15: `UnsafeCell::raw_get` of a p fixtures/reject/src/alloc.rs:cell_raw_unknown+6:3: `UnsafeCell::raw_get` of a pointer not made of a place of `std::cell::UnsafeCell`, such as a parameter, a vector's or a slice's, or one moved by arithmetic, which may point where no cell is fixtures/reject/src/alloc.rs:cell_raw_unknown+8:15: `UnsafeCell::raw_get` of a pointer not made of a place of `std::cell::UnsafeCell`, such as a parameter, a vector's or a slice's, or one moved by arithmetic, which may point where no cell is fixtures/reject/src/alloc.rs:cell_raw_unknown+9:13: `UnsafeCell::raw_get` of a pointer not made of a place of `std::cell::UnsafeCell`, such as a parameter, a vector's or a slice's, or one moved by arithmetic, which may point where no cell is +fixtures/reject/src/alloc.rs:flat_arrays_boxed+4:22: `Box::from_raw` of `[[u32; 2]; 2]`, which may be arrays `as_chunks` split from one flat array, which is not supported yet fixtures/reject/src/alloc.rs:pinned_lent+1:32: `UnsafeCell::get_mut` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:pinned_lent+2:43: `UnsafeCell::as_mut_unchecked` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:reinterpreted+1:27: a cast from a pointer to `u32` to one to `u8`, which reads the bytes of one type as another -fixtures/reject/src/alloc.rs:uninit_array_compared+5:22: `Box::from_raw` of `[[u32; 2]; 2]`, which may be arrays `as_chunks` split from one flat array, which is not supported yet -fixtures/reject/src/alloc.rs:uninit_array_compared+6:2: comparing pointers to `std::mem::MaybeUninit<[u32; 2]>`, an array a `MaybeUninit` or `ManuallyDrop` holds, whose shared reference through a raw pointer to part of an array is a copy -fixtures/reject/src/alloc.rs:uninit_array_lent+1:25: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet -fixtures/reject/src/alloc.rs:uninit_array_lent+2:59: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_lent+1:25: a reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own to lend, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_lent+2:59: a reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own to lend, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_lent+3:25: a reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own to lend, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_lent+4:59: a reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own to lend, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_lent+5:23: a reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own to lend, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_lent+6:23: a reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own to lend, which is not supported yet fixtures/reject/src/alloc.rs:uninit_cell_lent+2:17: `MaybeUninit::assume_init_mut` of `std::cell::UnsafeCell`, whose mutable reference is the object, but the uninitialized value's is the place it is kept in fixtures/reject/src/alloc.rs:vec_pointer+1:10: a raw pointer to `std::vec::Vec` behind a reference, which is the object and not where it is kept fixtures/reject/src/alloc.rs:wrapped_cells+8:19: a whole write of `std::mem::MaybeUninit<(std::cell::UnsafeCell, u32)>`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds @@ -253,10 +256,10 @@ fixtures/reject/src/pointers.rs:reached_out+8:27: a pointer reaching past a valu fixtures/reject/src/pointers.rs:text_apart+1:27: `offset_from` between pointers of two `str::as_ptr` calls, each into an encoding of the text of its own, which JS keeps in different arrays fixtures/reject/src/pointers.rs:text_apart+1:64: `offset_from` between pointers of two `str::as_ptr` calls, each into an encoding of the text of its own, which JS keeps in different arrays fixtures/reject/src/pointers.rs:text_before+1:28: a pointer reaching past a `str`'s bytes, which JS keeps apart from what holds it in Rust -fixtures/reject/src/pointers.rs:uninit_part_mut+5:25: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet +fixtures/reject/src/pointers.rs:uninit_part_mut+5:25: a reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own to lend, which is not supported yet fixtures/reject/src/pointers.rs:uninit_part_replaced+5:19: a raw pointer to `std::mem::MaybeUninit<(u32, u32)>` in `pointers::Gap`, which the crate may put another object in place of fixtures/reject/src/pointers.rs:uninit_part_replaced+6:19: a raw pointer to `std::mem::MaybeUninit<(u32, u32)>` in `pointers::Gap`, which the crate may put another object in place of -fixtures/reject/src/pointers.rs:uninit_rows_mut+5:25: a mutable reborrow of `std::mem::MaybeUninit<[[u8; 2]; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet +fixtures/reject/src/pointers.rs:uninit_rows_mut+5:25: a reborrow of `std::mem::MaybeUninit<[[u8; 2]; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own to lend, which is not supported yet fixtures/reject/src/pointers.rs:unit_elements+1:13: `offset_from` of pointers to `()`, which has no bytes fixtures/reject/src/pointers.rs:unit_elements+1:39: a slice of `()`, which has no bytes, from a pointer fixtures/reject/src/pointers.rs:variable_celled+2:10: a raw pointer to `(u32, u32)` in a variable assigned again while it may point there diff --git a/ts/fixtures/reject/expected.txt b/ts/fixtures/reject/expected.txt index 020665ada..04cb71f3c 100644 --- a/ts/fixtures/reject/expected.txt +++ b/ts/fixtures/reject/expected.txt @@ -33,13 +33,16 @@ fixtures/reject/src/alloc.rs:cell_raw_unknown+5:15: `UnsafeCell::raw_get` of a p fixtures/reject/src/alloc.rs:cell_raw_unknown+6:3: `UnsafeCell::raw_get` of a pointer not made of a place of `std::cell::UnsafeCell`, such as a parameter, a vector's or a slice's, or one moved by arithmetic, which may point where no cell is fixtures/reject/src/alloc.rs:cell_raw_unknown+8:15: `UnsafeCell::raw_get` of a pointer not made of a place of `std::cell::UnsafeCell`, such as a parameter, a vector's or a slice's, or one moved by arithmetic, which may point where no cell is fixtures/reject/src/alloc.rs:cell_raw_unknown+9:13: `UnsafeCell::raw_get` of a pointer not made of a place of `std::cell::UnsafeCell`, such as a parameter, a vector's or a slice's, or one moved by arithmetic, which may point where no cell is +fixtures/reject/src/alloc.rs:flat_arrays_boxed+4:22: `Box::from_raw` of `[[u32; 2]; 2]`, which may be arrays `as_chunks` split from one flat array, which is not supported yet fixtures/reject/src/alloc.rs:pinned_lent+1:32: `UnsafeCell::get_mut` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:pinned_lent+2:43: `UnsafeCell::as_mut_unchecked` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:reinterpreted+1:27: a cast from a pointer to `u32` to one to `u8`, which reads the bytes of one type as another -fixtures/reject/src/alloc.rs:uninit_array_compared+5:22: `Box::from_raw` of `[[u32; 2]; 2]`, which may be arrays `as_chunks` split from one flat array, which is not supported yet -fixtures/reject/src/alloc.rs:uninit_array_compared+6:2: comparing pointers to `std::mem::MaybeUninit<[u32; 2]>`, an array a `MaybeUninit` or `ManuallyDrop` holds, whose shared reference through a raw pointer to part of an array is a copy -fixtures/reject/src/alloc.rs:uninit_array_lent+1:25: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet -fixtures/reject/src/alloc.rs:uninit_array_lent+2:59: a mutable reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_lent+1:25: a reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own to lend, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_lent+2:59: a reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own to lend, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_lent+3:25: a reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own to lend, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_lent+4:59: a reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own to lend, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_lent+5:23: a reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own to lend, which is not supported yet +fixtures/reject/src/alloc.rs:uninit_array_lent+6:23: a reborrow of `std::mem::MaybeUninit<[u32; 2]>` through a raw pointer, which may point into part of an array with no JS array of its own to lend, which is not supported yet fixtures/reject/src/alloc.rs:uninit_cell_lent+2:17: `MaybeUninit::assume_init_mut` of `std::cell::UnsafeCell`, whose mutable reference is the object, but the uninitialized value's is the place it is kept in fixtures/reject/src/alloc.rs:vec_pointer+1:10: a raw pointer to `std::vec::Vec` behind a reference, which is the object and not where it is kept fixtures/reject/src/alloc.rs:wrapped_cells+8:19: a whole write of `std::mem::MaybeUninit<(std::cell::UnsafeCell, u32)>`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds diff --git a/ts/fixtures/reject/src/alloc.rs b/ts/fixtures/reject/src/alloc.rs index 6f9544799..7f51d7e02 100644 --- a/ts/fixtures/reject/src/alloc.rs +++ b/ts/fixtures/reject/src/alloc.rs @@ -146,24 +146,27 @@ pub fn cell_of_arrays() -> u16 { x.into_inner()[0][0] ^ v.into_inner()[0] as u16 } -/// `as_mut` and `NonNull::as_mut` of a pointer to an array a `MaybeUninit` holds, whose -/// mutable reference is the array, which part of an array has none of its own. +/// Reborrows through a pointer to an array a `MaybeUninit` holds, by `as_mut`, `as_ref`, +/// and `&*p`, shared and mutable, whose reference is the array, which part of an array has +/// none of its own. pub fn uninit_array_lent(p: *mut std::mem::MaybeUninit<[u32; 2]>) -> u32 { let first = unsafe { p.as_mut() }.map_or(0, |m| unsafe { m.assume_init_mut()[0] }); let second = unsafe { std::ptr::NonNull::new(p).unwrap().as_mut().assume_init_mut()[1] }; - first ^ second + let third = unsafe { p.as_ref() }.map_or(0, |m| unsafe { m.assume_init_ref()[0] }); + let fourth = unsafe { std::ptr::NonNull::new(p).unwrap().as_ref().assume_init_ref()[1] }; + let fifth = unsafe { (&*p).assume_init_ref()[0] }; + let sixth = unsafe { (&mut *p).assume_init_mut()[1] }; + first ^ second ^ third ^ fourth ^ fifth ^ sixth } -/// Pointers to an array a `MaybeUninit` holds compared, one a shared reference through a -/// raw pointer may make a copy of; and `Box::from_raw` of arrays `as_chunks_mut` split from -/// one flat array, which a box of arrays of their own can't share. -pub fn uninit_array_compared(p: *const std::mem::MaybeUninit<[u32; 2]>) -> bool { - let r = unsafe { p.as_ref() }.unwrap(); +/// `Box::from_raw` of arrays `as_chunks_mut` split from one flat array, which a box of +/// arrays of their own can't share. +pub fn flat_arrays_boxed() -> u32 { let flat = Box::into_raw(Box::new([1u32, 2, 3, 4])); let (runs, _) = unsafe { (*flat).as_chunks_mut::<2>() }; let whole: *mut [[u32; 2]; 2] = runs.first_chunk_mut().unwrap(); let back = unsafe { Box::from_raw(whole) }; - std::ptr::eq(p, r) && back[0][0] == 1 + back[0][0] } /// A `get_mut` and an `as_mut_unchecked` of a cell of a pinned `Box`, whose old value diff --git a/ts/fixtures/reject/ts.toml b/ts/fixtures/reject/ts.toml index c74ea12c0..16b46d93b 100644 --- a/ts/fixtures/reject/ts.toml +++ b/ts/fixtures/reject/ts.toml @@ -10,9 +10,9 @@ roots = [ "alloc::cell_pointer_reassigned", "alloc::cell_raw_reassigned", "alloc::cell_raw_unknown", + "alloc::flat_arrays_boxed", "alloc::pinned_lent", "alloc::reinterpreted", - "alloc::uninit_array_compared", "alloc::uninit_array_lent", "alloc::uninit_cell_lent", "alloc::vec_pointer", diff --git a/ts/src/lower/mir/rvalue.rs b/ts/src/lower/mir/rvalue.rs index 91887cf7d..17cff3689 100644 --- a/ts/src/lower/mir/rvalue.rs +++ b/ts/src/lower/mir/rvalue.rs @@ -56,23 +56,15 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { } } let value = self.place_expr(*place, span, out); - // A borrow of an array is a slice of all of it, sharing its elements. A shared one - // of a `MaybeUninit` of one through a raw pointer is the array of the pointer's - // elements: a view of bytes, and else the array where the slice is all of it. + // A borrow of an array is a slice of all of it, sharing its elements. One of a + // `MaybeUninit` of one through a raw pointer is the array: a view of bytes, and + // else refused, as the pointer may point into part of an array, which has no JS + // array of its own, so a copy would lose writes and differ in address. let pointee = place.ty(&self.mir.local_decls, tcx).ty; match (pointee.is_array(), self.in_array(*place)) { (true, false) => crate::lower::array_slice(self.b.t.uninit_inner(pointee), value), (false, true) if self.in_bytes(*place) => Expr::rs("byteSliceView", vec![value]), - (false, true) => match self.b.t.uninit_inner(pointee).kind() { - // Part of an array, or arrays `as_chunks_mut` splits from one slice, has - // no JS array of its own, so a write through a copy of it would be lost. - ty::Array(..) if matches!(kind, mir::BorrowKind::Mut { .. }) => self.err( - span, - format!("a mutable reborrow of `{pointee}` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet"), - ), - ty::Array(elem, _) => crate::lower::library::items_of(value, *elem), - _ => crate::lower::library::slice_items(value), - }, + (false, true) => self.err(span, crate::lower::pointer::uninit_reborrow(pointee)), _ => value, } } diff --git a/ts/src/lower/pointer.rs b/ts/src/lower/pointer.rs index 5a258e7ec..1c53d83c9 100644 --- a/ts/src/lower/pointer.rs +++ b/ts/src/lower/pointer.rs @@ -122,12 +122,6 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { "comparing pointers to `{ty}`, each an object JS makes of its own as it unsizes" )); } - let inner = self.uninit_inner(ty); - if self.pointee(ty) == Pointee::Array && inner != ty && !super::byte_array(inner) { - return Some(format!( - "comparing pointers to `{ty}`, an array a `MaybeUninit` or `ManuallyDrop` holds, whose shared reference through a raw pointer to part of an array is a copy" - )); - } match self.pointee(ty) { // `from_ref`, `from_mut` of a variable, and `Option::as_slice` make an array of // one of their own for a value, so only longer arrays are always where Rust's are. @@ -588,19 +582,14 @@ pub fn call<'tcx>( }; // A reference to the array a pointer points at: the slice the pointer is, or for one a // `MaybeUninit` or `ManuallyDrop` holds, whose reference is the array, as a reborrow of - // `*p` makes it: a view of bytes, a shared one the array where the slice is all of it, and - // a mutable one refused, as part of an array has no JS array of its own to write through. - let to_reference = |b: &mut Body<'_, '_, 'tcx>, p: Expr, shared: bool| { + // `*p` makes it: a view of bytes, and else refused. + let to_reference = |b: &mut Body<'_, '_, 'tcx>, p: Expr| { let ty = pointee(); let inner = b.t.uninit_inner(ty); - match inner.kind() { + match inner { _ if inner == ty => p, _ if super::byte_array(inner) => Expr::rs("byteSliceView", vec![p]), - ty::Array(elem, _) if shared => super::library::items_of(p, *elem), - _ => b.err( - span, - format!("a mutable reborrow of `{ty}` through a raw pointer, which may point into part of an array with no JS array of its own, which is not supported yet"), - ), + _ => b.err(span, uninit_reborrow(ty)), } }; // A raw pointer to a slice, from a reference to one, and the slice a read through it @@ -680,7 +669,7 @@ pub fn call<'tcx>( } ("NonNull", "as_mut") if array(b, pointee()) => { let p = arg(); - to_reference(b, p, false) + to_reference(b, p) } // A `&mut` to a `MaybeUninit` of a cell of a value JS copies is the place the cell is // kept in, but one to the cell is the cell. @@ -765,7 +754,7 @@ pub fn call<'tcx>( ty::Adt(_, args) => b.t.none(args.type_at(0)), _ => Expr::undefined(), }; - (to_reference(b, p.clone(), name == "as_ref"), none) + (to_reference(b, p.clone()), none) } false => (p.clone(), Expr::undefined()), }; @@ -779,7 +768,7 @@ pub fn call<'tcx>( Some(Pointee::Place) if owner == "NonNull" => arg().member("v"), Some(Pointee::Array) if owner == "NonNull" => { let p = arg(); - to_reference(b, p, true) + to_reference(b, p) } _ => arg(), }, @@ -1616,6 +1605,15 @@ fn object_field<'tcx>(b: &mut Body<'_, '_, 'tcx>, object: Expr, ty: Ty<'tcx>, i: } } +/// Why a reborrow through a raw pointer of `ty`, an array a `MaybeUninit` or `ManuallyDrop` +/// holds of other than bytes, is refused: its reference is the array, which part of an array +/// has none of its own, so a shared one would be a copy at another address. +pub fn uninit_reborrow(ty: Ty<'_>) -> String { + format!( + "a reborrow of `{ty}` through a raw pointer, which may point into part of an array with no JS array of its own to lend, which is not supported yet" + ) +} + /// Whether `ty` is `[u8]`, one of `MaybeUninit`, or an `UninitSlice`, whose slices are /// `rs.ByteSlice`s. pub fn slice_of_bytes(ty: Ty<'_>) -> bool { From f72d5421c54049eed0087c0ffd1e89cfdba5a0ac Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Sat, 7 Nov 2026 17:02:35 -0800 Subject: [PATCH 11/12] fix(ts): Box::from_raw of an array of no bytes from any pointer A box of a zero-sized array owns no allocation, so Rust takes any pointer to one back as a box; it no longer aborts where the pointer covers part of an array. Co-Authored-By: Claude Opus 5.5 --- .../lang/pointers/expected/pointers.ts | 35 ++++++++++--------- ts/fixtures/lang/pointers/src/pointers.rs | 6 ++++ ts/src/lower/pointer.rs | 10 ++++-- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/ts/fixtures/lang/pointers/expected/pointers.ts b/ts/fixtures/lang/pointers/expected/pointers.ts index d5c373bf0..c1f067770 100644 --- a/ts/fixtures/lang/pointers/expected/pointers.ts +++ b/ts/fixtures/lang/pointers/expected/pointers.ts @@ -4119,6 +4119,9 @@ export function arrayParts(data: rs.ByteSlice, out: rs.ByteVec): void { rs.iterExtendBytes(out, rs.iterMap(rs.iterSlice(rs.boxArrayFromRaw(raw)), (_210: rs.u32): rs.u8 => { return _210 & 0xff; }), undefined, true); + const units2: undefined[] = rs.sliceItems(rs.rawSliceOf(rs.sliceFrom([undefined, undefined, undefined])).array(2)); + const none2: rs.u32[] = rs.sliceItems(rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(rs.sliceFrom(words.items), 2), 0, 0))); + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(rs.sliceFrom(units2).length & 0xff, rs.sliceFrom(none2).length & 0xff)), undefined, true); rs.iterExtendBytes(out, rs.iterMap(rs.iterSlice(words.items), (_211: rs.u32): rs.u8 => { return _211 & 0xff; }), undefined, true); @@ -4131,17 +4134,17 @@ export function arrayParts(data: rs.ByteSlice, out: rs.ByteVec): void { }), undefined, 8, true); const p3: rs.ArraySlice> = rs.optionUnwrap(rs.arraySliceGetRange(rs.arraySliceRange(rs.arraySliceFrom(rows.items, rs.sliceFrom), 1), 0, 2)); const pointer3 = p3; - const _90: rs.ArraySlice> | undefined = pointer3 === rs.NULL ? undefined : pointer3; - if (_90 !== undefined) { - const _93: rs.u32 = rs.u32Add(n, 4); - const slice6 = rs.arraySliceAt(_90, 1); - slice6.data[slice6.start] = _93; + const _112: rs.ArraySlice> | undefined = pointer3 === rs.NULL ? undefined : pointer3; + if (_112 !== undefined) { + const _115: rs.u32 = rs.u32Add(n, 4); + const slice7 = rs.arraySliceAt(_112, 1); + slice7.data[slice7.start] = _115; } const pointer4 = p3; const nn2: rs.ArraySlice> = rs.optionUnwrap(pointer4 === rs.NULL ? undefined : pointer4); - const _100: rs.u32 = rs.u32Add(n, 5); - const slice7 = rs.arraySliceAt(nn2, 0); - slice7.data[slice7.start + 1] = _100; + const _122: rs.u32 = rs.u32Add(n, 5); + const slice8 = rs.arraySliceAt(nn2, 0); + slice8.data[slice8.start + 1] = _122; rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rows.items, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_212: rs.u32): rs.u8 => { return _212 & 0xff; }), undefined, true); @@ -4150,16 +4153,16 @@ export function arrayParts(data: rs.ByteSlice, out: rs.ByteVec): void { return copy$mem_MaybeUninit_array_u8(m); })), undefined, true); const cell: rs.Cell = new rs.Cell(copy$mem_MaybeUninit_array_u8(Uint8Array.of(n & 0xff, 2))); - const _126: rs.ByteSlice = rs.byteSliceFrom(cell.v); - _126.data[_126.start + 1] = 9; + const _148: rs.ByteSlice = rs.byteSliceFrom(cell.v); + _148.data[_148.start + 1] = 9; rs.iterExtendBytes(out, rs.iterSlice(cell.v), undefined, true); const uc: rs.Cell = new rs.Cell(copy$mem_MaybeUninit_array_u32([n, 3])); - const _138: rs.u32 = rs.u32Add(n, 8); - const _139: rs.Slice = rs.sliceFrom(uc.v); - _139.data[_139.start] = _138; - const _144: rs.u32 = rs.u32Add(n, 9); - const _145: rs.Slice = rs.sliceFrom(uc.v); - _145.data[_145.start + 1] = _144; + const _160: rs.u32 = rs.u32Add(n, 8); + const _161: rs.Slice = rs.sliceFrom(uc.v); + _161.data[_161.start] = _160; + const _166: rs.u32 = rs.u32Add(n, 9); + const _167: rs.Slice = rs.sliceFrom(uc.v); + _167.data[_167.start + 1] = _166; rs.iterExtendBytes(out, rs.iterSlice(rs.bytesMap(uc.v, (w5: rs.u32): rs.u8 => { return w5 & 0xff; })), undefined, true); diff --git a/ts/fixtures/lang/pointers/src/pointers.rs b/ts/fixtures/lang/pointers/src/pointers.rs index dde51b426..e8ad2f66c 100644 --- a/ts/fixtures/lang/pointers/src/pointers.rs +++ b/ts/fixtures/lang/pointers/src/pointers.rs @@ -3061,6 +3061,12 @@ pub fn array_parts(data: &[u8], out: &mut Vec) { unsafe { (*raw)[1] = 7 }; let back = unsafe { Box::from_raw(raw) }; out.extend(back.iter().map(|&w| w as u8)); + // Of arrays of no bytes, whose box owns no allocation, so any pointer to one makes one. + let units: Box<[()]> = Box::new([(); 3]); + let units = unsafe { Box::from_raw(Box::into_raw(units) as *mut [(); 2]) }; + let none: *mut [u32; 0] = words[2..].first_chunk_mut().unwrap(); + let none = unsafe { Box::from_raw(none) }; + out.extend([units.len() as u8, none.len() as u8]); out.extend(words.iter().map(|&w| w as u8)); // Of arrays of arrays. let mut rows: Vec<[u32; 2]> = words.chunks(2).map(|c| [c[0], c[c.len() - 1]]).collect(); diff --git a/ts/src/lower/pointer.rs b/ts/src/lower/pointer.rs index 1c53d83c9..01d90c0ee 100644 --- a/ts/src/lower/pointer.rs +++ b/ts/src/lower/pointer.rs @@ -841,10 +841,16 @@ pub fn call<'tcx>( ("Box", "from_raw") => match kind(b, pointee()) { Some(Pointee::Slice) => deref(pointee(), arg(), false), Some(Pointee::Place) => arg().member("v"), - // A box of an array is the array, all of which `into_raw` pointed at. Arrays - // `as_chunks` split from one flat array have no array of their own to box. + // A box of an array is the array, all of which `into_raw` pointed at. One of no + // bytes owns no allocation, so any pointer makes one, of the elements it points at. + // Arrays `as_chunks` split from one flat array have no array of their own to box. Some(Pointee::Array) => match b.t.uninit_inner(pointee()) { ty if super::byte_array(ty) => Expr::rs("byteSliceView", vec![arg()]), + ty if b.t.zero_sized(ty) + && let ty::Array(elem, _) = ty.kind() => + { + super::library::items_of(arg(), *elem) + } ty if super::array_slice::of_arrays(ty) => b.err( span, format!( From 3b9fefbab2328ad2d7992aa4ccfc332a8156de9a Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Sat, 7 Nov 2026 17:12:55 -0800 Subject: [PATCH 12/12] fix(ts): Box::from_raw of an array of no bytes at any length A pointer to an array of no bytes may claim more elements than it points at, so the box is a new array of its length, as a dangling pointer's is, and refused where its elements are more than structs and tuples. Co-Authored-By: Claude Opus 5.5 --- .../lang/pointers/expected/pointers.ts | 44 +++++++++++-------- ts/fixtures/lang/pointers/src/pointers.rs | 6 ++- ts/fixtures/reject/census.txt | 3 +- ts/fixtures/reject/expected.txt | 3 +- ts/fixtures/reject/src/alloc.rs | 15 +++++-- ts/fixtures/reject/ts.toml | 2 +- ts/src/lower/pointer.rs | 19 +++++--- 7 files changed, 59 insertions(+), 33 deletions(-) diff --git a/ts/fixtures/lang/pointers/expected/pointers.ts b/ts/fixtures/lang/pointers/expected/pointers.ts index c1f067770..748742a41 100644 --- a/ts/fixtures/lang/pointers/expected/pointers.ts +++ b/ts/fixtures/lang/pointers/expected/pointers.ts @@ -4119,9 +4119,17 @@ export function arrayParts(data: rs.ByteSlice, out: rs.ByteVec): void { rs.iterExtendBytes(out, rs.iterMap(rs.iterSlice(rs.boxArrayFromRaw(raw)), (_210: rs.u32): rs.u8 => { return _210 & 0xff; }), undefined, true); - const units2: undefined[] = rs.sliceItems(rs.rawSliceOf(rs.sliceFrom([undefined, undefined, undefined])).array(2)); - const none2: rs.u32[] = rs.sliceItems(rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(rs.sliceFrom(words.items), 2), 0, 0))); - rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(rs.sliceFrom(units2).length & 0xff, rs.sliceFrom(none2).length & 0xff)), undefined, true); + const raw2: rs.RawSlice = rs.rawSliceOf(rs.sliceFrom([undefined, undefined, undefined])); + const fewer: undefined[] = (new Array(2) as unknown) as undefined[]; + const more: undefined[] = (new Array(5) as unknown) as undefined[]; + const slice5 = rs.sliceFrom(words.items); + raw2.array(2); + raw2.array(5); + rs.optionUnwrap(rs.sliceGetRange(rs.sliceRange(slice5, 2), 0, 0)); + const none2: rs.u32[] = (new Array(0) as unknown) as rs.u32[]; + rs.iterExtendBytes(out, rs.iterSlice(rs.bytesMap([rs.sliceFrom(fewer).length, rs.iterCount(rs.iterSlice(more)), rs.sliceFrom(none2).length], (n2: rs.usize): rs.u8 => { + return n2 & 0xff; + })), undefined, true); rs.iterExtendBytes(out, rs.iterMap(rs.iterSlice(words.items), (_211: rs.u32): rs.u8 => { return _211 & 0xff; }), undefined, true); @@ -4134,17 +4142,17 @@ export function arrayParts(data: rs.ByteSlice, out: rs.ByteVec): void { }), undefined, 8, true); const p3: rs.ArraySlice> = rs.optionUnwrap(rs.arraySliceGetRange(rs.arraySliceRange(rs.arraySliceFrom(rows.items, rs.sliceFrom), 1), 0, 2)); const pointer3 = p3; - const _112: rs.ArraySlice> | undefined = pointer3 === rs.NULL ? undefined : pointer3; - if (_112 !== undefined) { - const _115: rs.u32 = rs.u32Add(n, 4); - const slice7 = rs.arraySliceAt(_112, 1); - slice7.data[slice7.start] = _115; + const _117: rs.ArraySlice> | undefined = pointer3 === rs.NULL ? undefined : pointer3; + if (_117 !== undefined) { + const _120: rs.u32 = rs.u32Add(n, 4); + const slice7 = rs.arraySliceAt(_117, 1); + slice7.data[slice7.start] = _120; } const pointer4 = p3; const nn2: rs.ArraySlice> = rs.optionUnwrap(pointer4 === rs.NULL ? undefined : pointer4); - const _122: rs.u32 = rs.u32Add(n, 5); + const _127: rs.u32 = rs.u32Add(n, 5); const slice8 = rs.arraySliceAt(nn2, 0); - slice8.data[slice8.start + 1] = _122; + slice8.data[slice8.start + 1] = _127; rs.iterExtendBytes(out, rs.iterMap(rs.iterFlatten(rs.arraySliceIter(rs.arraySliceFrom(rows.items, rs.sliceFrom)), (value: rs.Slice) => rs.iterSlice(rs.sliceItems(value)), true, 2), (_212: rs.u32): rs.u8 => { return _212 & 0xff; }), undefined, true); @@ -4153,16 +4161,16 @@ export function arrayParts(data: rs.ByteSlice, out: rs.ByteVec): void { return copy$mem_MaybeUninit_array_u8(m); })), undefined, true); const cell: rs.Cell = new rs.Cell(copy$mem_MaybeUninit_array_u8(Uint8Array.of(n & 0xff, 2))); - const _148: rs.ByteSlice = rs.byteSliceFrom(cell.v); - _148.data[_148.start + 1] = 9; + const _153: rs.ByteSlice = rs.byteSliceFrom(cell.v); + _153.data[_153.start + 1] = 9; rs.iterExtendBytes(out, rs.iterSlice(cell.v), undefined, true); const uc: rs.Cell = new rs.Cell(copy$mem_MaybeUninit_array_u32([n, 3])); - const _160: rs.u32 = rs.u32Add(n, 8); - const _161: rs.Slice = rs.sliceFrom(uc.v); - _161.data[_161.start] = _160; - const _166: rs.u32 = rs.u32Add(n, 9); - const _167: rs.Slice = rs.sliceFrom(uc.v); - _167.data[_167.start + 1] = _166; + const _165: rs.u32 = rs.u32Add(n, 8); + const _166: rs.Slice = rs.sliceFrom(uc.v); + _166.data[_166.start] = _165; + const _171: rs.u32 = rs.u32Add(n, 9); + const _172: rs.Slice = rs.sliceFrom(uc.v); + _172.data[_172.start + 1] = _171; rs.iterExtendBytes(out, rs.iterSlice(rs.bytesMap(uc.v, (w5: rs.u32): rs.u8 => { return w5 & 0xff; })), undefined, true); diff --git a/ts/fixtures/lang/pointers/src/pointers.rs b/ts/fixtures/lang/pointers/src/pointers.rs index e8ad2f66c..56d259cd0 100644 --- a/ts/fixtures/lang/pointers/src/pointers.rs +++ b/ts/fixtures/lang/pointers/src/pointers.rs @@ -3063,10 +3063,12 @@ pub fn array_parts(data: &[u8], out: &mut Vec) { out.extend(back.iter().map(|&w| w as u8)); // Of arrays of no bytes, whose box owns no allocation, so any pointer to one makes one. let units: Box<[()]> = Box::new([(); 3]); - let units = unsafe { Box::from_raw(Box::into_raw(units) as *mut [(); 2]) }; + let raw = Box::into_raw(units); + let fewer = unsafe { Box::from_raw(raw as *mut [(); 2]) }; + let more = unsafe { Box::from_raw(raw as *mut [(); 5]) }; let none: *mut [u32; 0] = words[2..].first_chunk_mut().unwrap(); let none = unsafe { Box::from_raw(none) }; - out.extend([units.len() as u8, none.len() as u8]); + out.extend([fewer.len(), more.iter().count(), none.len()].map(|n| n as u8)); out.extend(words.iter().map(|&w| w as u8)); // Of arrays of arrays. let mut rows: Vec<[u32; 2]> = words.chunks(2).map(|c| [c[0], c[c.len() - 1]]).collect(); diff --git a/ts/fixtures/reject/census.txt b/ts/fixtures/reject/census.txt index b318ef450..84558557f 100644 --- a/ts/fixtures/reject/census.txt +++ b/ts/fixtures/reject/census.txt @@ -6,6 +6,8 @@ fixtures/reject/src/alloc.rs:alloc_retyped+8:21: memory from `alloc` cast to poi fixtures/reject/src/alloc.rs:alloc_retyped+10:17: memory from `alloc` cast to pointers to `i32` and to `u32`, which reads the bytes of one type as another fixtures/reject/src/alloc.rs:allocated+4:3: a byte of memory from `alloc`, which JS keeps as the values a cast of its pointer types it as fixtures/reject/src/alloc.rs:allocated+5:11: a byte of memory from `alloc`, which JS keeps as the values a cast of its pointer types it as +fixtures/reject/src/alloc.rs:arrays_boxed+4:22: `Box::from_raw` of `[[u32; 2]; 2]`, which may be arrays `as_chunks` split from one flat array, which is not supported yet +fixtures/reject/src/alloc.rs:arrays_boxed+6:23: `Box::from_raw` of `[alloc::Only; 2]`, a value of no bytes made of more than structs and tuples fixtures/reject/src/alloc.rs:bytes_as_values+3:3: a byte of memory from `alloc`, which JS keeps as the values a cast of its pointer types it as fixtures/reject/src/alloc.rs:bytes_as_values+4:15: a cast from a pointer to `u8` to one to `u32`, which reads the bytes of one type as another fixtures/reject/src/alloc.rs:bytes_as_values+5:16: a cast from a pointer to `u8` to one to `pointers::Halves`, which reads the bytes of one type as another @@ -29,7 +31,6 @@ fixtures/reject/src/alloc.rs:cell_raw_unknown+5:15: `UnsafeCell::raw_get` of a p fixtures/reject/src/alloc.rs:cell_raw_unknown+6:3: `UnsafeCell::raw_get` of a pointer not made of a place of `std::cell::UnsafeCell`, such as a parameter, a vector's or a slice's, or one moved by arithmetic, which may point where no cell is fixtures/reject/src/alloc.rs:cell_raw_unknown+8:15: `UnsafeCell::raw_get` of a pointer not made of a place of `std::cell::UnsafeCell`, such as a parameter, a vector's or a slice's, or one moved by arithmetic, which may point where no cell is fixtures/reject/src/alloc.rs:cell_raw_unknown+9:13: `UnsafeCell::raw_get` of a pointer not made of a place of `std::cell::UnsafeCell`, such as a parameter, a vector's or a slice's, or one moved by arithmetic, which may point where no cell is -fixtures/reject/src/alloc.rs:flat_arrays_boxed+4:22: `Box::from_raw` of `[[u32; 2]; 2]`, which may be arrays `as_chunks` split from one flat array, which is not supported yet fixtures/reject/src/alloc.rs:pinned_lent+1:32: `UnsafeCell::get_mut` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:pinned_lent+2:43: `UnsafeCell::as_mut_unchecked` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:reinterpreted+1:27: a cast from a pointer to `u32` to one to `u8`, which reads the bytes of one type as another diff --git a/ts/fixtures/reject/expected.txt b/ts/fixtures/reject/expected.txt index 5285f87b2..c2eae6dd6 100644 --- a/ts/fixtures/reject/expected.txt +++ b/ts/fixtures/reject/expected.txt @@ -10,6 +10,8 @@ fixtures/reject/src/alloc.rs:alloc_retyped+8:21: memory from `alloc` cast to poi fixtures/reject/src/alloc.rs:alloc_retyped+10:17: memory from `alloc` cast to pointers to `i32` and to `u32`, which reads the bytes of one type as another fixtures/reject/src/alloc.rs:allocated+4:3: a byte of memory from `alloc`, which JS keeps as the values a cast of its pointer types it as fixtures/reject/src/alloc.rs:allocated+5:11: a byte of memory from `alloc`, which JS keeps as the values a cast of its pointer types it as +fixtures/reject/src/alloc.rs:arrays_boxed+4:22: `Box::from_raw` of `[[u32; 2]; 2]`, which may be arrays `as_chunks` split from one flat array, which is not supported yet +fixtures/reject/src/alloc.rs:arrays_boxed+6:23: `Box::from_raw` of `[alloc::Only; 2]`, a value of no bytes made of more than structs and tuples fixtures/reject/src/alloc.rs:bytes_as_values+3:3: a byte of memory from `alloc`, which JS keeps as the values a cast of its pointer types it as fixtures/reject/src/alloc.rs:bytes_as_values+4:15: a cast from a pointer to `u8` to one to `u32`, which reads the bytes of one type as another fixtures/reject/src/alloc.rs:bytes_as_values+5:16: a cast from a pointer to `u8` to one to `pointers::Halves`, which reads the bytes of one type as another @@ -33,7 +35,6 @@ fixtures/reject/src/alloc.rs:cell_raw_unknown+5:15: `UnsafeCell::raw_get` of a p fixtures/reject/src/alloc.rs:cell_raw_unknown+6:3: `UnsafeCell::raw_get` of a pointer not made of a place of `std::cell::UnsafeCell`, such as a parameter, a vector's or a slice's, or one moved by arithmetic, which may point where no cell is fixtures/reject/src/alloc.rs:cell_raw_unknown+8:15: `UnsafeCell::raw_get` of a pointer not made of a place of `std::cell::UnsafeCell`, such as a parameter, a vector's or a slice's, or one moved by arithmetic, which may point where no cell is fixtures/reject/src/alloc.rs:cell_raw_unknown+9:13: `UnsafeCell::raw_get` of a pointer not made of a place of `std::cell::UnsafeCell`, such as a parameter, a vector's or a slice's, or one moved by arithmetic, which may point where no cell is -fixtures/reject/src/alloc.rs:flat_arrays_boxed+4:22: `Box::from_raw` of `[[u32; 2]; 2]`, which may be arrays `as_chunks` split from one flat array, which is not supported yet fixtures/reject/src/alloc.rs:pinned_lent+1:32: `UnsafeCell::get_mut` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:pinned_lent+2:43: `UnsafeCell::as_mut_unchecked` of `std::pin::Pin>`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address fixtures/reject/src/alloc.rs:reinterpreted+1:27: a cast from a pointer to `u32` to one to `u8`, which reads the bytes of one type as another diff --git a/ts/fixtures/reject/src/alloc.rs b/ts/fixtures/reject/src/alloc.rs index 7f51d7e02..723532aee 100644 --- a/ts/fixtures/reject/src/alloc.rs +++ b/ts/fixtures/reject/src/alloc.rs @@ -160,13 +160,22 @@ pub fn uninit_array_lent(p: *mut std::mem::MaybeUninit<[u32; 2]>) -> u32 { } /// `Box::from_raw` of arrays `as_chunks_mut` split from one flat array, which a box of -/// arrays of their own can't share. -pub fn flat_arrays_boxed() -> u32 { +/// arrays of their own can't share, and of an array of no bytes whose elements are more than +/// structs and tuples, which the translator can't make anew. +pub fn arrays_boxed() -> u32 { let flat = Box::into_raw(Box::new([1u32, 2, 3, 4])); let (runs, _) = unsafe { (*flat).as_chunks_mut::<2>() }; let whole: *mut [[u32; 2]; 2] = runs.first_chunk_mut().unwrap(); let back = unsafe { Box::from_raw(whole) }; - back[0][0] + let marks = Box::into_raw(Box::new([Only::One; 2])); + let marks = unsafe { Box::from_raw(marks) }; + back[0][0] + marks.len() as u32 +} + +/// An enum of one variant, a value of no bytes. +#[derive(Clone, Copy)] +enum Only { + One, } /// A `get_mut` and an `as_mut_unchecked` of a cell of a pinned `Box`, whose old value diff --git a/ts/fixtures/reject/ts.toml b/ts/fixtures/reject/ts.toml index 953de89bf..5f97a1870 100644 --- a/ts/fixtures/reject/ts.toml +++ b/ts/fixtures/reject/ts.toml @@ -3,6 +3,7 @@ roots = [ "alloc::addressed", "alloc::alloc_retyped", "alloc::allocated", + "alloc::arrays_boxed", "alloc::bytes_as_values", "alloc::cell_of_arrays", "alloc::cell_of_objects", @@ -10,7 +11,6 @@ roots = [ "alloc::cell_pointer_reassigned", "alloc::cell_raw_reassigned", "alloc::cell_raw_unknown", - "alloc::flat_arrays_boxed", "alloc::pinned_lent", "alloc::reinterpreted", "alloc::uninit_array_lent", diff --git a/ts/src/lower/pointer.rs b/ts/src/lower/pointer.rs index 01d90c0ee..a31f5a3e9 100644 --- a/ts/src/lower/pointer.rs +++ b/ts/src/lower/pointer.rs @@ -842,15 +842,20 @@ pub fn call<'tcx>( Some(Pointee::Slice) => deref(pointee(), arg(), false), Some(Pointee::Place) => arg().member("v"), // A box of an array is the array, all of which `into_raw` pointed at. One of no - // bytes owns no allocation, so any pointer makes one, of the elements it points at. - // Arrays `as_chunks` split from one flat array have no array of their own to box. + // bytes owns no allocation, so any pointer of any length makes one: a new array, as + // a dangling pointer's is. Arrays `as_chunks` split from one flat array have no + // array of their own to box. Some(Pointee::Array) => match b.t.uninit_inner(pointee()) { ty if super::byte_array(ty) => Expr::rs("byteSliceView", vec![arg()]), - ty if b.t.zero_sized(ty) - && let ty::Array(elem, _) = ty.kind() => - { - super::library::items_of(arg(), *elem) - } + ty if b.t.zero_sized(ty) => match ty.kind() { + ty::Array(elem, len) if b.t.empty(*elem) || len.try_to_target_usize(b.t.tcx) == Some(0) => { + b.t.uninit(pointee(), span) + } + _ => b.err( + span, + format!("`Box::from_raw` of `{ty}`, a value of no bytes made of more than structs and tuples"), + ), + }, ty if super::array_slice::of_arrays(ty) => b.err( span, format!(