diff --git a/quest/m3/ts-unsafe/README.md b/quest/m3/ts-unsafe/README.md index 86575a3a5..328b9830b 100644 --- a/quest/m3/ts-unsafe/README.md +++ b/quest/m3/ts-unsafe/README.md @@ -77,4 +77,3 @@ Public API: the translator's output. ## Required - [A raw pointer behind a reference](/quest/m3/ts-unsafe/raw-behind-ref.md) - `&raw const *r` of a value JS copies points where the reference came from -- [UnsafeCell's raw accessors](/quest/m3/ts-unsafe/unsafecell.md) - `UnsafeCell::raw_get`, `from_mut`, and `replace` translate diff --git a/quest/m3/ts-unsafe/unsafecell.md b/quest/m3/ts-unsafe/unsafecell.md deleted file mode 100644 index 33c4225cd..000000000 --- a/quest/m3/ts-unsafe/unsafecell.md +++ /dev/null @@ -1,15 +0,0 @@ -# [XS] UnsafeCell's raw accessors - -## Goal - -[rust2-ts](/ts/README.md) translates `UnsafeCell::raw_get`, `UnsafeCell::from_mut`, and -`UnsafeCell::replace`, proven by differential tests against native Rust. Today each is -refused as an unsupported call, and `raw_get(&c)` also as a raw pointer behind a -reference. - -## Plan - -`UnsafeCell::get` already lends the cell where it is an `rs.Place`. No consumer at the moq -pin. - -Public API: the translator's output. diff --git a/ts/fixtures/lang/borrows/expected/borrows.ts b/ts/fixtures/lang/borrows/expected/borrows.ts index cf5bfa9ec..18e6b73f0 100644 --- a/ts/fixtures/lang/borrows/expected/borrows.ts +++ b/ts/fixtures/lang/borrows/expected/borrows.ts @@ -1,7 +1,7 @@ // Generated by rust2-ts. Do not edit. import * as rs from "./rs.ts"; -import { copy$Option_tuple2_u64_u64, copy$tuple2_u64_u64, drop$Result_cell_RefMut_Vec_u8_cell_BorrowMutError, drop$Result_cell_RefMut_array4_u8_cell_BorrowMutError, drop$Result_cell_RefMut_borrows_Parts_cell_BorrowMutError, drop$Result_cell_RefMut_borrows_Tagged_cell_BorrowMutError, drop$Result_cell_RefMut_tuple2_u16_Vec_u8_cell_BorrowMutError, drop$Result_cell_RefMut_u32_cell_BorrowMutError, drop$Result_cell_RefMut_u32_tuple2_cell_RefMut_borrows_Parts_unit, drop$Result_cell_Ref_Vec_u8_cell_BorrowError, drop$Result_cell_Ref_array4_u8_cell_BorrowError, drop$Result_cell_Ref_borrows_Parts_cell_BorrowError, drop$Result_cell_Ref_ref_str_tuple2_cell_Ref_tuple2_u8_ref_str_u8, drop$Result_cell_Ref_tuple2_u16_Vec_u8_cell_BorrowError, drop$Result_cell_Ref_u32_cell_BorrowError, drop$Result_cell_Ref_u32_cell_Ref_borrows_Parts, drop$Result_cell_Ref_u32_tuple2_cell_Ref_borrows_Parts_unit, drop$tuple2_Option_cell_Ref_borrows_Tagged_Option_cell_RefMut_borrows_Tagged, drop$tuple2_Result_cell_Ref_Vec_u8_cell_BorrowError_cell_Ref_Vec_u8, drop$tuple2_cell_RefMut_slice_u8_cell_RefMut_slice_u8, drop$tuple2_cell_Ref_Vec_u8_cell_Ref_u8, drop$tuple2_cell_Ref_str_cell_RefMut_u32, drop$tuple3_cell_Ref_String_cell_Ref_array4_u8_cell_Ref_u32 } from "./lib.ts"; +import { copy$Option_tuple2_u64_u64, copy$tuple2_u64_u64, copy$tuple2_u8_char, drop$Result_cell_RefMut_Vec_u8_cell_BorrowMutError, drop$Result_cell_RefMut_array4_u8_cell_BorrowMutError, drop$Result_cell_RefMut_borrows_Parts_cell_BorrowMutError, drop$Result_cell_RefMut_borrows_Tagged_cell_BorrowMutError, drop$Result_cell_RefMut_tuple2_u16_Vec_u8_cell_BorrowMutError, drop$Result_cell_RefMut_u32_cell_BorrowMutError, drop$Result_cell_RefMut_u32_tuple2_cell_RefMut_borrows_Parts_unit, drop$Result_cell_Ref_Vec_u8_cell_BorrowError, drop$Result_cell_Ref_array4_u8_cell_BorrowError, drop$Result_cell_Ref_borrows_Parts_cell_BorrowError, drop$Result_cell_Ref_ref_str_tuple2_cell_Ref_tuple2_u8_ref_str_u8, drop$Result_cell_Ref_tuple2_u16_Vec_u8_cell_BorrowError, drop$Result_cell_Ref_u32_cell_BorrowError, drop$Result_cell_Ref_u32_cell_Ref_borrows_Parts, drop$Result_cell_Ref_u32_tuple2_cell_Ref_borrows_Parts_unit, drop$tuple2_Option_cell_Ref_borrows_Tagged_Option_cell_RefMut_borrows_Tagged, drop$tuple2_Result_cell_Ref_Vec_u8_cell_BorrowError_cell_Ref_Vec_u8, drop$tuple2_cell_RefMut_slice_u8_cell_RefMut_slice_u8, drop$tuple2_cell_Ref_Vec_u8_cell_Ref_u8, drop$tuple2_cell_Ref_str_cell_RefMut_u32, drop$tuple3_cell_Ref_String_cell_Ref_array4_u8_cell_Ref_u32 } from "./lib.ts"; import * as Noisy from "./borrows.Noisy.ts"; import * as Parts from "./borrows.Parts.ts"; import * as Polling from "./borrows.Polling.ts"; @@ -33,7 +33,7 @@ export function borrows(data: rs.ByteSlice, out: rs.ByteVec): void { const copy: [rs.u64, rs.u64] = copy$tuple2_u64_u64(copy$tuple2_u64_u64(pair.v)); copy[0] = rs.u64Add(copy[0], op as rs.u64); rs.byteVecPush(out, rs.u64Low(copy$tuple2_u64_u64(pair.v)[0]) & 0xff); - rs.cellSet(pair, [copy[1], copy[0]] as [rs.u64, rs.u64]); + rs.ptrWrite(pair.v, [copy[1], copy[0]] as [rs.u64, rs.u64]); rs.byteVecPush(out, rs.u64Low(copy$tuple2_u64_u64(pair.v)[1]) & 0xff); } else if (_25 === 2) { rs.byteVecPush(out, rs.cellReplace(count, op as rs.u32) & 0xff); @@ -1134,12 +1134,12 @@ export function printed(data: rs.ByteSlice, out: rs.ByteVec): void { rs.refRelease(last); rs.refMutRelease(exclusive); } else if (_25 === 3) { - const _164: [rs.u8, rs.char] = [rs.u8WrappingAdd(pair.v[0], v), rs.u8Add(97, rs.u8Rem(v, 26)) as rs.char]; - rs.cellSet(pair, _164); + const _164: [rs.u8, rs.char] = [rs.u8WrappingAdd(copy$tuple2_u8_char(pair.v)[0], v), rs.u8Add(97, rs.u8Rem(v, 26)) as rs.char]; + rs.ptrWrite(pair.v, _164); const wide: rs.Cell = new rs.Cell(rs.u64Shl(v as rs.u64, 56)); const maybe: rs.Cell = new rs.Cell(thenSome$0quywni(rs.u8Rem(v, 2) === 0, v)); const _184: rs.Cell = new rs.Cell(undefined); - const args34 = [(f: rs.Formatter) => rs.cellDebug(() => pair.v, f, (value: [rs.u8, rs.char], f: rs.Formatter) => rs.fmtTuple([(f: rs.Formatter) => rs.u8Debug(value[0], f), (f: rs.Formatter) => rs.fmtCharDebug(value[1], f)], f)), (f: rs.Formatter) => rs.cellDebug(() => wide.v, f, rs.u64Debug), (f: rs.Formatter) => rs.cellDebug(() => maybe.v, f, (value: rs.u8 | undefined, f: rs.Formatter) => rs.fmtOption(value, f, rs.u8Debug)), (f: rs.Formatter) => rs.cellDebug(() => _184.v, f, rs.fmtUnit)]; + const args34 = [(f: rs.Formatter) => rs.cellDebug(() => copy$tuple2_u8_char(pair.v), f, (value: [rs.u8, rs.char], f: rs.Formatter) => rs.fmtTuple([(f: rs.Formatter) => rs.u8Debug(value[0], f), (f: rs.Formatter) => rs.fmtCharDebug(value[1], f)], f)), (f: rs.Formatter) => rs.cellDebug(() => wide.v, f, rs.u64Debug), (f: rs.Formatter) => rs.cellDebug(() => maybe.v, f, (value: rs.u8 | undefined, f: rs.Formatter) => rs.fmtOption(value, f, rs.u8Debug)), (f: rs.Formatter) => rs.cellDebug(() => _184.v, f, rs.fmtUnit)]; text = rs.fmtFormat([args34[0], " ", rs.fmtSpec({ alternate: true }, args34[0]), " ", args34[1], " ", args34[2], " ", rs.fmtSpec({ alternate: true }, args34[2]), " ", args34[3], " ", rs.fmtSpec({ align: ">", width: 3 }, args34[0])]); } else if (_25 === 4) { rs.cellSet(shown.cell, v); diff --git a/ts/fixtures/lang/borrows/expected/lib.ts b/ts/fixtures/lang/borrows/expected/lib.ts index 44b4c6b14..d00d97391 100644 --- a/ts/fixtures/lang/borrows/expected/lib.ts +++ b/ts/fixtures/lang/borrows/expected/lib.ts @@ -14,6 +14,10 @@ export function copy$tuple2_u64_u64(v: [rs.u64, rs.u64]): [rs.u64, rs.u64] { return [v[0], v[1]]; } +export function copy$tuple2_u8_char(v: [rs.u8, rs.char]): [rs.u8, rs.char] { + return [v[0], v[1]]; +} + export function drop$Option_cell_RefMut_borrows_Tagged(_1: rs.RefCell | undefined): void { if (_1 !== undefined) { rs.refMutRelease(_1); diff --git a/ts/fixtures/lang/collections/expected/collections.ts b/ts/fixtures/lang/collections/expected/collections.ts index 49f4eae5d..65efd5ce8 100644 --- a/ts/fixtures/lang/collections/expected/collections.ts +++ b/ts/fixtures/lang/collections/expected/collections.ts @@ -4340,14 +4340,14 @@ export function cellEqs(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void const _23: [rs.Cell, rs.Cell] = [new rs.Cell(copy$collections_Quirky(x)), new rs.Cell(copy$collections_Quirky(y))]; const ca: rs.Cell = _23[0]; const cb: rs.Cell = _23[1]; - putEq(rs.cellBy(Quirky.eq$cmp_PartialEq)(ca, cb), log, out); - putEq(!rs.cellBy(Quirky.eq$cmp_PartialEq)(ca, cb), log, out); - putEq(rs.cellBy(Quirky.lt$cmp_PartialOrd)(ca, cb), log, out); - putEq(rs.cellBy(Quirky.le$cmp_PartialOrd)(ca, cb), log, out); - putEq(rs.cellBy(Quirky.gt$cmp_PartialOrd)(ca, cb), log, out); - putEq(rs.cellBy(Quirky.ge$cmp_PartialOrd)(ca, cb), log, out); - putOrder(rs.cellBy(Quirky.partialCmp$cmp_PartialOrd)(ca, cb), log, out); - putCmp(rs.cellBy(Quirky.cmp$cmp_Ord)(ca, cb), log, out); + putEq(rs.cellBy(Quirky.eq$cmp_PartialEq, copy$collections_Quirky)(ca, cb), log, out); + putEq(!rs.cellBy(Quirky.eq$cmp_PartialEq, copy$collections_Quirky)(ca, cb), log, out); + putEq(rs.cellBy(Quirky.lt$cmp_PartialOrd, copy$collections_Quirky)(ca, cb), log, out); + putEq(rs.cellBy(Quirky.le$cmp_PartialOrd, copy$collections_Quirky)(ca, cb), log, out); + putEq(rs.cellBy(Quirky.gt$cmp_PartialOrd, copy$collections_Quirky)(ca, cb), log, out); + putEq(rs.cellBy(Quirky.ge$cmp_PartialOrd, copy$collections_Quirky)(ca, cb), log, out); + putOrder(rs.cellBy(Quirky.partialCmp$cmp_PartialOrd, copy$collections_Quirky)(ca, cb), log, out); + putCmp(rs.cellBy(Quirky.cmp$cmp_Ord, copy$collections_Quirky)(ca, cb), log, out); const _68: [rs.RefCell, rs.RefCell] = [new rs.RefCell(copy$collections_Quirky(x)), new rs.RefCell(copy$collections_Quirky(y))]; const ra: rs.RefCell = _68[0]; const rb: rs.RefCell = _68[1]; @@ -4434,40 +4434,40 @@ export function cellEqs(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void const _404: [rs.RefCell>, rs.RefCell>] = [new rs.RefCell(new rs.Cell(copy$collections_Quirky(x))), new rs.RefCell(new rs.Cell(copy$collections_Quirky(y)))]; const rca: rs.RefCell> = _404[0]; const rcb: rs.RefCell> = _404[1]; - putEq(rs.refCellBy(rs.cellBy(Quirky.eq$cmp_PartialEq))(rca, rcb), log, out); - putEq(!rs.refCellBy(rs.cellBy(Quirky.eq$cmp_PartialEq))(rca, rcb), log, out); - putEq(rs.refCellBy(rs.cellBy(Quirky.lt$cmp_PartialOrd))(rca, rcb), log, out); - putEq(rs.refCellBy(rs.cellBy(Quirky.le$cmp_PartialOrd))(rca, rcb), log, out); - putEq(rs.refCellBy(rs.cellBy(Quirky.gt$cmp_PartialOrd))(rca, rcb), log, out); - putEq(rs.refCellBy(rs.cellBy(Quirky.ge$cmp_PartialOrd))(rca, rcb), log, out); - putOrder(rs.refCellBy(rs.cellBy(Quirky.partialCmp$cmp_PartialOrd))(rca, rcb), log, out); - putCmp(rs.refCellBy(rs.cellBy(Quirky.cmp$cmp_Ord))(rca, rcb), log, out); + putEq(rs.refCellBy(rs.cellBy(Quirky.eq$cmp_PartialEq, copy$collections_Quirky))(rca, rcb), log, out); + putEq(!rs.refCellBy(rs.cellBy(Quirky.eq$cmp_PartialEq, copy$collections_Quirky))(rca, rcb), log, out); + putEq(rs.refCellBy(rs.cellBy(Quirky.lt$cmp_PartialOrd, copy$collections_Quirky))(rca, rcb), log, out); + putEq(rs.refCellBy(rs.cellBy(Quirky.le$cmp_PartialOrd, copy$collections_Quirky))(rca, rcb), log, out); + putEq(rs.refCellBy(rs.cellBy(Quirky.gt$cmp_PartialOrd, copy$collections_Quirky))(rca, rcb), log, out); + putEq(rs.refCellBy(rs.cellBy(Quirky.ge$cmp_PartialOrd, copy$collections_Quirky))(rca, rcb), log, out); + putOrder(rs.refCellBy(rs.cellBy(Quirky.partialCmp$cmp_PartialOrd, copy$collections_Quirky))(rca, rcb), log, out); + putCmp(rs.refCellBy(rs.cellBy(Quirky.cmp$cmp_Ord, copy$collections_Quirky))(rca, rcb), log, out); const _452: rs.Cell | undefined = new rs.Cell(copy$collections_Quirky(x)); const _455: rs.Cell | undefined = new rs.Cell(copy$collections_Quirky(y)); - putEq(rs.eqOption(rs.cellBy(Quirky.eq$cmp_PartialEq))(_452, _455), log, out); + putEq(rs.eqOption(rs.cellBy(Quirky.eq$cmp_PartialEq, copy$collections_Quirky))(_452, _455), log, out); const _461: rs.Cell | undefined = new rs.Cell(copy$collections_Quirky(x)); const _464: rs.Cell | undefined = new rs.Cell(copy$collections_Quirky(y)); - putEq(!rs.eqOption(rs.cellBy(Quirky.eq$cmp_PartialEq))(_461, _464), log, out); + putEq(!rs.eqOption(rs.cellBy(Quirky.eq$cmp_PartialEq, copy$collections_Quirky))(_461, _464), log, out); const _470: rs.Cell | undefined = new rs.Cell(copy$collections_Quirky(x)); const _473: rs.Cell | undefined = new rs.Cell(copy$collections_Quirky(y)); - putEq(rs.cmpOption(rs.cellBy(Quirky.partialCmp$cmp_PartialOrd))(_470, _473) === -1, log, out); + putEq(rs.cmpOption(rs.cellBy(Quirky.partialCmp$cmp_PartialOrd, copy$collections_Quirky))(_470, _473) === -1, log, out); const _479: rs.Cell | undefined = new rs.Cell(copy$collections_Quirky(x)); const _482: rs.Cell | undefined = new rs.Cell(copy$collections_Quirky(y)); - const order7 = rs.cmpOption(rs.cellBy(Quirky.partialCmp$cmp_PartialOrd))(_479, _482); + const order7 = rs.cmpOption(rs.cellBy(Quirky.partialCmp$cmp_PartialOrd, copy$collections_Quirky))(_479, _482); putEq(order7 !== undefined && order7 <= 0, log, out); const _488: rs.Cell | undefined = new rs.Cell(copy$collections_Quirky(x)); const _491: rs.Cell | undefined = new rs.Cell(copy$collections_Quirky(y)); - putEq(rs.cmpOption(rs.cellBy(Quirky.partialCmp$cmp_PartialOrd))(_488, _491) === 1, log, out); + putEq(rs.cmpOption(rs.cellBy(Quirky.partialCmp$cmp_PartialOrd, copy$collections_Quirky))(_488, _491) === 1, log, out); const _497: rs.Cell | undefined = new rs.Cell(copy$collections_Quirky(x)); const _500: rs.Cell | undefined = new rs.Cell(copy$collections_Quirky(y)); - const order8 = rs.cmpOption(rs.cellBy(Quirky.partialCmp$cmp_PartialOrd))(_497, _500); + const order8 = rs.cmpOption(rs.cellBy(Quirky.partialCmp$cmp_PartialOrd, copy$collections_Quirky))(_497, _500); putEq(order8 !== undefined && order8 >= 0, log, out); const _506: rs.Cell | undefined = new rs.Cell(copy$collections_Quirky(x)); const _509: rs.Cell | undefined = new rs.Cell(copy$collections_Quirky(y)); - putOrder(rs.cmpOption(rs.cellBy(Quirky.partialCmp$cmp_PartialOrd))(_506, _509), log, out); + putOrder(rs.cmpOption(rs.cellBy(Quirky.partialCmp$cmp_PartialOrd, copy$collections_Quirky))(_506, _509), log, out); const _515: rs.Cell | undefined = new rs.Cell(copy$collections_Quirky(x)); const _518: rs.Cell | undefined = new rs.Cell(copy$collections_Quirky(y)); - putCmp(rs.cmpOption(rs.cellBy(Quirky.cmp$cmp_Ord))(_515, _518), log, out); + putCmp(rs.cmpOption(rs.cellBy(Quirky.cmp$cmp_Ord, copy$collections_Quirky))(_515, _518), log, out); const _524: [rs.RefCell, Quirky.Quirky] = [new rs.RefCell(copy$collections_Quirky(x)), x]; const _527: [rs.RefCell, Quirky.Quirky] = [new rs.RefCell(copy$collections_Quirky(y)), y]; putEq(rs.eqTuple([rs.refCellBy(Quirky.eq$cmp_PartialEq), Quirky.eq$cmp_PartialEq])(_524, _527), log, out); @@ -4513,7 +4513,7 @@ export function cellEqs(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void const _629: rs.Vec> = each$collections_Quirky_Cell_collections_Quirky_collections_cell_eqs_closure3(rs.sliceFrom(vb.items), (_22: Quirky.Quirky): rs.Cell => { return new rs.Cell(copy$collections_Quirky(copy$collections_Quirky(_22))); }); - putEq(rs.eqSlice(rs.cellBy(Quirky.eq$cmp_PartialEq))(_625, _629), log, out); + putEq(rs.eqSlice(rs.cellBy(Quirky.eq$cmp_PartialEq, copy$collections_Quirky))(_625, _629), log, out); const _636: rs.Vec> = each$collections_Quirky_cell_RefCell_collections_Quirky_collections_cell_eqs_closure4(rs.sliceFrom(va.items), (_26: Quirky.Quirky): rs.RefCell => { return new rs.RefCell(copy$collections_Quirky(copy$collections_Quirky(_26))); }); @@ -4523,13 +4523,13 @@ export function cellEqs(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void putEq(!rs.eqSlice(rs.refCellBy(Quirky.eq$cmp_PartialEq))(_636, _640), log, out); const _647: [rs.Cell, rs.RefCell] = [new rs.Cell(copy$collections_Quirky(x)), new rs.RefCell(copy$collections_Quirky(y))]; const _651: [rs.Cell, rs.RefCell] = [new rs.Cell(copy$collections_Quirky(y)), new rs.RefCell(copy$collections_Quirky(x))]; - putEq(!rs.eqTuple([rs.cellBy(Quirky.eq$cmp_PartialEq), rs.refCellBy(Quirky.eq$cmp_PartialEq)])(_647, _651), log, out); + putEq(!rs.eqTuple([rs.cellBy(Quirky.eq$cmp_PartialEq, copy$collections_Quirky), rs.refCellBy(Quirky.eq$cmp_PartialEq)])(_647, _651), log, out); const _658: rs.Arc> = new rs.Arc(new rs.RefCell(copy$collections_Quirky(x))); const _661: rs.Arc> = new rs.Arc(new rs.RefCell(copy$collections_Quirky(y))); putEq(!rs.eqArc(rs.refCellBy(Quirky.eq$cmp_PartialEq), true)(_658, _661), log, out); _661[Symbol.dispose](); _658[Symbol.dispose](); - putEq(copy$collections_Quirky(rs.ordMax(new rs.Cell(copy$collections_Quirky(x)), new rs.Cell(copy$collections_Quirky(y)), rs.cellBy(Quirky.lt$cmp_PartialOrd)).v)._0 === x._0, log, out); + putEq(copy$collections_Quirky(rs.ordMax(new rs.Cell(copy$collections_Quirky(x)), new rs.Cell(copy$collections_Quirky(y)), rs.cellBy(Quirky.lt$cmp_PartialOrd, copy$collections_Quirky)).v)._0 === x._0, log, out); const _679: rs.RefCell = rs.refCellBorrow(rs.ordMin(new rs.RefCell(copy$collections_Quirky(x)), new rs.RefCell(copy$collections_Quirky(y)), rs.refCellBy(Quirky.lt$cmp_PartialOrd))); putEq(_679.value._0 === x._0, log, out); rs.refRelease(_679); @@ -4540,7 +4540,7 @@ export function cellEqs(kind: rs.u8, data: rs.ByteSlice, out: rs.ByteVec): void } const lo: Quirky.Quirky = _688[0]; const hi: Quirky.Quirky = _688[1]; - rs.byteVecPush(out, copy$collections_Quirky(rs.ordClamp(new rs.Cell({ _0: at(2), _1: log }), new rs.Cell(copy$collections_Quirky(lo)), new rs.Cell(copy$collections_Quirky(hi)), rs.cellBy(Quirky.le$cmp_PartialOrd), rs.cellBy(Quirky.lt$cmp_PartialOrd), rs.cellBy(Quirky.gt$cmp_PartialOrd)).v)._0 & 0xff); + rs.byteVecPush(out, copy$collections_Quirky(rs.ordClamp(new rs.Cell({ _0: at(2), _1: log }), new rs.Cell(copy$collections_Quirky(lo)), new rs.Cell(copy$collections_Quirky(hi)), rs.cellBy(Quirky.le$cmp_PartialOrd, copy$collections_Quirky), rs.cellBy(Quirky.lt$cmp_PartialOrd, copy$collections_Quirky), rs.cellBy(Quirky.gt$cmp_PartialOrd, copy$collections_Quirky)).v)._0 & 0xff); rs.iterExtendBytes(out, rs.iterSlice(rs.u16ToBeBytes(rs.cellReplace(log, 0)).reverse()), undefined, true); const once: (a0: rs.usize, a1: Quirky.Quirky) => rs.OnceCell = (i3: rs.usize, v: Quirky.Quirky): rs.OnceCell => { const cell: rs.OnceCell = new rs.OnceCell(undefined); diff --git a/ts/fixtures/lang/conversions/expected/conversions.ts b/ts/fixtures/lang/conversions/expected/conversions.ts index 7cb3d4fe4..3a08aa9d1 100644 --- a/ts/fixtures/lang/conversions/expected/conversions.ts +++ b/ts/fixtures/lang/conversions/expected/conversions.ts @@ -773,7 +773,12 @@ export function lentParam$Option_u16(to: rs.Place, data: rs. rs.idx(s, 0); const borrowed6 = s.data; const borrowed7 = s.start; - put$conversions_Value_Option_u16(rs.cellReplace(rs.cellIn(rs.sliceView(rs.sliceOfPlace(rs.place(() => borrowed6[borrowed7], (value6) => borrowed6[borrowed7] = value6)))), [make$conversions_Value_Option_u16(data, 26)])[0], out); + const _114: rs.Cell> = rs.cellOfPlace(rs.partPlace(rs.sliceView(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)); + rs.sliceSet(pointer, _121); + put$conversions_Value_Option_u16(old6[0], out); rs.idx(s, 0); const borrowed8 = s.data; const borrowed9 = s.start; @@ -835,7 +840,12 @@ 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; - put$conversions_Value_String(rs.cellReplace(rs.cellIn(rs.sliceView(rs.sliceOfPlace(rs.place(() => borrowed3[borrowed4], (value3) => borrowed3[borrowed4] = value3))), 1), [make$conversions_Value_String(data, 26)])[0], out); + const _114: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(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); + rs.sliceSet(pointer, _121); + put$conversions_Value_String(old6[0], out); rs.idx(s, 0); const borrowed5 = s.data; const borrowed6 = s.start; @@ -897,7 +907,12 @@ 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; - put$conversions_Value_Vec_u32(rs.cellReplace(rs.cellIn(rs.sliceView(rs.sliceOfPlace(rs.place(() => borrowed3[borrowed4], (value3) => borrowed3[borrowed4] = value3))), 1), [make$conversions_Value_Vec_u32(data, 26)])[0], out); + const _114: rs.Cell[]> = rs.cellOfPlace(rs.partPlace(rs.sliceView(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); + rs.sliceSet(pointer, _121); + put$conversions_Value_Vec_u32(old6[0], out); rs.idx(s, 0); const borrowed5 = s.data; const borrowed6 = s.start; @@ -959,7 +974,12 @@ 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; - put$conversions_Value_Vec_u8(rs.cellReplace(rs.cellIn(rs.sliceView(rs.sliceOfPlace(rs.place(() => borrowed3[borrowed4], (value3) => borrowed3[borrowed4] = value3))), 1), [make$conversions_Value_Vec_u8(data, 26)])[0], out); + const _114: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(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); + rs.sliceSet(pointer, _121); + put$conversions_Value_Vec_u8(old6[0], out); rs.idx(s, 0); const borrowed5 = s.data; const borrowed6 = s.start; @@ -1015,7 +1035,7 @@ export function lentParam$array0_u8(to: rs.ByteSlice, data: rs.ByteSlice, out: r rs.idx(s, 0); put$conversions_Value_array0_u8(rs.arraySliceAt(s, 0), out); rs.idx(s, 0); - put$conversions_Value_array0_u8(rs.byteSliceFrom(rs.cellReplace(rs.cellIn(rs.byteSliceView(rs.arraySliceAt(s, 0))), copy$array_u8(make$conversions_Value_array0_u8(data, 25)))), out); + put$conversions_Value_array0_u8(rs.byteSliceFrom(rs.cellReplace(rs.cellOfPlace(rs.partPlace(rs.byteSliceView(rs.arraySliceAt(s, 0)))), copy$array_u8(make$conversions_Value_array0_u8(data, 25)))), out); rs.idx(s, 0); put$conversions_Value_array0_u8(rs.byteSliceFrom(rs.cellReplace(rs.cellOfArraySlice(rs.arraySliceOne(rs.arraySliceAt(s, 0), 0)), [copy$array_u8(make$conversions_Value_array0_u8(data, 26))])[0]), out); rs.idx(s, 0); @@ -1089,7 +1109,12 @@ export function lentParam$array1_u8(to: rs.ByteSlice, data: rs.ByteSlice, out: r rs.idx(s, 0); put$conversions_Value_array1_u8(rs.arraySliceAt(s, 0), out); rs.idx(s, 0); - put$conversions_Value_array1_u8(rs.byteSliceFrom(rs.cellReplace(rs.cellIn(rs.byteSliceView(rs.arraySliceAt(s, 0))), copy$array_u8(make$conversions_Value_array1_u8(data, 25)))), out); + const _105: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.byteSliceView(rs.arraySliceAt(s, 0)))); + const _111: Uint8Array = copy$array_u8(make$conversions_Value_array1_u8(data, 25)); + const pointer = rs.byteSliceFrom(_105.v); + const old6 = rs.byteSliceToArray(pointer); + 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); rs.idx(s, 0); @@ -1154,7 +1179,12 @@ export function lentParam$array2_u32(to: rs.Slice, data: rs.ByteSlice, o rs.idx(s, 0); put$conversions_Value_array2_u32(rs.arraySliceAt(s, 0), out); rs.idx(s, 0); - put$conversions_Value_array2_u32(rs.sliceFrom(rs.cellReplace(rs.cellIn(rs.sliceView(rs.arraySliceAt(s, 0))), copy$array_u32(make$conversions_Value_array2_u32(data, 25)))), out); + const _105: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(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)); + 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); rs.idx(s, 0); @@ -1227,7 +1257,12 @@ export function lentParam$array3_u8(to: rs.ByteSlice, data: rs.ByteSlice, out: r rs.idx(s, 0); put$conversions_Value_array3_u8(rs.arraySliceAt(s, 0), out); rs.idx(s, 0); - put$conversions_Value_array3_u8(rs.byteSliceFrom(rs.cellReplace(rs.cellIn(rs.byteSliceView(rs.arraySliceAt(s, 0))), copy$array_u8(make$conversions_Value_array3_u8(data, 25)))), out); + const _105: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.byteSliceView(rs.arraySliceAt(s, 0)))); + const _111: Uint8Array = copy$array_u8(make$conversions_Value_array3_u8(data, 25)); + const pointer = rs.byteSliceFrom(_105.v); + const old6 = rs.byteSliceToArray(pointer); + 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); rs.idx(s, 0); @@ -1301,7 +1336,12 @@ export function lentParam$array40_u8(to: rs.ByteSlice, data: rs.ByteSlice, out: rs.idx(s, 0); put$conversions_Value_array40_u8(rs.arraySliceAt(s, 0), out); rs.idx(s, 0); - put$conversions_Value_array40_u8(rs.byteSliceFrom(rs.cellReplace(rs.cellIn(rs.byteSliceView(rs.arraySliceAt(s, 0))), copy$array_u8(make$conversions_Value_array40_u8(data, 25)))), out); + const _105: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.byteSliceView(rs.arraySliceAt(s, 0)))); + const _111: Uint8Array = copy$array_u8(make$conversions_Value_array40_u8(data, 25)); + const pointer = rs.byteSliceFrom(_105.v); + const old6 = rs.byteSliceToArray(pointer); + 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); rs.idx(s, 0); @@ -1367,13 +1407,23 @@ export function lentParam$conversions_Logged(to: Logged.Logged, data: rs.ByteSli rs.idx(s, 0); Logged.put$conversions_Value(s.data[s.start], out); rs.idx(s, 0); - const _104: Logged.Logged = rs.cellReplace(rs.cellIn(s.data[s.start]), Logged.make$conversions_Value(data, 25)); + const _105: rs.Cell = rs.cellOfPlace(rs.partPlace(s.data[s.start])); + const _111: Logged.Logged = Logged.make$conversions_Value(data, 25); + const pointer = _105.v; + const old6 = rs.objectCopy(pointer); + rs.ptrWrite(pointer, _111); + const _104: Logged.Logged = old6; Logged.put$conversions_Value(_104, out); _104[Symbol.dispose](); rs.idx(s, 0); const borrowed3 = s.data; const borrowed4 = s.start; - const old: Logged.Logged = rs.cellReplace(rs.cellIn(rs.sliceView(rs.sliceOfPlace(rs.place(() => borrowed3[borrowed4], (value3) => borrowed3[borrowed4] = value3))), 1), [Logged.make$conversions_Value(data, 26)])[0]; + const _114: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(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); + rs.sliceSet(pointer2, _121); + const old: Logged.Logged = old7[0]; Logged.put$conversions_Value(old, out); rs.idx(s, 0); const borrowed5 = s.data; @@ -1440,11 +1490,21 @@ export function lentParam$conversions_Named(to: Named.Named, data: rs.ByteSlice, rs.idx(s, 0); Named.put$conversions_Value(s.data[s.start], out); rs.idx(s, 0); - Named.put$conversions_Value(rs.cellReplace(rs.cellIn(s.data[s.start]), Named.make$conversions_Value(data, 25)), out); + const _105: rs.Cell = rs.cellOfPlace(rs.partPlace(s.data[s.start])); + const _111: Named.Named = Named.make$conversions_Value(data, 25); + const pointer = _105.v; + const old6 = rs.objectCopy(pointer); + rs.ptrWrite(pointer, _111); + Named.put$conversions_Value(old6, out); rs.idx(s, 0); const borrowed3 = s.data; const borrowed4 = s.start; - Named.put$conversions_Value(rs.cellReplace(rs.cellIn(rs.sliceView(rs.sliceOfPlace(rs.place(() => borrowed3[borrowed4], (value3) => borrowed3[borrowed4] = value3))), 1), [Named.make$conversions_Value(data, 26)])[0], out); + const _114: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(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); + rs.sliceSet(pointer2, _121); + Named.put$conversions_Value(old7[0], out); rs.idx(s, 0); const borrowed5 = s.data; const borrowed6 = s.start; @@ -1517,7 +1577,12 @@ export function lentParam$u32(to: rs.Place, data: rs.ByteSlice, out: rs. rs.idx(s, 0); const borrowed6 = s.data; const borrowed7 = s.start; - put$conversions_Value_u32(rs.cellReplace(rs.cellIn(rs.sliceView(rs.sliceOfPlace(rs.place(() => borrowed6[borrowed7], (value6) => borrowed6[borrowed7] = value6)))), [make$conversions_Value_u32(data, 26)])[0], out); + const _114: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(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)); + rs.sliceSet(pointer, _121); + put$conversions_Value_u32(old6[0], out); rs.idx(s, 0); const borrowed8 = s.data; const borrowed9 = s.start; @@ -1590,7 +1655,12 @@ export function lentParam$u64(to: rs.Place, data: rs.ByteSlice, out: rs. rs.idx(s, 0); const borrowed6 = s.data; const borrowed7 = s.start; - put$conversions_Value_u64(rs.cellReplace(rs.cellIn(rs.sliceView(rs.sliceOfPlace(rs.place(() => borrowed6[borrowed7], (value6) => borrowed6[borrowed7] = value6)))), [make$conversions_Value_u64(data, 26)])[0], out); + const _114: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(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)); + rs.sliceSet(pointer, _121); + put$conversions_Value_u64(old6[0], out); rs.idx(s, 0); const borrowed8 = s.data; const borrowed9 = s.start; @@ -1948,37 +2018,55 @@ export function setThrough$Vec_u8(to: rs.ByteVec, value: rs.ByteVec): rs.ByteVec /** A cell of what a `&mut` whose place only the caller knows points at, written through. */ export function setThrough$array0_u8(to: rs.ByteSlice, value: Uint8Array): Uint8Array { - return rs.cellReplace(rs.cellIn(rs.byteSliceView(to)), copy$array_u8(value)); + return rs.cellReplace(rs.cellOfPlace(rs.partPlace(rs.byteSliceView(to))), copy$array_u8(value)); } /** A cell of what a `&mut` whose place only the caller knows points at, written through. */ export function setThrough$array1_u8(to: rs.ByteSlice, value: Uint8Array): Uint8Array { - return rs.cellReplace(rs.cellIn(rs.byteSliceView(to)), copy$array_u8(value)); + const pointer = rs.byteSliceFrom(rs.cellOfPlace(rs.partPlace(rs.byteSliceView(to))).v); + const old = rs.byteSliceToArray(pointer); + rs.byteSliceSet(pointer, copy$array_u8(value)); + return old; } /** 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[] { - return rs.cellReplace(rs.cellIn(rs.sliceView(to)), copy$array_u32(value)); + const pointer = rs.sliceFrom(rs.cellOfPlace(rs.partPlace(rs.sliceView(to))).v); + const old = rs.objectCopy(rs.sliceView(pointer)); + rs.sliceSet(pointer, copy$array_u32(value)); + return old; } /** A cell of what a `&mut` whose place only the caller knows points at, written through. */ export function setThrough$array3_u8(to: rs.ByteSlice, value: Uint8Array): Uint8Array { - return rs.cellReplace(rs.cellIn(rs.byteSliceView(to)), copy$array_u8(value)); + const pointer = rs.byteSliceFrom(rs.cellOfPlace(rs.partPlace(rs.byteSliceView(to))).v); + const old = rs.byteSliceToArray(pointer); + rs.byteSliceSet(pointer, copy$array_u8(value)); + return old; } /** A cell of what a `&mut` whose place only the caller knows points at, written through. */ export function setThrough$array40_u8(to: rs.ByteSlice, value: Uint8Array): Uint8Array { - return rs.cellReplace(rs.cellIn(rs.byteSliceView(to)), copy$array_u8(value)); + const pointer = rs.byteSliceFrom(rs.cellOfPlace(rs.partPlace(rs.byteSliceView(to))).v); + const old = rs.byteSliceToArray(pointer); + rs.byteSliceSet(pointer, copy$array_u8(value)); + return old; } /** A cell of what a `&mut` whose place only the caller knows points at, written through. */ export function setThrough$conversions_Logged(to: Logged.Logged, value: Logged.Logged): Logged.Logged { - return rs.cellReplace(rs.cellIn(to), value); + const pointer = rs.cellOfPlace(rs.partPlace(to)).v; + const old = rs.objectCopy(pointer); + rs.ptrWrite(pointer, value); + return old; } /** A cell of what a `&mut` whose place only the caller knows points at, written through. */ export function setThrough$conversions_Named(to: Named.Named, value: Named.Named): Named.Named { - return rs.cellReplace(rs.cellIn(to), value); + const pointer = rs.cellOfPlace(rs.partPlace(to)).v; + const old = rs.objectCopy(pointer); + rs.ptrWrite(pointer, value); + return old; } /** A cell of what a `&mut` whose place only the caller knows points at, written through. */ @@ -2391,14 +2479,14 @@ export function converted$array0_u8(data: rs.ByteSlice, out: rs.ByteVec): void { _70.data.set(rs.byteSliceToArray(_71), _70.start); put$conversions_Value_array0_u8(rs.byteSliceFrom(copied), out); put$conversions_Value_array0_u8(rs.byteSliceFrom(a), out); - const cell: rs.Cell = rs.cellIn(rs.byteSliceView(rs.byteSliceFrom(c))); + const cell: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.byteSliceView(rs.byteSliceFrom(c)))); const old: Uint8Array = rs.cellReplace(cell, copy$array_u8(make$conversions_Value_array0_u8(data, 10))); rs.cellSet(cell, copy$array_u8(make$conversions_Value_array0_u8(data, 11))); put$conversions_Value_array0_u8(rs.byteSliceFrom(old), out); put$conversions_Value_array0_u8(rs.byteSliceFrom(c), out); put$conversions_Value_array0_u8(rs.byteSliceFrom(setThrough$array0_u8(rs.byteSliceFrom(v.items[rs.idx(v.items, 0)]), make$conversions_Value_array0_u8(data, 12))), out); put$conversions_Value_array0_u8(rs.byteSliceFrom(v.items[rs.idx(v.items, 0)]), out); - rs.cellSet(rs.cellIn(rs.byteSliceView(rs.byteSliceFrom(held.value))), copy$array_u8(make$conversions_Value_array0_u8(data, 17))); + rs.cellSet(rs.cellOfPlace(rs.partPlace(rs.byteSliceView(rs.byteSliceFrom(held.value)))), copy$array_u8(make$conversions_Value_array0_u8(data, 17))); put$conversions_Value_array0_u8(rs.byteSliceFrom(held.value), out); const array: Uint8Array[] = [copy$array_u8(make$conversions_Value_array0_u8(data, 13)), copy$array_u8(make$conversions_Value_array0_u8(data, 14)), copy$array_u8(make$conversions_Value_array0_u8(data, 15))]; rs.iterExtendBytes(out, rs.iterSlice(rs.bytesMap([rs.arraySliceFrom(array, rs.byteSliceFrom).length, rs.arraySliceFrom(array, rs.byteSliceFrom).length], (n: rs.usize): rs.u8 => { @@ -2501,14 +2589,21 @@ export function converted$array1_u8(data: rs.ByteSlice, out: rs.ByteVec): void { _70.data.set(rs.byteSliceToArray(_71), _70.start); put$conversions_Value_array1_u8(rs.byteSliceFrom(copied), out); put$conversions_Value_array1_u8(rs.byteSliceFrom(a), out); - const cell: rs.Cell = rs.cellIn(rs.byteSliceView(rs.byteSliceFrom(c))); - const old: Uint8Array = rs.cellReplace(cell, copy$array_u8(make$conversions_Value_array1_u8(data, 10))); - rs.cellSet(cell, copy$array_u8(make$conversions_Value_array1_u8(data, 11))); + const cell: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.byteSliceView(rs.byteSliceFrom(c)))); + const _79: Uint8Array = copy$array_u8(make$conversions_Value_array1_u8(data, 10)); + const pointer = rs.byteSliceFrom(cell.v); + const old2 = rs.byteSliceToArray(pointer); + rs.byteSliceSet(pointer, _79); + const old: Uint8Array = old2; + const _81: Uint8Array = copy$array_u8(make$conversions_Value_array1_u8(data, 11)); + rs.byteSliceSet(rs.byteSliceFrom(cell.v), _81); put$conversions_Value_array1_u8(rs.byteSliceFrom(old), out); put$conversions_Value_array1_u8(rs.byteSliceFrom(c), out); put$conversions_Value_array1_u8(rs.byteSliceFrom(setThrough$array1_u8(rs.byteSliceFrom(v.items[rs.idx(v.items, 0)]), make$conversions_Value_array1_u8(data, 12))), out); put$conversions_Value_array1_u8(rs.byteSliceFrom(v.items[rs.idx(v.items, 0)]), out); - rs.cellSet(rs.cellIn(rs.byteSliceView(rs.byteSliceFrom(held.value))), copy$array_u8(make$conversions_Value_array1_u8(data, 17))); + const _96: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.byteSliceView(rs.byteSliceFrom(held.value)))); + const _98: Uint8Array = copy$array_u8(make$conversions_Value_array1_u8(data, 17)); + rs.byteSliceSet(rs.byteSliceFrom(_96.v), _98); put$conversions_Value_array1_u8(rs.byteSliceFrom(held.value), out); const array: Uint8Array[] = [copy$array_u8(make$conversions_Value_array1_u8(data, 13)), copy$array_u8(make$conversions_Value_array1_u8(data, 14)), copy$array_u8(make$conversions_Value_array1_u8(data, 15))]; rs.iterExtendBytes(out, rs.iterSlice(rs.bytesMap([rs.arraySliceFrom(array, rs.byteSliceFrom).length, rs.arraySliceFrom(array, rs.byteSliceFrom).length], (n: rs.usize): rs.u8 => { @@ -2610,14 +2705,21 @@ export function converted$array2_u32(data: rs.ByteSlice, out: rs.ByteVec): void rs.replaceIn(rs.sliceView(_70), rs.sliceToArray(_71)); put$conversions_Value_array2_u32(rs.sliceFrom(copied), out); put$conversions_Value_array2_u32(rs.sliceFrom(a), out); - const cell: rs.Cell = rs.cellIn(rs.sliceView(rs.sliceFrom(c))); - const old: rs.u32[] = rs.cellReplace(cell, copy$array_u32(make$conversions_Value_array2_u32(data, 10))); - rs.cellSet(cell, copy$array_u32(make$conversions_Value_array2_u32(data, 11))); + const cell: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(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)); + 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); 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); - rs.cellSet(rs.cellIn(rs.sliceView(rs.sliceFrom(held.value))), copy$array_u32(make$conversions_Value_array2_u32(data, 17))); + const _96: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.sliceView(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); 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 => { @@ -2715,14 +2817,21 @@ export function converted$array3_u8(data: rs.ByteSlice, out: rs.ByteVec): void { _70.data.set(rs.byteSliceToArray(_71), _70.start); put$conversions_Value_array3_u8(rs.byteSliceFrom(copied), out); put$conversions_Value_array3_u8(rs.byteSliceFrom(a), out); - const cell: rs.Cell = rs.cellIn(rs.byteSliceView(rs.byteSliceFrom(c))); - const old: Uint8Array = rs.cellReplace(cell, copy$array_u8(make$conversions_Value_array3_u8(data, 10))); - rs.cellSet(cell, copy$array_u8(make$conversions_Value_array3_u8(data, 11))); + const cell: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.byteSliceView(rs.byteSliceFrom(c)))); + const _79: Uint8Array = copy$array_u8(make$conversions_Value_array3_u8(data, 10)); + const pointer = rs.byteSliceFrom(cell.v); + const old2 = rs.byteSliceToArray(pointer); + rs.byteSliceSet(pointer, _79); + const old: Uint8Array = old2; + const _81: Uint8Array = copy$array_u8(make$conversions_Value_array3_u8(data, 11)); + rs.byteSliceSet(rs.byteSliceFrom(cell.v), _81); put$conversions_Value_array3_u8(rs.byteSliceFrom(old), out); put$conversions_Value_array3_u8(rs.byteSliceFrom(c), out); put$conversions_Value_array3_u8(rs.byteSliceFrom(setThrough$array3_u8(rs.byteSliceFrom(v.items[rs.idx(v.items, 0)]), make$conversions_Value_array3_u8(data, 12))), out); put$conversions_Value_array3_u8(rs.byteSliceFrom(v.items[rs.idx(v.items, 0)]), out); - rs.cellSet(rs.cellIn(rs.byteSliceView(rs.byteSliceFrom(held.value))), copy$array_u8(make$conversions_Value_array3_u8(data, 17))); + const _96: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.byteSliceView(rs.byteSliceFrom(held.value)))); + const _98: Uint8Array = copy$array_u8(make$conversions_Value_array3_u8(data, 17)); + rs.byteSliceSet(rs.byteSliceFrom(_96.v), _98); put$conversions_Value_array3_u8(rs.byteSliceFrom(held.value), out); const array: Uint8Array[] = [copy$array_u8(make$conversions_Value_array3_u8(data, 13)), copy$array_u8(make$conversions_Value_array3_u8(data, 14)), copy$array_u8(make$conversions_Value_array3_u8(data, 15))]; rs.iterExtendBytes(out, rs.iterSlice(rs.bytesMap([rs.arraySliceFrom(array, rs.byteSliceFrom).length, rs.arraySliceFrom(array, rs.byteSliceFrom).length], (n: rs.usize): rs.u8 => { @@ -2826,14 +2935,21 @@ export function converted$array40_u8(data: rs.ByteSlice, out: rs.ByteVec): void _70.data.set(rs.byteSliceToArray(_71), _70.start); put$conversions_Value_array40_u8(rs.byteSliceFrom(copied), out); put$conversions_Value_array40_u8(rs.byteSliceFrom(a), out); - const cell: rs.Cell = rs.cellIn(rs.byteSliceView(rs.byteSliceFrom(c))); - const old: Uint8Array = rs.cellReplace(cell, copy$array_u8(make$conversions_Value_array40_u8(data, 10))); - rs.cellSet(cell, copy$array_u8(make$conversions_Value_array40_u8(data, 11))); + const cell: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.byteSliceView(rs.byteSliceFrom(c)))); + const _79: Uint8Array = copy$array_u8(make$conversions_Value_array40_u8(data, 10)); + const pointer = rs.byteSliceFrom(cell.v); + const old2 = rs.byteSliceToArray(pointer); + rs.byteSliceSet(pointer, _79); + const old: Uint8Array = old2; + const _81: Uint8Array = copy$array_u8(make$conversions_Value_array40_u8(data, 11)); + rs.byteSliceSet(rs.byteSliceFrom(cell.v), _81); put$conversions_Value_array40_u8(rs.byteSliceFrom(old), out); put$conversions_Value_array40_u8(rs.byteSliceFrom(c), out); put$conversions_Value_array40_u8(rs.byteSliceFrom(setThrough$array40_u8(rs.byteSliceFrom(v.items[rs.idx(v.items, 0)]), make$conversions_Value_array40_u8(data, 12))), out); put$conversions_Value_array40_u8(rs.byteSliceFrom(v.items[rs.idx(v.items, 0)]), out); - rs.cellSet(rs.cellIn(rs.byteSliceView(rs.byteSliceFrom(held.value))), copy$array_u8(make$conversions_Value_array40_u8(data, 17))); + const _96: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.byteSliceView(rs.byteSliceFrom(held.value)))); + const _98: Uint8Array = copy$array_u8(make$conversions_Value_array40_u8(data, 17)); + rs.byteSliceSet(rs.byteSliceFrom(_96.v), _98); put$conversions_Value_array40_u8(rs.byteSliceFrom(held.value), out); const array: Uint8Array[] = [copy$array_u8(make$conversions_Value_array40_u8(data, 13)), copy$array_u8(make$conversions_Value_array40_u8(data, 14)), copy$array_u8(make$conversions_Value_array40_u8(data, 15))]; rs.iterExtendBytes(out, rs.iterSlice(rs.bytesMap([rs.arraySliceFrom(array, rs.byteSliceFrom).length, rs.arraySliceFrom(array, rs.byteSliceFrom).length], (n: rs.usize): rs.u8 => { @@ -2939,9 +3055,17 @@ export function converted$conversions_Logged(data: rs.ByteSlice, out: rs.ByteVec old7[Symbol.dispose](); Logged.put$conversions_Value(copied, out); Logged.put$conversions_Value(a, out); - const cell: rs.Cell = rs.cellIn(c); - const old: Logged.Logged = rs.cellReplace(cell, Logged.make$conversions_Value(data, 10)); - rs.cellSet(cell, Logged.make$conversions_Value(data, 11), rs.drop); + const cell: rs.Cell = rs.cellOfPlace(rs.partPlace(c)); + const _79: Logged.Logged = Logged.make$conversions_Value(data, 10); + const pointer = cell.v; + const old8 = rs.objectCopy(pointer); + rs.ptrWrite(pointer, _79); + const old: Logged.Logged = old8; + const _81: Logged.Logged = Logged.make$conversions_Value(data, 11); + const pointer2 = cell.v; + const old9 = rs.objectCopy(pointer2); + rs.ptrWrite(pointer2, _81); + old9[Symbol.dispose](); Logged.put$conversions_Value(old, out); Logged.put$conversions_Value(c, out); const at5 = rs.idx(v.items, 0); @@ -2950,7 +3074,12 @@ export function converted$conversions_Logged(data: rs.ByteSlice, out: rs.ByteVec Logged.put$conversions_Value(_88, out); _88[Symbol.dispose](); Logged.put$conversions_Value(v.items[rs.idx(v.items, 0)], out); - rs.cellSet(rs.cellIn(held.value), Logged.make$conversions_Value(data, 17), rs.drop); + const _96: rs.Cell = rs.cellOfPlace(rs.partPlace(held.value)); + const _98: Logged.Logged = Logged.make$conversions_Value(data, 17); + const pointer3 = _96.v; + const old10 = rs.objectCopy(pointer3); + rs.ptrWrite(pointer3, _98); + old10[Symbol.dispose](); Logged.put$conversions_Value(held.value, out); const array: Logged.Logged[] = [Logged.make$conversions_Value(data, 13), Logged.make$conversions_Value(data, 14), Logged.make$conversions_Value(data, 15)]; rs.iterExtendBytes(out, rs.iterSlice(rs.bytesMap([rs.sliceFrom(array).length, rs.sliceFrom(array).length], (n: rs.usize): rs.u8 => { @@ -3045,16 +3174,23 @@ export function converted$conversions_Named(data: rs.ByteSlice, out: rs.ByteVec) a = Named.clone$Clone(copied); Named.put$conversions_Value(copied, out); Named.put$conversions_Value(a, out); - const cell: rs.Cell = rs.cellIn(c); - const old: Named.Named = rs.cellReplace(cell, Named.make$conversions_Value(data, 10)); - rs.cellSet(cell, Named.make$conversions_Value(data, 11)); + const cell: rs.Cell = rs.cellOfPlace(rs.partPlace(c)); + const _79: Named.Named = Named.make$conversions_Value(data, 10); + const pointer = cell.v; + const old2 = rs.objectCopy(pointer); + rs.ptrWrite(pointer, _79); + const old: Named.Named = old2; + const _81: Named.Named = Named.make$conversions_Value(data, 11); + rs.ptrWrite(cell.v, _81); Named.put$conversions_Value(old, out); Named.put$conversions_Value(c, out); const at5 = rs.idx(v.items, 0); const _91: Named.Named = Named.make$conversions_Value(data, 12); Named.put$conversions_Value(setThrough$conversions_Named(v.items[at5], _91), out); Named.put$conversions_Value(v.items[rs.idx(v.items, 0)], out); - rs.cellSet(rs.cellIn(held.value), Named.make$conversions_Value(data, 17)); + const _96: rs.Cell = rs.cellOfPlace(rs.partPlace(held.value)); + const _98: Named.Named = Named.make$conversions_Value(data, 17); + rs.ptrWrite(_96.v, _98); Named.put$conversions_Value(held.value, out); const array: Named.Named[] = [Named.make$conversions_Value(data, 13), Named.make$conversions_Value(data, 14), Named.make$conversions_Value(data, 15)]; rs.iterExtendBytes(out, rs.iterSlice(rs.bytesMap([rs.sliceFrom(array).length, rs.sliceFrom(array).length], (n: rs.usize): rs.u8 => { diff --git a/ts/fixtures/lang/dyns/expected/dyns.ts b/ts/fixtures/lang/dyns/expected/dyns.ts index a89507525..3b9eb51db 100644 --- a/ts/fixtures/lang/dyns/expected/dyns.ts +++ b/ts/fixtures/lang/dyns/expected/dyns.ts @@ -2204,11 +2204,17 @@ export function rests(dataData: Uint8Array, dataStart: number, dataLen: number, dropped(out); locked[Symbol.dispose](); dropped(out); - let slot: rs.Cell = (undefined as unknown) as rs.Cell; + let slot: rs.Cell = (new rs.Cell(undefined) as unknown) as rs.Cell; const thin: rs.Place> = rs.place(() => slot, (value22) => slot = value22); const wide: rs.Place> = rs.rawUnsizePlace(thin, (p12) => rs.tailDyn(p12, { v: (value23: rs.Cell) => new ofPlace$u32(value23) })); const null_: boolean = wide === rs.NULL; - thin.v = new rs.Cell(a as rs.u32); + const pointer = thin; + const value24 = new rs.Cell(a as rs.u32); + if (pointer.v === undefined) { + pointer.v = value24; + } else { + pointer.v.v = value24.v; + } wide.v.v.grow$Shape(b); const area5: rs.u32 = wide.v.v.area$Shape(); const _677: rs.u32 = slot.v; diff --git a/ts/fixtures/lang/locals/expected/lib.ts b/ts/fixtures/lang/locals/expected/lib.ts index 4d402e1fd..99773d02a 100644 --- a/ts/fixtures/lang/locals/expected/lib.ts +++ b/ts/fixtures/lang/locals/expected/lib.ts @@ -12,6 +12,10 @@ export function copy$tuple2_locals_Twin_locals_Twin(v: [Twin.Twin, Twin.Twin]): return [copy$locals_Twin(v[0]), copy$locals_Twin(v[1])]; } +export function copy$tuple2_u8_u8(v: [rs.u8, rs.u8]): [rs.u8, rs.u8] { + return [v[0], v[1]]; +} + /** * Each case's name and what it runs. The first two bytes, big-endian, pick one modulo * their count, so a case added at the end moves no other. diff --git a/ts/fixtures/lang/locals/expected/locals.ts b/ts/fixtures/lang/locals/expected/locals.ts index 0e82c8bd5..6dcc73831 100644 --- a/ts/fixtures/lang/locals/expected/locals.ts +++ b/ts/fixtures/lang/locals/expected/locals.ts @@ -1,7 +1,7 @@ // Generated by rust2-ts. Do not edit. import * as rs from "./rs.ts"; -import { copy$locals_Twin } from "./lib.ts"; +import { copy$locals_Twin, copy$tuple2_u8_u8 } from "./lib.ts"; import { thenSome$1qfl7tz } from "./core/bool.ts"; import { mapOr$14nyq77 as option_mapOr$14nyq77, mapOr$0543jy8 as option_mapOr$0543jy8, mapOr$1idpb1d as option_mapOr$1idpb1d } from "./core/option.ts"; import { mapOr$12d9lqr as result_mapOr$12d9lqr } from "./core/result.ts"; @@ -258,13 +258,14 @@ export function serial(reset: boolean): rs.u8 { return ((next: rs.Cell<[rs.u8, rs.u8]>): rs.u8 => { let _4!: [rs.u8, rs.u8]; if (!reset) { - _4 = next.v; + _4 = copy$tuple2_u8_u8(next.v); } else { _4 = [0, 4] as [rs.u8, rs.u8]; } const n: rs.u8 = _4[0]; const end: rs.u8 = _4[1]; - rs.cellSet(next, [rs.u8WrappingAdd(n, !reset ? 1 : 0), end] as [rs.u8, rs.u8]); + const _6: [rs.u8, rs.u8] = [rs.u8WrappingAdd(n, !reset ? 1 : 0), end]; + rs.ptrWrite(next.v, _6); return n; })(NEXT$serial.get()); } diff --git a/ts/fixtures/lang/manual/expected/lib.ts b/ts/fixtures/lang/manual/expected/lib.ts index fde5ceb36..edefa48c1 100644 --- a/ts/fixtures/lang/manual/expected/lib.ts +++ b/ts/fixtures/lang/manual/expected/lib.ts @@ -27,6 +27,10 @@ export function copy$tuple2_u8_u16(v: [rs.u8, rs.u16]): [rs.u8, rs.u16] { return [v[0], v[1]]; } +export function copy$tuple2_u8_u8(v: [rs.u8, rs.u8]): [rs.u8, rs.u8] { + return [v[0], v[1]]; +} + /** * Each case's name and what it runs. The first two bytes, big-endian, pick one modulo * their count, so a case added at the end moves no other. diff --git a/ts/fixtures/lang/manual/expected/uninit.Counted.ts b/ts/fixtures/lang/manual/expected/uninit.Counted.ts index af84b7397..58f6989b4 100644 --- a/ts/fixtures/lang/manual/expected/uninit.Counted.ts +++ b/ts/fixtures/lang/manual/expected/uninit.Counted.ts @@ -1,6 +1,7 @@ // Generated by rust2-ts. Do not edit. import * as rs from "./rs.ts"; +import { copy$tuple2_u8_u8 } from "./lib.ts"; /** Counts its clones and drops, so a write that clones in shows it drops nothing. */ export class Counted { @@ -18,16 +19,22 @@ export class Counted { } export function clone$Clone(self: Counted): Counted { - const _4: [rs.u8, rs.u8] = self._1.v; + const _4: [rs.u8, rs.u8] = copy$tuple2_u8_u8(self._1.v); const c: rs.u8 = _4[0]; const d: rs.u8 = _4[1]; - rs.cellSet(self._1, [rs.u8WrappingAdd(c, 1), d] as [rs.u8, rs.u8]); + const _11: rs.Cell<[rs.u8, rs.u8]> = self._1; + const _6: [rs.u8, rs.u8] = [rs.u8WrappingAdd(c, 1), d]; + rs.ptrWrite(_11.v, _6); return new Counted(rs.u8WrappingAdd(self._0, 1), self._1); } export function drop$ops_Drop(self: Counted): void { - const _4: [rs.u8, rs.u8] = self._1.v; - rs.cellSet(self._1, [_4[0], rs.u8WrappingAdd(_4[1], 1)] as [rs.u8, rs.u8]); + const _4: [rs.u8, rs.u8] = copy$tuple2_u8_u8(self._1.v); + const c: rs.u8 = _4[0]; + const d: rs.u8 = _4[1]; + const _9: rs.Cell<[rs.u8, rs.u8]> = self._1; + const _6: [rs.u8, rs.u8] = [c, rs.u8WrappingAdd(d, 1)]; + rs.ptrWrite(_9.v, _6); } //# sourceMappingURL=uninit.Counted.ts.map diff --git a/ts/fixtures/lang/manual/expected/uninit.Zeroed.ts b/ts/fixtures/lang/manual/expected/uninit.Zeroed.ts index 7b7409008..303500e0e 100644 --- a/ts/fixtures/lang/manual/expected/uninit.Zeroed.ts +++ b/ts/fixtures/lang/manual/expected/uninit.Zeroed.ts @@ -1,6 +1,7 @@ // Generated by rust2-ts. Do not edit. import * as rs from "./rs.ts"; +import { copy$tuple2_u8_u8 } from "./lib.ts"; import type * as Tag from "./uninit.Tag.ts"; /** @@ -46,8 +47,9 @@ export class Zeroed { export function drop$ops_Drop(self: Zeroed): void { if (self.seen !== undefined) { const seen: rs.Cell<[rs.u8, rs.u8]> = self.seen; - const _6: [rs.u8, rs.u8] = seen.v; - rs.cellSet(seen, [_6[0], rs.u8WrappingAdd(_6[1], 1)] as [rs.u8, rs.u8]); + const _6: [rs.u8, rs.u8] = copy$tuple2_u8_u8(seen.v); + const _8: [rs.u8, rs.u8] = [_6[0], rs.u8WrappingAdd(_6[1], 1)]; + rs.ptrWrite(seen.v, _8); } } diff --git a/ts/fixtures/lang/manual/expected/uninit.ts b/ts/fixtures/lang/manual/expected/uninit.ts index 8f5ea9849..26e7d6af8 100644 --- a/ts/fixtures/lang/manual/expected/uninit.ts +++ b/ts/fixtures/lang/manual/expected/uninit.ts @@ -1,7 +1,7 @@ // Generated by rust2-ts. Do not edit. import * as rs from "./rs.ts"; -import { copy$array_array2_u16, copy$array_u16 } from "./lib.ts"; +import { copy$array_array2_u16, copy$array_u16, copy$tuple2_u8_u8 } from "./lib.ts"; import { unwrapOr$1fr498u as option_unwrapOr$1fr498u, map$1yjmt5m as option_map$1yjmt5m } from "./core/option.ts"; import * as Counted from "./uninit.Counted.ts"; import type * as Held from "./uninit.Held.ts"; @@ -169,13 +169,13 @@ export function boxedUninits(data: rs.ByteSlice, out: rs.ByteVec): void { }); rs.sliceWriteCloneOfSlice(counted, rs.sliceFrom(src2.items), Counted.clone$Clone); rs.sliceWriteCloneOfSlice(counted, rs.sliceFrom(src2.items), Counted.clone$Clone); - rs.byteVecPush(out, counts.v[0]); - rs.byteVecPush(out, counts.v[1]); + rs.byteVecPush(out, copy$tuple2_u8_u8(counts.v)[0]); + rs.byteVecPush(out, copy$tuple2_u8_u8(counts.v)[1]); const counted2: rs.Slice = counted; rs.iterExtendBytes(out, rs.iterMap(rs.iterSlice(rs.sliceItems(counted2)), (c: Counted.Counted): rs.u8 => { return c._0; }), undefined, true); - rs.byteVecPush(out, counts.v[1]); + rs.byteVecPush(out, copy$tuple2_u8_u8(counts.v)[1]); rs.byteVecExtendFromSlice(out, boxedClone$u8(data)); const _134: rs.Slice = boxedClone$uninit_Counted(counted2); rs.iterExtendBytes(out, rs.iterMap(rs.iterSlice(rs.sliceItems(_134)), (c2: Counted.Counted): rs.u8 => { @@ -183,7 +183,7 @@ export function boxedUninits(data: rs.ByteSlice, out: rs.ByteVec): void { }), undefined, true); rs.dropAll(_134); rs.dropAll(counted2); - rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(counts.v[0], counts.v[1])), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(copy$tuple2_u8_u8(counts.v)[0], copy$tuple2_u8_u8(counts.v)[1])), undefined, true); const len: rs.usize = data.length; const p: rs.Place = rs.rawByteSliceOf(rs.byteSliceNewUninit(len)).ptr; rs.ptrCopy(rs.byteSliceAsPtr(data), p, len); @@ -283,15 +283,15 @@ export function boxedOne(data: rs.ByteSlice, out: rs.ByteVec): void { const counted2: Counted.Counted = counted; rs.byteVecPush(out, counted2._0); counted2[Symbol.dispose](); - rs.byteVecPush(out, counts.v[1]); + rs.byteVecPush(out, copy$tuple2_u8_u8(counts.v)[1]); (new Counted.Counted((undefined as unknown) as rs.u8, (undefined as unknown) as rs.Cell<[rs.u8, rs.u8]>) as unknown) as Counted.Counted; rs.ptrWrite((new Counted.Counted((undefined as unknown) as rs.u8, (undefined as unknown) as rs.Cell<[rs.u8, rs.u8]>) as unknown) as Counted.Counted, new Counted.Counted(first, counts)); - rs.byteVecPush(out, counts.v[1]); + rs.byteVecPush(out, copy$tuple2_u8_u8(counts.v)[1]); rs.byteVecPush(out, boxed$u8(rs.u8WrappingAdd(first, 1))); const _154: Counted.Counted = boxed$uninit_Counted(new Counted.Counted(first, counts)); rs.byteVecPush(out, _154._0); _154[Symbol.dispose](); - rs.byteVecPush(out, counts.v[1]); + rs.byteVecPush(out, copy$tuple2_u8_u8(counts.v)[1]); } /** `value` boxed by way of a box not yet written. */ @@ -444,14 +444,14 @@ export function boxedZeroed(data: rs.ByteSlice, out: rs.ByteVec): void { const seen2: Zeroed.Zeroed = seen; rs.byteVecPush(out, seen2.many[299] & 0xff); seen2[Symbol.dispose](); - rs.byteVecPush(out, counts.v[1]); + rs.byteVecPush(out, copy$tuple2_u8_u8(counts.v)[1]); ((new Zeroed.Zeroed(0, false, 0, 0.0, 0, 0, Array.from({ length: 3 }, (): rs.u16 => { return 0; }), Array.from({ length: 300 }, (): rs.u32 => { return 0; }), [0, 0], "Zero", "Zero", rs.NULL, undefined) as unknown) as Zeroed.Zeroed).seen = counts; undefined; - rs.byteVecPush(out, counts.v[1]); + rs.byteVecPush(out, copy$tuple2_u8_u8(counts.v)[1]); rs.byteVecExtendFromSlice(out, rs.byteSliceFrom(rs.u64ToBeBytes(zeroedBox$u64()).reverse())); const _409: [rs.u8, rs.u16] = zeroedBox$tuple2_u8_u16(); rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(_409[0], _409[1] & 0xff)), undefined, true); diff --git a/ts/fixtures/lang/pointers/caller.ts b/ts/fixtures/lang/pointers/caller.ts index 3bf736228..d9616c730 100644 --- a/ts/fixtures/lang/pointers/caller.ts +++ b/ts/fixtures/lang/pointers/caller.ts @@ -15,4 +15,29 @@ const unsafeCells = [ [], ].map((bytes) => Uint8Array.of(...op("pointers::cells"), 0, ...bytes)); -export const cases: Uint8Array[] = [...unsafeCells]; +/** + * `pointers::raw_cells` scripts: each operation, then each replace before and after writes + * through pointers to where the cells are kept, through cells of what a `&mut` borrows, and + * of pointers to no cell beside boxes replaced and swapped. + */ +const rawCells = [ + [0, 8, 9, 2, 3, 4, 5, 6, 7], + [1, 249, 3, 251, 0, 11, 4, 252, 2, 3], + [2, 10, 18, 4, 12, 20, 3, 1, 0], + [5, 13, 21, 0, 3, 5, 253, 4], + [6, 14, 22, 30, 254], + [], +].map((bytes) => Uint8Array.of(...op("pointers::raw_cells"), 0, ...bytes)); + +/** + * `pointers::cell_writes` scripts: each write, then each again with a wrapping operand, and + * cells of what a `&mut` borrows between writes to the others. + */ +const cellWrites = [ + [0, 1, 2, 3, 4, 5, 6, 7], + [8, 249, 250, 3, 252, 13, 1, 0], + [5, 2, 4, 253, 0, 5, 3], + [], +].map((bytes) => Uint8Array.of(...op("pointers::cell_writes"), 0, ...bytes)); + +export const cases: Uint8Array[] = [...unsafeCells, ...rawCells, ...cellWrites]; diff --git a/ts/fixtures/lang/pointers/expected/lib.ts b/ts/fixtures/lang/pointers/expected/lib.ts index 519c4950b..d654e3dda 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, 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 } 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"; @@ -17,6 +17,7 @@ import * as List from "./pointers.List.ts"; import type * as Outer from "./pointers.Outer.ts"; import type * as Pair from "./pointers.Pair.ts"; import type * as Paired from "./pointers.Paired.ts"; +import type * as Reentrant from "./pointers.Reentrant.ts"; import type * as Spot from "./pointers.Spot.ts"; import type * as Twin from "./pointers.Twin.ts"; @@ -141,6 +142,10 @@ export function copy$pointers_Pair(v: Pair.Pair): Pair.Pair { return { a: v.a, b: v.b }; } +export function copy$pointers_Reentrant(v: Reentrant.Reentrant): Reentrant.Reentrant { + return { _0: v._0, _1: v._1 }; +} + export function copy$pointers_Spot(v: Spot.Spot): Spot.Spot { return { at: copy$tuple2_u16_u8(v.at), tag: v.tag }; } @@ -197,6 +202,10 @@ export function copy$tuple2_u8_sync_Arc_u8(v: [rs.u8, rs.Arc]): [rs.u8, r return [v[0], v[1]]; } +export function copy$tuple2_u8_u16(v: [rs.u8, rs.u16]): [rs.u8, rs.u16] { + return [v[0], v[1]]; +} + export function copy$tuple2_u8_u8(v: [rs.u8, rs.u8]): [rs.u8, rs.u8] { return [v[0], v[1]]; } @@ -306,9 +315,30 @@ export function cases(): rs.Vec<[string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.By arrayCasts(data28, out28); }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["pointers::generic_unions", (_238: rs.u8, data29: rs.ByteSlice, out29: rs.ByteVec): undefined => { genericUnions(data29, out29); - }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["pointers::lone_bytes", (_239: rs.u8, data30: rs.ByteSlice, out30: rs.ByteVec): undefined => { - loneBytes(data30, out30); + }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["pointers::raw_cells", (_239: rs.u8, data30: rs.ByteSlice, out30: rs.ByteVec): undefined => { + rawCells(data30, out30); + }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["pointers::cell_writes", (_240: rs.u8, data31: rs.ByteSlice, out31: rs.ByteVec): undefined => { + cellWrites(data31, out31); + }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["pointers::nested_cells", (_241: rs.u8, data32: rs.ByteSlice, out32: rs.ByteVec): undefined => { + 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]]); } +/** + * `UnsafeCell::get` and `raw_get` of a cell of a slice, which only a caller can give, as + * translated code can't unsize a cell. + */ +export function cellSlice(c: rs.Cell>, at: rs.usize): rs.u16 { + const _4: rs.RawSlice = rs.rawSliceOf(c.v); + rs.idx(_4, at); + const slice = _4.deref(); + const _3: rs.u16 = slice.data[slice.start + at]; + const _9: rs.RawSlice = rs.rawSliceOf(c.v); + rs.idx(_9, 0); + const slice2 = _9.deref(); + return _3 ^ slice2.data[slice2.start]; +} + //# sourceMappingURL=lib.ts.map diff --git a/ts/fixtures/lang/pointers/expected/pointers.Celled.ts b/ts/fixtures/lang/pointers/expected/pointers.Celled.ts new file mode 100644 index 000000000..ca6835c66 --- /dev/null +++ b/ts/fixtures/lang/pointers/expected/pointers.Celled.ts @@ -0,0 +1,11 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; + +/** A struct holding a cell beside a number. */ +export interface Celled { + c: rs.Cell; + n: rs.u8; +} + +//# sourceMappingURL=pointers.Celled.ts.map diff --git a/ts/fixtures/lang/pointers/expected/pointers.Reentrant.ts b/ts/fixtures/lang/pointers/expected/pointers.Reentrant.ts new file mode 100644 index 000000000..b1fe9e0dc --- /dev/null +++ b/ts/fixtures/lang/pointers/expected/pointers.Reentrant.ts @@ -0,0 +1,26 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import { REENTERED } from "./pointers.ts"; + +/** A struct Rust copies whose `default` and `eq` write the cell holding it. */ +export interface Reentrant { + _0: rs.u8; + _1: rs.u8; +} + +export function default$Default(): Reentrant { + ((c: rs.Cell): undefined => { + rs.ptrWrite(c.v, { _0: 7, _1: 7 }); + })(REENTERED.get()); + return { _0: 0, _1: 0 }; +} + +export function eq$cmp_PartialEq(self: Reentrant, other: Reentrant): boolean { + ((c: rs.Cell): undefined => { + rs.ptrWrite(c.v, { _0: 9, _1: 9 }); + })(REENTERED.get()); + return self._0 === other._0; +} + +//# sourceMappingURL=pointers.Reentrant.ts.map diff --git a/ts/fixtures/lang/pointers/expected/pointers.Segment.ts b/ts/fixtures/lang/pointers/expected/pointers.Segment.ts index 1d0029b17..876451e00 100644 --- a/ts/fixtures/lang/pointers/expected/pointers.Segment.ts +++ b/ts/fixtures/lang/pointers/expected/pointers.Segment.ts @@ -16,7 +16,7 @@ export interface Segment { function new_(): Segment { let _6!: rs.usize; const slots: Lent.Lent<[rs.u8, rs.u8]>[] = Array.from({ length: 4 }, (): Lent.Lent<[rs.u8, rs.u8]> => { - return (new Lent.Lent((undefined as unknown) as rs.Cell<[rs.u8, rs.u8]>) as unknown) as Lent.Lent<[rs.u8, rs.u8]>; + return (new Lent.Lent((new rs.Cell([undefined, undefined]) as unknown) as rs.Cell<[rs.u8, rs.u8]>) as unknown) as Lent.Lent<[rs.u8, rs.u8]>; }); let iterStart: rs.usize = 0; const iterEnd: rs.usize = 4; @@ -27,7 +27,14 @@ function new_(): Segment { } const _15: Lent.Lent<[rs.u8, rs.u8]>[] = slots; const _13: Lent.Lent<[rs.u8, rs.u8]> = Lent.new$mem_MaybeUninit_tuple2_u8_u8(([undefined, undefined] as unknown) as [rs.u8, rs.u8]); - rs.ptrWrite(_15[at], _13); + const object = _15[at]; + const value = _13; + const cell = object._0; + rs.ptrWrite(object, value); + if (cell !== undefined) { + object._0 = cell; + rs.ptrWrite(cell.v, value._0.v); + } } return { filled: 0, slots }; } @@ -35,7 +42,7 @@ function new_(): Segment { /** As [`Self::new`], with kio's loop written with an iterator. */ export function iterated(): Segment { const slots: Lent.Lent<[rs.u8, rs.u8]>[] = Array.from({ length: 4 }, (): Lent.Lent<[rs.u8, rs.u8]> => { - return (new Lent.Lent((undefined as unknown) as rs.Cell<[rs.u8, rs.u8]>) as unknown) as Lent.Lent<[rs.u8, rs.u8]>; + return (new Lent.Lent((new rs.Cell([undefined, undefined]) as unknown) as rs.Cell<[rs.u8, rs.u8]>) as unknown) as Lent.Lent<[rs.u8, rs.u8]>; }); const iter: rs.Iter> = rs.iterSlice(slots); while (true) { @@ -44,7 +51,15 @@ export function iterated(): Segment { break; } const uninit = _8; - rs.ptrWrite(uninit, Lent.new$mem_MaybeUninit_tuple2_u8_u8(([undefined, undefined] as unknown) as [rs.u8, rs.u8])); + const object = uninit; + const value = Lent.new$mem_MaybeUninit_tuple2_u8_u8(([undefined, undefined] as unknown) as [rs.u8, rs.u8]); + const cell = object._0; + rs.ptrWrite(object, value); + if (cell !== undefined) { + object._0 = cell; + rs.ptrWrite(cell.v, value._0.v); + } + undefined; uninit; } return { filled: 0, slots }; diff --git a/ts/fixtures/lang/pointers/expected/pointers.Slots.ts b/ts/fixtures/lang/pointers/expected/pointers.Slots.ts new file mode 100644 index 000000000..8927790e6 --- /dev/null +++ b/ts/fixtures/lang/pointers/expected/pointers.Slots.ts @@ -0,0 +1,23 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Held from "./pointers.Held.ts"; + +/** A struct holding cells, reached through a raw pointer to it. */ +export class Slots { + num: rs.Cell; + held: rs.Cell; + pair: rs.Cell<[rs.u8, rs.u16]>; + + constructor(num: rs.Cell, held: rs.Cell, pair: rs.Cell<[rs.u8, rs.u16]>) { + this.num = num; + this.held = held; + this.pair = pair; + } + + [Symbol.dispose](): void { + this.held[Symbol.dispose](); + } +} + +//# sourceMappingURL=pointers.Slots.ts.map diff --git a/ts/fixtures/lang/pointers/expected/pointers.ts b/ts/fixtures/lang/pointers/expected/pointers.ts index 3f573a6dd..7413590fa 100644 --- a/ts/fixtures/lang/pointers/expected/pointers.ts +++ b/ts/fixtures/lang/pointers/expected/pointers.ts @@ -1,7 +1,7 @@ // Generated by rust2-ts. Do not edit. 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_Spot, copy$pointers_Twin, copy$tuple2_array2_u32_u8, copy$tuple2_u16_u8, copy$tuple2_u32_u32, 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 { 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 type * as Aimed from "./pointers.Aimed.ts"; @@ -9,6 +9,7 @@ import * as Bin from "./pointers.Bin.ts"; import type * as ByCall from "./pointers.ByCall.ts"; import * as ByClosure from "./pointers.ByClosure.ts"; import type * as ByObject from "./pointers.ByObject.ts"; +import type * as Celled from "./pointers.Celled.ts"; import * as Counted from "./pointers.Counted.ts"; import type * as Duo from "./pointers.Duo.ts"; import type * as Either from "./pointers.Either.ts"; @@ -32,10 +33,12 @@ import type * as Pair from "./pointers.Pair.ts"; import * as Paired from "./pointers.Paired.ts"; import * as Pointing from "./pointers.Pointing.ts"; import type * as Reattached from "./pointers.Reattached.ts"; +import * as Reentrant from "./pointers.Reentrant.ts"; import type * as Refilled from "./pointers.Refilled.ts"; import type * as Run from "./pointers.Run.ts"; import * as Segment from "./pointers.Segment.ts"; import * as Shelf from "./pointers.Shelf.ts"; +import * as Slots from "./pointers.Slots.ts"; import type * as Span from "./pointers.Span.ts"; import type * as Spot from "./pointers.Spot.ts"; import type * as Stable from "./pointers.Stable.ts"; @@ -234,7 +237,7 @@ export function places(data: rs.ByteSlice, out: rs.ByteVec): void { } else if (_21 === 10) { const _46: Pair.Pair = { a: v, b: rs.u32Add(v, 1) }; const pointer2 = pp; - const old3 = copy$pointers_Pair(pointer2); + const old3 = rs.objectCopy(pointer2); rs.ptrWrite(pointer2, _46); old3; } else if (_21 === 11) { @@ -1991,7 +1994,14 @@ export function through$Cell_u8(nest: Enclosed.Enclosed>, n: rs.u } rs.byteVecPush(out, _43 | (_50 ? 1 : 0)); if (rs.u8Rem(n, 5) === 0) { - (nest.inner.at as rs.Place>).v = made$pointers_Aim_Cell_u8(n); + const pointer = nest.inner.at as rs.Place>; + const value = made$pointers_Aim_Cell_u8(n); + if (pointer.v === undefined) { + pointer.v = value; + } else { + pointer.v.v = value.v; + } + undefined; } rs.byteVecPush(out, get$pointers_Aim_Cell_u8((nest.inner.seen as rs.Place>).v)); } @@ -3139,6 +3149,849 @@ export function genericUnions(data: rs.ByteSlice, out: rs.ByteVec): void { } } +/** + * What `UnsafeCell::raw_get` gives of a reference to a cell of a number, a struct Rust + * copies, one JS keeps as an object, a tuple, and arrays of bytes and of numbers; of a + * pointer to a variable's cell, to a field through a pointer to its struct, and from + * `MaybeUninit::as_ptr`; cells `UnsafeCell::from_mut` makes of a variable, an object, + * an element, and an array, written through `get`; `UnsafeCell::replace` of each, which a + * pointer taken before sees, giving back what it held undropped; what `as_ref_unchecked` + * and `as_mut_unchecked` lend; and the allocations of boxes and pinned boxes replaced and + * swapped through pointers, `UnsafeCell`s, one `from_mut` makes, and `Cell`s. + */ +export function rawCells(data: rs.ByteSlice, out: rs.ByteVec): void { + const count: rs.Arc = new rs.Arc(undefined); + let num: rs.Cell = new rs.Cell(7); + const duo: rs.Cell = new rs.Cell({ _0: 1, _1: 2 }); + const held: rs.Cell = new rs.Cell(new Held.Held(3, rs.arcClone(count))); + const pair: rs.Cell<[rs.u8, rs.u16]> = new rs.Cell([4, 5] as [rs.u8, rs.u16]); + const bytes: rs.Cell = new rs.Cell(Uint8Array.of(6, 7)); + const wide: rs.Cell = new rs.Cell([8, 9]); + const slots: Slots.Slots = new Slots.Slots(new rs.Cell(10), new rs.Cell(new Held.Held(11, rs.arcClone(count))), new rs.Cell([12, 13] as [rs.u8, rs.u16])); + const slot: rs.Cell = new rs.Cell(14); + let local: rs.u32 = 15; + const whole: Held.Held = new Held.Held(16, rs.arcClone(count)); + const elems: rs.u16[] = [17, 18, 19]; + for (const op of rs.byteSliceView(data)) { + const n: rs.u8 = rs.u8Div(op, 8); + const _41: rs.u8 = rs.u8Rem(op, 8); + if (_41 === 0) { + const _43: rs.u32 = ((n as rs.u32) << 20) >>> 0; + const _47: rs.Place = num; + _47.v = (_47.v ^ _43) >>> 0; + const _50: rs.u32 = n as rs.u32; + const _51: rs.Place = num; + _51.v = (_51.v ^ _50) >>> 0; + const _54: Duo.Duo = duo.v; + _54._1 = _54._1 ^ n; + const _57: Held.Held = held.v; + _57.n = _57.n ^ n; + const _60: rs.u16 = ((n as rs.u16) << 8) & 0xffff; + const _64: [rs.u8, rs.u16] = pair.v; + _64[1] = _64[1] ^ _60; + const _67: rs.ByteSlice = rs.byteSliceFrom(bytes.v); + const _70: rs.usize = rs.u8Rem(n, 2) as rs.usize; + if (!(_70 < 2)) { + rs.panic("index out of bounds: the len is " + 2 + " but the index is " + _70); + } + _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 _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); + } + _78.data[_78.start + _81] = _78.data[_78.start + _81] ^ _74; + rs.iterExtendBytes(out, rs.iterSlice(rs.u32ToBeBytes(num.v).reverse()), undefined, true); + 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); + 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); + const _115: rs.u32 = rs.u32WrappingMul(p.v.v, ((n as rs.u32) | 1) >>> 0); + p.v.v = _115; + const s: Slots.Slots = slots; + const _122: rs.u32 = n as rs.u32; + const _123: rs.Place = s.num; + _123.v = rs.u32Add(_123.v, _122); + const _126: Held.Held = s.held.v; + _126.n = _126.n ^ n; + const _128: [rs.u8, rs.u16] = s.pair.v; + _128[0] = _128[0] ^ n; + const _130: rs.u32 = n as rs.u32; + const _131: rs.Place = { v: slot }.v; + _131.v = (_131.v ^ _130) >>> 0; + rs.iterExtendBytes(out, rs.iterSlice(rs.u32ToBeBytes(num.v).reverse()), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(rs.u32ToBeBytes(slots.num.v).reverse()), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(slots.held.v.n, slots.pair.v[0])), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(rs.u32ToBeBytes(slot.v).reverse()), undefined, true); + } else if (_41 === 2) { + const c: rs.Cell = rs.cellOfPlace(rs.place(() => local, (value7) => local = value7)); + c.v = rs.intRotateLeft(c.v, n as rs.u32, 32, false); + const _169: Held.Held = rs.cellOfPlace(rs.partPlace(whole)).v; + _169.n = _169.n ^ n; + const _173: rs.usize = rs.u8Rem(n, 3) as rs.usize; + if (!(_173 < 3)) { + rs.panic("index out of bounds: the len is " + 3 + " but the index is " + _173); + } + const borrowed2 = elems; + const e: rs.Cell = rs.cellOfPlace(rs.place(() => borrowed2[_173], (value8) => borrowed2[_173] = value8)); + const _177: rs.u16 = n as rs.u16; + const _178: rs.Place = e; + _178.v = _178.v ^ _177; + rs.iterExtendBytes(out, rs.iterSlice(rs.u32ToBeBytes(local).reverse()), undefined, true); + rs.byteVecPush(out, whole.n); + rs.iterExtendBytes(out, rs.iterFlatMap(rs.iterSlice(elems), (e2: rs.u16): Uint8Array => { + return rs.u16ToBeBytes(e2).reverse(); + }, (value: Uint8Array) => rs.iterSlice(value), true, 2), undefined, true); + } else if (_41 === 3) { + const p2: rs.Place = num; + const _194: rs.u32 = ((n as rs.u32) << 3) >>> 0; + const pointer9 = num; + const old22 = pointer9.v; + pointer9.v = _194; + rs.iterExtendBytes(out, rs.iterSlice(rs.u32ToBeBytes(old22).reverse()), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(rs.u32ToBeBytes(p2.v).reverse()), undefined, true); + const p3: Held.Held = held.v; + const _207: Held.Held = new Held.Held(n, rs.arcClone(count)); + const pointer10 = held.v; + const old23 = rs.objectCopy(pointer10); + rs.ptrWrite(pointer10, _207); + const old2: Held.Held = old23; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(old2.n, p3.n, count.strong & 0xff)), undefined, true); + old2[Symbol.dispose](); + rs.byteVecPush(out, count.strong & 0xff); + const p4: [rs.u8, rs.u16] = pair.v; + const _226: [rs.u8, rs.u16] = [n, rs.u16Mul(n as rs.u16, 3)]; + const pointer11 = pair.v; + const old24 = rs.objectCopy(pointer11); + rs.ptrWrite(pointer11, _226); + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(old24[0], p4[0])), undefined, true); + const p5: rs.ByteSlice = rs.byteSliceFrom(bytes.v); + const pointer12 = rs.byteSliceFrom(bytes.v); + const old25 = rs.byteSliceToArray(pointer12); + rs.byteSliceSet(pointer12, Uint8Array.of(n, ~n & 0xff)); + rs.iterExtendBytes(out, rs.iterSlice(old25), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(rs.byteSliceToArray(p5)), undefined, true); + const pointer13 = duo.v; + const old26 = rs.objectCopy(pointer13); + rs.ptrWrite(pointer13, { _0: n, _1: n ^ 1 }); + const old5: Duo.Duo = old26; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(old5._0, old5._1, duo.v._0)), undefined, true); + } else if (_41 === 4) { + const _256: rs.Cell = rs.cellOfPlace(rs.place(() => local, (value5) => local = value5)); + const _258: rs.u32 = n as rs.u32; + const pointer6 = _256; + const old19 = pointer6.v; + pointer6.v = _258; + rs.iterExtendBytes(out, rs.iterSlice(rs.u32ToBeBytes(old19).reverse()), undefined, true); + const h2: rs.Cell = rs.cellOfPlace(rs.partPlace(whole)); + const p6: Held.Held = h2.v; + const _267: Held.Held = new Held.Held(~n & 0xff, rs.arcClone(count)); + const pointer7 = h2.v; + const old20 = rs.objectCopy(pointer7); + rs.ptrWrite(pointer7, _267); + const old7: Held.Held = old20; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(old7.n, p6.n, whole.n, count.strong & 0xff)), undefined, true); + const _283: rs.usize = rs.u8Rem(n, 3) as rs.usize; + if (!(_283 < 3)) { + rs.panic("index out of bounds: the len is " + 3 + " but the index is " + _283); + } + const borrowed = elems; + const _281: rs.Cell = rs.cellOfPlace(rs.place(() => borrowed[_283], (value6) => borrowed[_283] = value6)); + const _287: rs.u16 = n as rs.u16; + const pointer8 = _281; + const old21 = pointer8.v; + pointer8.v = _287; + rs.iterExtendBytes(out, rs.iterSlice(rs.u16ToBeBytes(old21).reverse()), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(rs.u32ToBeBytes(local).reverse()), undefined, true); + old7[Symbol.dispose](); + } else if (_41 === 5) { + const _293: rs.u32 = n as rs.u32; + const _294: rs.Place = num; + _294.v = (_294.v ^ _293) >>> 0; + const r: rs.Place = num; + r.v = rs.intRotateLeft(r.v, 1, 32, false); + const _300: Held.Held = held.v; + _300.n = _300.n ^ n; + const _302: rs.u16 = n as rs.u16; + const _303: [rs.u8, rs.u16] = pair.v; + _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.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); + 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)))); + const _343: rs.ByteSlice = rs.byteSliceFrom(a.v); + const _345: rs.usize = rs.u8Rem(n, 3) as rs.usize; + if (!(_345 < 3)) { + rs.panic("index out of bounds: the len is " + 3 + " but the index is " + _345); + } + _343.data[_343.start + _345] = _343.data[_343.start + _345] ^ 64; + const pointer5 = rs.byteSliceFrom(a.v); + const old18 = rs.byteSliceToArray(pointer5); + rs.byteSliceSet(pointer5, Uint8Array.of(3, n, 4)); + rs.iterExtendBytes(out, rs.iterSlice(old18), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(copy$array_u8(arr)), undefined, true); + } else if (_41 === 6) { + const held2: (a0: rs.u8) => Held.Held = (n2: rs.u8): Held.Held => { + return new Held.Held(n2, rs.arcClone(count)); + }; + let a2: Held.Held = held2(n); + const atA: Held.Held = a2; + const _364: rs.Place = rs.place(() => a2, (value) => a2 = value); + const _366: Held.Held = held2(~n & 0xff); + const pointer = _364; + const old11 = pointer.v; + pointer.v = _366; + const old10: Held.Held = old11; + let other: Held.Held = held2(n ^ 1); + const _378: [Held.Held, Held.Held] = [a2, other]; + const atNew: Held.Held = _378[0]; + const atOther: Held.Held = _378[1]; + const x3 = rs.place(() => a2, (value2) => a2 = value2); + const y3 = rs.place(() => other, (value3) => other = value3); + const old12 = x3.v; + x3.v = y3.v; + y3.v = old12; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(atA === old10 ? 1 : 0, atNew === other ? 1 : 0)), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(atOther === a2 ? 1 : 0, old10.n, a2.n, other.n)), undefined, true); + const pinned: rs.Cell<[rs.u8, rs.u16]> = new rs.Cell([n, 1] as [rs.u8, rs.u16]); + const atPinned: [rs.u8, rs.u16] = pinned.v; + const _417: [rs.u8, rs.u16] = [n ^ 2, 2]; + const pointer2 = pinned; + const old13 = pointer2.v; + pointer2.v = _417; + const was: [rs.u8, rs.u16] = old13; + const _422: [rs.Cell<[rs.u8, rs.u16]>, rs.Cell<[rs.u8, rs.u16]>] = [new rs.Cell([n, 3] as [rs.u8, rs.u16]), new rs.Cell([~n & 0xff, 4] as [rs.u8, rs.u16])]; + const x: rs.Cell<[rs.u8, rs.u16]> = _422[0]; + const y: rs.Cell<[rs.u8, rs.u16]> = _422[1]; + const atX: [rs.u8, rs.u16] = x.v; + const x4 = x; + const y4 = y; + const old14 = x4.v; + x4.v = y4.v; + y4.v = old14; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(atX === y.v ? 1 : 0, x.v[0])), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(atPinned === was ? 1 : 0, was[0], pinned.v[0])), undefined, true); + const cell: rs.Cell = new rs.Cell(held2(n ^ 3)); + const atCell: Held.Held = cell.v; + const _479: Held.Held = held2(n ^ 4); + const pointer3 = cell; + const old15 = pointer3.v; + pointer3.v = _479; + const was2: Held.Held = old15; + let boxed: Held.Held = held2(n ^ 7); + const atBoxed: Held.Held = boxed; + const _493: rs.Cell = rs.cellOfPlace(rs.place(() => boxed, (value4) => boxed = value4)); + const _495: Held.Held = held2(n); + const pointer4 = _493; + const old16 = pointer4.v; + pointer4.v = _495; + const lent: Held.Held = old16; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(atBoxed === lent ? 1 : 0, lent.n, boxed.n)), undefined, true); + const _509: [rs.Cell, rs.Cell] = [new rs.Cell(held2(n ^ 5)), new rs.Cell(held2(n ^ 6))]; + const x2: rs.Cell = _509[0]; + const y2: rs.Cell = _509[1]; + const atX2: Held.Held = x2.v; + const x5 = x2; + const y5 = y2; + const old17 = x5.v; + x5.v = y5.v; + y5.v = old17; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(atCell === was2 ? 1 : 0, was2.n, cell.v.n)), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(atX2 === y2.v ? 1 : 0, count.strong & 0xff)), undefined, true); + y2[Symbol.dispose](); + x2[Symbol.dispose](); + lent[Symbol.dispose](); + boxed[Symbol.dispose](); + was2[Symbol.dispose](); + cell[Symbol.dispose](); + other[Symbol.dispose](); + old10[Symbol.dispose](); + a2[Symbol.dispose](); + } else { + rs.byteVecPush(out, n); + } + } + rs.iterExtendBytes(out, rs.iterSlice(rs.u32ToBeBytes(num.v).reverse()), undefined, true); + const _557: Held.Held = held.v; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(_557.n, count.strong & 0xff)), undefined, true); + _557[Symbol.dispose](); + rs.iterExtendBytes(out, rs.iterSlice(rs.u32ToBeBytes(slots.num.v).reverse()), undefined, true); + slots.held[Symbol.dispose](); + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(whole.n, count.strong & 0xff)), undefined, true); + rs.iterExtendBytes(out, rs.iterFlatMap(rs.iterSlice(elems), (e3: rs.u16): Uint8Array => { + return rs.u16ToBeBytes(e3).reverse(); + }, (value: Uint8Array) => rs.iterSlice(value), true, 2), undefined, true); + whole[Symbol.dispose](); + count[Symbol.dispose](); +} + +export const REENTERED: rs.LocalKey> = /* @__PURE__ */ new rs.LocalKey(REENTERED$init, false); + +export function REENTERED$init(): rs.Cell { + return new rs.Cell({ _0: 1, _1: 1 }); +} + +/** + * What `Cell`s of a tuple, a struct Rust copies, one that owns a count, and arrays of bytes + * and of numbers, and cells `Cell::from_mut` makes of a tuple and an array, hold after + * `replace`, `set`, `swap` (but of the arrays), `take`, and `update`, each read back + * through a pointer `as_ptr` gave before, and what each gives back and drops; and `take` + * and `==` of a cell its value's `default` and `eq` write. + */ +export function cellWrites(data: rs.ByteSlice, out: rs.ByteVec): void { + const count: rs.Arc = new rs.Arc(undefined); + const held: (a0: rs.u8) => Held.Held = (n2: rs.u8): Held.Held => { + return new Held.Held(n2, rs.arcClone(count)); + }; + const pair: rs.Cell<[rs.u8, rs.u16]> = new rs.Cell([1, 2] as [rs.u8, rs.u16]); + const duo: rs.Cell = new rs.Cell({ _0: 3, _1: 4 }); + const owner: rs.Cell = new rs.Cell(held(5)); + const bytes: rs.Cell = new rs.Cell(Uint8Array.of(6, 7)); + const wide: rs.Cell = new rs.Cell([8, 9]); + const _21: [[rs.u8, rs.u16], Duo.Duo, Held.Held] = [pair.v, duo.v, owner.v]; + 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 toBytes: rs.ByteSlice = _30[0]; + const toWide: rs.Slice = _30[1]; + const lent: [rs.u8, rs.u16] = [10, 11]; + const lentBytes: Uint8Array = Uint8Array.of(12, 13); + for (const op of rs.byteSliceView(data)) { + const n: rs.u8 = rs.u8Div(op, 8); + const _46: rs.u8 = rs.u8Rem(op, 8); + if (_46 === 0) { + const _50: [rs.u8, rs.u16] = [n, ((n as rs.u16) << 8) & 0xffff]; + const pointer15 = pair.v; + const old16 = rs.objectCopy(pointer15); + rs.ptrWrite(pointer15, _50); + const _57: rs.u8 = old16[0]; + const _61: Duo.Duo = { _0: n, _1: ~n & 0xff }; + const pointer16 = duo.v; + const old17 = rs.objectCopy(pointer16); + rs.ptrWrite(pointer16, _61); + const _58: rs.u8 = old17._1; + const _66: Held.Held = held(n); + const pointer17 = owner.v; + const old18 = rs.objectCopy(pointer17); + rs.ptrWrite(pointer17, _66); + const _64: Held.Held = old18; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(_57, _58, _64.n)), undefined, true); + _64[Symbol.dispose](); + const _72: Uint8Array = Uint8Array.of(n, 1); + const pointer18 = rs.byteSliceFrom(bytes.v); + const old19 = rs.byteSliceToArray(pointer18); + 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)); + rs.sliceSet(pointer19, _78); + rs.iterExtendBytes(out, rs.iterSlice(rs.u16ToBeBytes(old20[1]).reverse()), undefined, true); + } else if (_46 === 1) { + rs.ptrWrite(pair.v, [n ^ 1, 3] as [rs.u8, rs.u16]); + rs.ptrWrite(duo.v, { _0: n ^ 2, _1: 4 }); + const _92: Held.Held = held(n ^ 3); + const pointer14 = owner.v; + const old15 = rs.objectCopy(pointer14); + rs.ptrWrite(pointer14, _92); + old15[Symbol.dispose](); + 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); + } 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; + const y2 = _110.v; + const old12 = rs.objectCopy(x2); + rs.ptrWrite(x2, rs.objectCopy(y2)); + rs.ptrWrite(y2, old12); + const other: rs.Cell = new rs.Cell({ _0: 8, _1: n }); + const x3 = duo.v; + const y3 = other.v; + const old13 = rs.objectCopy(x3); + rs.ptrWrite(x3, rs.objectCopy(y3)); + rs.ptrWrite(y3, old13); + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(copy$pointers_Duo(other.v)._0, copy$pointers_Duo(other.v)._1)), undefined, true); + const other2: rs.Cell = new rs.Cell(held(n ^ 5)); + const x4 = owner.v; + const y4 = other2.v; + const old14 = rs.objectCopy(x4); + rs.ptrWrite(x4, rs.objectCopy(y4)); + rs.ptrWrite(y4, old14); + const _135: Held.Held = other2.v; + rs.byteVecPush(out, _135.n); + _135[Symbol.dispose](); + } else if (_46 === 3) { + const value3 = [0, 0]; + const pointer11 = pair.v; + const old9 = rs.objectCopy(pointer11); + rs.ptrWrite(pointer11, value3); + rs.byteVecPush(out, old9[0]); + const value4 = rs.bytes(2); + const pointer12 = rs.byteSliceFrom(bytes.v); + const old10 = rs.byteSliceToArray(pointer12); + rs.byteSliceSet(pointer12, value4); + rs.iterExtendBytes(out, rs.iterSlice(old10), undefined, true); + const value5 = Array.from({ length: 2 }, (): rs.u16 => { + return 0; + }); + const pointer13 = rs.sliceFrom(wide.v); + const old11 = rs.objectCopy(rs.sliceView(pointer13)); + rs.sliceSet(pointer13, value5); + rs.iterExtendBytes(out, rs.iterSlice(rs.u16ToBeBytes(old11[0]).reverse()), undefined, true); + } else if (_46 === 4) { + const _153: (a0: [rs.u8, rs.u16]) => [rs.u8, rs.u16] = (_25: [rs.u8, rs.u16]): [rs.u8, rs.u16] => { + const a3: rs.u8 = _25[0]; + const b3: rs.u16 = _25[1]; + return [rs.u8WrappingAdd(a3, n), b3 ^ 1] as [rs.u8, rs.u16]; + }; + const pointer7 = pair.v; + rs.ptrWrite(pointer7, _153(copy$tuple2_u8_u16(pointer7))); + const _157: (a0: Duo.Duo) => Duo.Duo = (_27: Duo.Duo): Duo.Duo => { + return { _0: _27._1, _1: _27._0 ^ n }; + }; + const pointer8 = duo.v; + rs.ptrWrite(pointer8, _157(copy$pointers_Duo(pointer8))); + const _161: (a0: Uint8Array) => Uint8Array = (_28: Uint8Array): Uint8Array => { + return Uint8Array.of(_28[1], rs.u8WrappingMul(_28[0], n)); + }; + const pointer9 = rs.byteSliceFrom(bytes.v); + rs.byteSliceSet(pointer9, _161(rs.byteSliceToArray(pointer9))); + const _165: (a0: rs.u16[]) => rs.u16[] = (_29: rs.u16[]): rs.u16[] => { + const a6: rs.u16 = _29[0]; + return [rs.intRotateLeft(_29[1], n as rs.u32, 16, false), a6]; + }; + const pointer10 = rs.sliceFrom(wide.v); + rs.sliceSet(pointer10, _165(rs.sliceToArray(pointer10))); + } else if (_46 === 6) { + ((c3: rs.Cell): undefined => { + rs.ptrWrite(c3.v, { _0: n, _1: 1 }); + const value2 = Reentrant.default$Default(); + const pointer6 = c3.v; + const old8 = rs.objectCopy(pointer6); + rs.ptrWrite(pointer6, value2); + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(old8._0, copy$pointers_Reentrant(c3.v)._0)), undefined, true); + rs.ptrWrite(c3.v, { _0: n, _1: 1 }); + const _172: rs.Cell = new rs.Cell({ _0: n, _1: 2 }); + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(rs.cellBy(Reentrant.eq$cmp_PartialEq, copy$pointers_Reentrant)(c3, _172) ? 1 : 0, copy$pointers_Reentrant(c3.v)._0)), undefined, true); + })(REENTERED.get()); + } else if (_46 === 5) { + const c: rs.Cell<[rs.u8, rs.u16]> = rs.cellOfPlace(rs.partPlace(lent)); + const p: [rs.u8, rs.u16] = c.v; + rs.ptrWrite(c.v, [n, 1] as [rs.u8, rs.u16]); + const _176: [rs.u8, rs.u16] = [n ^ 1, 2]; + const pointer = c.v; + const old4 = rs.objectCopy(pointer); + rs.ptrWrite(pointer, _176); + const old2: [rs.u8, rs.u16] = old4; + const _180: rs.Cell<[rs.u8, rs.u16]> = new rs.Cell([n ^ 2, 3] as [rs.u8, rs.u16]); + const x = c.v; + const y = _180.v; + const old5 = rs.objectCopy(x); + rs.ptrWrite(x, rs.objectCopy(y)); + rs.ptrWrite(y, old5); + const pointer2 = c.v; + rs.ptrWrite(pointer2, ((_2: [rs.u8, rs.u16]): [rs.u8, rs.u16] => { + return [_2[0] ^ 4, _2[1]] as [rs.u8, rs.u16]; + })(copy$tuple2_u8_u16(pointer2))); + const _186: rs.u8 = old2[0]; + const _187: rs.u8 = p[0]; + const value = [0, 0]; + const pointer3 = c.v; + const old6 = rs.objectCopy(pointer3); + rs.ptrWrite(pointer3, value); + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(_186, _187, old6[0])), undefined, true); + const c2: rs.Cell = rs.cellOfPlace(rs.partPlace(rs.byteSliceView(rs.byteSliceFrom(lentBytes)))); + const p2: rs.ByteSlice = rs.byteSliceFrom(c2.v); + const _194: Uint8Array = Uint8Array.of(n, 5); + const pointer4 = rs.byteSliceFrom(c2.v); + const old7 = rs.byteSliceToArray(pointer4); + rs.byteSliceSet(pointer4, _194); + const old3: Uint8Array = old7; + const pointer5 = rs.byteSliceFrom(c2.v); + rs.byteSliceSet(pointer5, ((_23: Uint8Array): Uint8Array => { + return Uint8Array.of(_23[1], _23[0]); + })(rs.byteSliceToArray(pointer5))); + rs.iterExtendBytes(out, rs.iterSlice(old3), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(rs.byteSliceToArray(p2)), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(lent[0], lentBytes[0])), undefined, true); + } else { + rs.byteVecPush(out, n); + } + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(toPair[0], toDuo._0, toDuo._1, toOwner.n)), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(rs.u16ToBeBytes(toPair[1]).reverse()), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(rs.byteSliceToArray(toBytes)), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(rs.u16ToBeBytes(toWide.data[toWide.start + 1]).reverse()), undefined, true); + rs.byteVecPush(out, count.strong & 0xff); + } + const _227: rs.u8 = copy$tuple2_u8_u16(pair.v)[0]; + const _230: rs.u8 = copy$pointers_Duo(duo.v)._1; + const _234: Held.Held = owner.v; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(_227, _230, _234.n, copy$array_u8(bytes.v)[1])), undefined, true); + _234[Symbol.dispose](); + rs.byteVecPush(out, count.strong & 0xff); + count[Symbol.dispose](); +} + +/** + * Whole writes of values holding cells into a cell, a tuple, and a struct, each read back + * through a pointer saved into an inner cell before: `UnsafeCell::replace`, `ptr::replace`, + * `ptr::write`, `ptr::swap`, `Cell`'s writes, and assignments through a raw pointer; a + * value `ptr::read` copies out before one, and before a write into a part holding no + * cell; `ptr::write`s into memory not written yet; and pointers `UnsafeCell::raw_get` + * makes into such memory before the write. + */ +export function nestedCells(data: rs.ByteSlice, out: rs.ByteVec): void { + const nest: rs.Cell> = new rs.Cell(new rs.Cell(1)); + const deep: rs.Cell>> = new rs.Cell(new rs.Cell(new rs.Cell(2))); + const pair: rs.Cell<[rs.Cell, rs.u8]> = new rs.Cell([new rs.Cell(3), 4] as [rs.Cell, rs.u8]); + const strukt: rs.Cell = new rs.Cell({ c: new rs.Cell(5), n: 6 }); + const obj: rs.Cell> = new rs.Cell(new rs.Cell([7, 8] as [rs.u8, rs.u8])); + const cell: rs.Cell<[rs.Cell, rs.u8]> = new rs.Cell([new rs.Cell(9), 10] as [rs.Cell, rs.u8]); + const wrapped: rs.Cell> = new rs.Cell(new rs.Cell(11)); + const toWrapped: rs.Place = wrapped.v; + const toNest: rs.Place = nest.v; + const toDeep: rs.Place = deep.v.v; + const toPair: rs.Place = pair.v[0]; + const toStrukt: rs.Place = strukt.v.c; + const toObj: [rs.u8, rs.u8] = obj.v.v; + const toCell: rs.Place = cell.v[0]; + for (const op of rs.byteSliceView(data)) { + const n: rs.u8 = rs.u8Div(op, 8); + const _60: rs.u8 = rs.u8Rem(op, 8); + if (_60 === 0) { + const _64: rs.Cell = new rs.Cell(n as rs.u32); + const pointer16 = nest; + const old16 = new rs.Cell(pointer16.v.v); + const pointer17 = pointer16; + const value25 = _64; + if (pointer17.v === undefined) { + pointer17.v = value25; + } else { + pointer17.v.v = value25.v; + } + undefined; + rs.byteVecPush(out, old16.v & 0xff); + const _71: rs.Cell> = new rs.Cell(new rs.Cell(rs.u32Add(n as rs.u32, 1))); + const pointer18 = deep; + const old17 = new rs.Cell(new rs.Cell(pointer18.v.v.v)); + const pointer19 = pointer18; + const value26 = _71; + if (pointer19.v === undefined) { + pointer19.v = value26; + } else { + pointer19.v.v.v = value26.v.v; + } + undefined; + rs.byteVecPush(out, old17.v.v & 0xff); + const _82: [rs.Cell, rs.u8] = [new rs.Cell(rs.u32Add(n as rs.u32, 2)), n]; + const pointer20 = pair.v; + const object13 = pointer20; + const copy7 = rs.objectCopy(object13); + copy7[0] = new rs.Cell(object13[0].v); + const old18 = copy7; + const object14 = pointer20; + const value27 = _82; + const cell9 = object14[0]; + rs.ptrWrite(object14, value27); + if (cell9 !== undefined) { + object14[0] = cell9; + cell9.v = value27[0].v; + } + undefined; + const old3: [rs.Cell, rs.u8] = old18; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(old3[0].v & 0xff, old3[1])), undefined, true); + const _95: Celled.Celled = { c: new rs.Cell(rs.u32Add(n as rs.u32, 3)), n }; + const pointer21 = strukt.v; + const object15 = pointer21; + const copy8 = rs.objectCopy(object15); + copy8.c = new rs.Cell(object15.c.v); + const old19 = copy8; + const object16 = pointer21; + const value28 = _95; + const cell10 = object16.c; + rs.ptrWrite(object16, value28); + if (cell10 !== undefined) { + object16.c = cell10; + cell10.v = value28.c.v; + } + undefined; + const old4: Celled.Celled = old19; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(old4.c.v & 0xff, old4.n)), undefined, true); + const _108: rs.Cell<[rs.u8, rs.u8]> = new rs.Cell([n, n ^ 1] as [rs.u8, rs.u8]); + const pointer22 = obj; + const old20 = new rs.Cell(copy$tuple2_u8_u8(pointer22.v.v)); + const pointer23 = pointer22; + const value29 = _108; + if (pointer23.v === undefined) { + pointer23.v = value29; + } else { + rs.ptrWrite(pointer23.v.v, value29.v); + } + undefined; + rs.byteVecPush(out, old20.v[1]); + } else if (_60 === 1) { + const _115: rs.Place> = nest; + const _117: rs.Cell = new rs.Cell(((n as rs.u32) ^ 1) >>> 0); + const pointer13 = _115; + const old14 = new rs.Cell(pointer13.v.v); + const pointer14 = pointer13; + const value23 = _117; + if (pointer14.v === undefined) { + pointer14.v = value23; + } else { + pointer14.v.v = value23.v; + } + undefined; + rs.byteVecPush(out, old14.v & 0xff); + const _124: [rs.Cell, rs.u8] = pair.v; + const _126: [rs.Cell, rs.u8] = [new rs.Cell(((n as rs.u32) ^ 2) >>> 0), n]; + const pointer15 = _124; + const object11 = pointer15; + const copy6 = rs.objectCopy(object11); + copy6[0] = new rs.Cell(object11[0].v); + const old15 = copy6; + const object12 = pointer15; + const value24 = _126; + const cell8 = object12[0]; + rs.ptrWrite(object12, value24); + if (cell8 !== undefined) { + object12[0] = cell8; + cell8.v = value24[0].v; + } + undefined; + rs.byteVecPush(out, old15[0].v & 0xff); + } else if (_60 === 2) { + const pointer12 = nest; + const value21 = new rs.Cell(((n as rs.u32) ^ 3) >>> 0); + if (pointer12.v === undefined) { + pointer12.v = value21; + } else { + pointer12.v.v = value21.v; + } + undefined; + const object10 = strukt.v; + const value22 = { c: new rs.Cell(((n as rs.u32) ^ 4) >>> 0), n }; + const cell7 = object10.c; + rs.ptrWrite(object10, value22); + if (cell7 !== undefined) { + object10.c = cell7; + cell7.v = value22.c.v; + } + undefined; + } else if (_60 === 3) { + const other: rs.Cell> = new rs.Cell(new rs.Cell(((n as rs.u32) ^ 5) >>> 0)); + const x = nest; + const y = other; + const old12 = new rs.Cell(x.v.v); + const pointer10 = x; + const value17 = new rs.Cell(y.v.v); + if (pointer10.v === undefined) { + pointer10.v = value17; + } else { + pointer10.v.v = value17.v; + } + undefined; + const pointer11 = y; + const value18 = old12; + if (pointer11.v === undefined) { + pointer11.v = value18; + } else { + pointer11.v.v = value18.v; + } + undefined; + rs.byteVecPush(out, other.v.v & 0xff); + const other2: Celled.Celled = { c: new rs.Cell(((n as rs.u32) ^ 12) >>> 0), n: ~n & 0xff }; + const x2 = strukt.v; + const y2 = other2; + const object6 = x2; + const copy4 = rs.objectCopy(object6); + copy4.c = new rs.Cell(object6.c.v); + const old13 = copy4; + const object7 = y2; + const copy5 = rs.objectCopy(object7); + copy5.c = new rs.Cell(object7.c.v); + const object8 = x2; + const value19 = copy5; + const cell5 = object8.c; + rs.ptrWrite(object8, value19); + if (cell5 !== undefined) { + object8.c = cell5; + cell5.v = value19.c.v; + } + undefined; + const object9 = y2; + const value20 = old13; + const cell6 = object9.c; + rs.ptrWrite(object9, value20); + if (cell6 !== undefined) { + object9.c = cell6; + cell6.v = value20.c.v; + } + undefined; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(other2.c.v & 0xff, other2.n)), undefined, true); + } else if (_60 === 4) { + const _178: [rs.Cell, rs.u8] = [new rs.Cell(((n as rs.u32) ^ 6) >>> 0), n]; + const pointer9 = cell.v; + const object3 = pointer9; + const copy3 = rs.objectCopy(object3); + copy3[0] = new rs.Cell(object3[0].v); + const old11 = copy3; + const object4 = pointer9; + const value15 = _178; + const cell3 = object4[0]; + rs.ptrWrite(object4, value15); + if (cell3 !== undefined) { + object4[0] = cell3; + cell3.v = value15[0].v; + } + undefined; + rs.byteVecPush(out, old11[0].v & 0xff); + const _188: [rs.Cell, rs.u8] = [new rs.Cell(((n as rs.u32) ^ 7) >>> 0), n]; + const object5 = cell.v; + const value16 = _188; + const cell4 = object5[0]; + rs.ptrWrite(object5, value16); + if (cell4 !== undefined) { + object5[0] = cell4; + cell4.v = value16[0].v; + } + undefined; + } else if (_60 === 5) { + toNest.v = rs.u32Mul(n as rs.u32, 3); + toPair.v = rs.u32Mul(n as rs.u32, 5); + const kept: rs.Cell = new rs.Cell(nest.v.v); + const pointer8 = nest; + const value14 = new rs.Cell(rs.u32Add(n as rs.u32, 7)); + if (pointer8.v === undefined) { + pointer8.v = value14; + } else { + pointer8.v.v = value14.v; + } + undefined; + rs.byteVecPush(out, kept.v & 0xff); + } else if (_60 === 6) { + const _212: rs.Cell = new rs.Cell(((n as rs.u32) ^ 8) >>> 0); + const pointer = wrapped; + const old10 = new rs.Cell(pointer.v.v); + const pointer2 = pointer; + const value3 = _212; + if (pointer2.v === undefined) { + pointer2.v = value3; + } else { + pointer2.v.v = value3.v; + } + undefined; + rs.byteVecPush(out, old10.v & 0xff); + const _220: rs.Cell = new rs.Cell(((n as rs.u32) ^ 9) >>> 0); + const pointer3 = wrapped; + const value4 = _220; + if (pointer3.v === undefined) { + pointer3.v = value4; + } else { + pointer3.v.v = value4.v; + } + undefined; + let fresh: rs.Cell = (new rs.Cell(undefined) as unknown) as rs.Cell; + const pointer4 = rs.place(() => fresh, (value5) => fresh = value5); + const value6 = new rs.Cell(((n as rs.u32) ^ 10) >>> 0); + if (pointer4.v === undefined) { + pointer4.v = value6; + } else { + pointer4.v.v = value6.v; + } + undefined; + const parts: [rs.Cell, rs.u8] = ([new rs.Cell(undefined), undefined] as unknown) as [rs.Cell, rs.u8]; + const object = parts; + const value7 = [new rs.Cell(((n as rs.u32) ^ 11) >>> 0), n] as [rs.Cell, rs.u8]; + const cell2 = object[0]; + rs.ptrWrite(object, value7); + if (cell2 !== undefined) { + object[0] = cell2; + cell2.v = value7[0].v; + } + undefined; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(fresh.v & 0xff, parts[0].v & 0xff)), undefined, true); + let slot: rs.Cell = (new rs.Cell(undefined) as unknown) as rs.Cell; + let pairSlot: rs.Cell<[rs.u8, rs.u8]> = (new rs.Cell([undefined, undefined]) as unknown) as rs.Cell<[rs.u8, rs.u8]>; + const toSlot: rs.Place> = rs.place(() => slot, (value8) => slot = value8); + const toPairSlot: rs.Place> = rs.place(() => pairSlot, (value9) => pairSlot = value9); + const _259: [rs.Place, [rs.u8, rs.u8]] = [toSlot.v, toPairSlot.v.v]; + const early: rs.Place = _259[0]; + const earlyPair: [rs.u8, rs.u8] = _259[1]; + const pointer5 = toSlot; + const value10 = new rs.Cell(((n as rs.u32) ^ 17) >>> 0); + if (pointer5.v === undefined) { + pointer5.v = value10; + } else { + pointer5.v.v = value10.v; + } + undefined; + const pointer6 = toPairSlot; + const value11 = new rs.Cell([n, ~n & 0xff] as [rs.u8, rs.u8]); + if (pointer6.v === undefined) { + pointer6.v = value11; + } else { + rs.ptrWrite(pointer6.v.v, value11.v); + } + undefined; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(early.v & 0xff, earlyPair[1])), undefined, true); + let uninit: rs.Cell = new rs.Cell(n as rs.u32); + const readOut: rs.Cell = new rs.Cell(uninit.v); + const pointer7 = rs.place(() => uninit, (value12) => uninit = value12); + const value13 = new rs.Cell(((n as rs.u32) ^ 19) >>> 0); + if (pointer7.v === undefined) { + pointer7.v = value13; + } else { + pointer7.v.v = value13.v; + } + undefined; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(readOut.v & 0xff, uninit.v & 0xff)), undefined, true); + const src: rs.Cell<[rs.Cell, [rs.u32, rs.u32]]> = new rs.Cell([new rs.Cell(n as rs.u32), [2, 3] as [rs.u32, rs.u32]] as [rs.Cell, [rs.u32, rs.u32]]); + const object2 = src.v; + const copy2 = rs.objectCopy(object2); + copy2[0] = new rs.Cell(object2[0].v); + copy2[1] = copy$tuple2_u32_u32(object2[1]); + const copy: [rs.Cell, [rs.u32, rs.u32]] = copy2; + src.v[1][0] = 9; + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(copy[1][0] & 0xff, src.v[1][0] & 0xff)), undefined, true); + } else { + const _316: rs.Cell = new rs.Cell(((n as rs.u32) ^ 13) >>> 0); + const _319: rs.Place> = nest; + const value = _316; + if (_319.v === undefined) { + _319.v = value; + } else { + _319.v.v = value.v; + } + const _321: rs.Cell> = new rs.Cell(new rs.Cell(((n as rs.u32) ^ 14) >>> 0)); + const _325: rs.Place>> = deep; + const value2 = _321; + if (_325.v === undefined) { + _325.v = value2; + } else { + _325.v.v.v = value2.v.v; + } + } + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(toNest.v & 0xff, toDeep.v & 0xff, toPair.v & 0xff, toStrukt.v & 0xff)), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(toObj[0], toObj[1], toCell.v & 0xff, toWrapped.v & 0xff)), undefined, true); + rs.iterExtendBytes(out, rs.iterSlice(Uint8Array.of(nest.v.v & 0xff, pair.v[1], strukt.v.n)), undefined, true); + } +} + /** * Bytes whose `&raw` the body takes, a parameter's included: raw, mutable, and shared * slices of each, and pointers to arrays cast from them by each route, are views of diff --git a/ts/fixtures/lang/pointers/src/lib.rs b/ts/fixtures/lang/pointers/src/lib.rs index 94c7f807f..985c039c8 100644 --- a/ts/fixtures/lang/pointers/src/lib.rs +++ b/ts/fixtures/lang/pointers/src/lib.rs @@ -53,6 +53,17 @@ fn cases() -> Vec<(&'static str, Case)> { ("pointers::generic_unions", |_, data, out| { pointers::generic_unions(data, out) }), + ("pointers::raw_cells", |_, data, out| pointers::raw_cells(data, out)), + ("pointers::cell_writes", |_, data, out| pointers::cell_writes(data, out)), + ("pointers::nested_cells", |_, data, out| { + pointers::nested_cells(data, out) + }), ("pointers::lone_bytes", |_, data, out| pointers::lone_bytes(data, out)), ] } + +/// `UnsafeCell::get` and `raw_get` of a cell of a slice, which only a caller can give, as +/// translated code can't unsize a cell. +pub fn cell_slice(c: &std::cell::UnsafeCell<[u16]>, at: usize) -> u16 { + unsafe { (*std::cell::UnsafeCell::raw_get(c))[at] ^ (*c.get())[0] } +} diff --git a/ts/fixtures/lang/pointers/src/pointers.rs b/ts/fixtures/lang/pointers/src/pointers.rs index 66c8ac8cd..1705c9f96 100644 --- a/ts/fixtures/lang/pointers/src/pointers.rs +++ b/ts/fixtures/lang/pointers/src/pointers.rs @@ -2529,6 +2529,444 @@ pub fn generic_unions(data: &[u8], out: &mut Vec) { } } +/// A struct holding cells, reached through a raw pointer to it. +struct Slots { + num: UnsafeCell, + held: UnsafeCell, + pair: UnsafeCell<(u8, u16)>, +} + +/// What `UnsafeCell::raw_get` gives of a reference to a cell of a number, a struct Rust +/// copies, one JS keeps as an object, a tuple, and arrays of bytes and of numbers; of a +/// pointer to a variable's cell, to a field through a pointer to its struct, and from +/// `MaybeUninit::as_ptr`; cells `UnsafeCell::from_mut` makes of a variable, an object, +/// an element, and an array, written through `get`; `UnsafeCell::replace` of each, which a +/// pointer taken before sees, giving back what it held undropped; what `as_ref_unchecked` +/// and `as_mut_unchecked` lend; and the allocations of boxes and pinned boxes replaced and +/// swapped through pointers, `UnsafeCell`s, one `from_mut` makes, and `Cell`s. +pub fn raw_cells(data: &[u8], out: &mut Vec) { + let count = Rc::new(()); + let num = UnsafeCell::new(7u32); + let duo = UnsafeCell::new(Duo(1, 2)); + let held = UnsafeCell::new(Held { + n: 3, + count: Rc::clone(&count), + }); + let pair = UnsafeCell::new((4u8, 5u16)); + let bytes = UnsafeCell::new([6u8, 7]); + let wide = UnsafeCell::new([8u16, 9]); + let slots = Slots { + num: UnsafeCell::new(10), + held: UnsafeCell::new(Held { + n: 11, + count: Rc::clone(&count), + }), + pair: UnsafeCell::new((12, 13)), + }; + let slot = MaybeUninit::new(UnsafeCell::new(14u32)); + let mut local = 15u32; + let mut whole = Held { + n: 16, + count: Rc::clone(&count), + }; + let mut elems = [17u16, 18, 19]; + for &op in data { + let n = op / 8; + match op % 8 { + // Through references, each read back through `get`. + 0 => unsafe { + *UnsafeCell::raw_get(&num) ^= u32::from(n) << 20; + *UnsafeCell::raw_get(&num as *const _) ^= u32::from(n); + (*UnsafeCell::raw_get(&duo)).1 ^= n; + (*UnsafeCell::raw_get(&held)).n ^= n; + (*UnsafeCell::raw_get(&pair)).1 ^= u16::from(n) << 8; + (*UnsafeCell::raw_get(&bytes))[usize::from(n % 2)] ^= n; + (*UnsafeCell::raw_get(&wide))[usize::from(n % 2)] ^= u16::from(n) << 4; + out.extend((*num.get()).to_le_bytes()); + out.extend([(*duo.get()).1, (*held.get()).n]); + out.extend((*pair.get()).1.to_le_bytes()); + out.extend(*bytes.get()); + out.extend((*wide.get())[1].to_le_bytes()); + }, + // Through raw pointers to where each cell is kept. + 1 => unsafe { + let p = &raw const num; + *UnsafeCell::raw_get(p) = (*UnsafeCell::raw_get(p)).wrapping_mul(u32::from(n) | 1); + let s = &raw const slots; + *UnsafeCell::raw_get(&raw const (*s).num) += u32::from(n); + (*UnsafeCell::raw_get(&raw const (*s).held)).n ^= n; + (*UnsafeCell::raw_get(&raw const (*s).pair)).0 ^= n; + *UnsafeCell::raw_get(slot.as_ptr()) ^= u32::from(n); + out.extend((*num.get()).to_le_bytes()); + out.extend((*slots.num.get()).to_le_bytes()); + out.extend([(*slots.held.get()).n, (*slots.pair.get()).0]); + out.extend((*slot.assume_init_ref().get()).to_le_bytes()); + }, + // Cells of what a `&mut` borrows, written through `get` and seen by the borrowed. + 2 => unsafe { + let c = UnsafeCell::from_mut(&mut local); + *c.get() = (*c.get()).rotate_left(u32::from(n)); + let h = UnsafeCell::from_mut(&mut whole); + (*h.get()).n ^= n; + let e = UnsafeCell::from_mut(&mut elems[usize::from(n % 3)]); + *e.get() ^= u16::from(n); + out.extend(local.to_le_bytes()); + out.push(whole.n); + out.extend(elems.iter().flat_map(|e| e.to_le_bytes())); + }, + // Each replaced, what it held given back, a pointer taken before seeing the new. + 3 => unsafe { + let p = num.get(); + let old = num.replace(u32::from(n) << 3); + out.extend(old.to_le_bytes()); + out.extend((*p).to_le_bytes()); + let p = held.get(); + let old = held.replace(Held { + n, + count: Rc::clone(&count), + }); + out.extend([old.n, (*p).n, Rc::strong_count(&count) as u8]); + drop(old); + out.push(Rc::strong_count(&count) as u8); + let p = pair.get(); + let old = pair.replace((n, u16::from(n) * 3)); + out.extend([old.0, (*p).0]); + let p = bytes.get(); + let old = bytes.replace([n, !n]); + out.extend(old); + out.extend(*p); + let old = duo.replace(Duo(n, n ^ 1)); + out.extend([old.0, old.1, (*duo.get()).0]); + }, + // Through cells `from_mut` makes, each replaced. + 4 => unsafe { + let old = UnsafeCell::from_mut(&mut local).replace(u32::from(n)); + out.extend(old.to_le_bytes()); + let h = UnsafeCell::from_mut(&mut whole); + let p = h.get(); + let old = h.replace(Held { + n: !n, + count: Rc::clone(&count), + }); + out.extend([old.n, (*p).n, whole.n, Rc::strong_count(&count) as u8]); + let old = UnsafeCell::from_mut(&mut elems[usize::from(n % 3)]).replace(u16::from(n)); + out.extend(old.to_le_bytes()); + out.extend(local.to_le_bytes()); + }, + // What the unchecked references lend, and a cell of an array a `&mut` borrows. + 5 => unsafe { + *num.as_mut_unchecked() ^= u32::from(n); + let r = num.as_mut_unchecked(); + *r = r.rotate_left(1); + held.as_mut_unchecked().n ^= n; + pair.as_mut_unchecked().1 ^= u16::from(n); + bytes.as_mut_unchecked()[1] ^= n; + *wide.as_mut_unchecked() = [u16::from(n), 1]; + out.extend(num.as_ref_unchecked().to_le_bytes()); + out.extend([held.as_ref_unchecked().n, duo.as_ref_unchecked().0]); + out.extend(pair.as_ref_unchecked().1.to_le_bytes()); + out.extend(bytes.as_ref_unchecked()); + out.extend(wide.as_ref_unchecked()[0].to_le_bytes()); + let mut arr = [n, 1, 2]; + let a = UnsafeCell::from_mut(&mut arr); + (*a.get())[usize::from(n % 3)] ^= 0x40; + let old = a.replace([3, n, 4]); + out.extend(old); + out.extend(arr); + }, + // Boxes replaced and swapped through pointers and cells, each allocation moving + // with its box. + 6 => unsafe { + let held = |n| Held { + n, + count: Rc::clone(&count), + }; + let mut a = Box::new(held(n)); + let at_a: *const Held = &*a; + let old = ptr::replace(&mut a, Box::new(held(!n))); + let mut other = Box::new(held(n ^ 1)); + let (at_new, at_other): (*const Held, *const Held) = (&*a, &*other); + ptr::swap(&mut a, &mut other); + out.extend([u8::from(ptr::eq(at_a, &*old)), u8::from(ptr::eq(at_new, &*other))]); + out.extend([u8::from(ptr::eq(at_other, &*a)), old.n, a.n, other.n]); + let pinned = UnsafeCell::new(Box::pin((n, 1u16))); + let at_pinned: *const (u8, u16) = &**pinned.get(); + let was = pinned.replace(Box::pin((n ^ 2, 2))); + let (x, y) = (Cell::new(Box::pin((n, 3u16))), Cell::new(Box::pin((!n, 4u16)))); + let at_x: *const (u8, u16) = &**x.as_ptr(); + x.swap(&y); + out.extend([u8::from(ptr::eq(at_x, &**y.as_ptr())), x.into_inner().0]); + out.extend([u8::from(ptr::eq(at_pinned, &*was)), was.0, pinned.into_inner().0]); + let cell = UnsafeCell::new(Box::new(held(n ^ 3))); + let at_cell: *const Held = &**cell.get(); + let was = cell.replace(Box::new(held(n ^ 4))); + let mut boxed = Box::new(held(n ^ 7)); + let at_boxed: *const Held = &*boxed; + let lent = UnsafeCell::from_mut(&mut boxed).replace(Box::new(held(n))); + out.extend([u8::from(ptr::eq(at_boxed, &*lent)), lent.n, boxed.n]); + let (x, y) = (Cell::new(Box::new(held(n ^ 5))), Cell::new(Box::new(held(n ^ 6)))); + let at_x: *const Held = &**x.as_ptr(); + x.swap(&y); + out.extend([u8::from(ptr::eq(at_cell, &*was)), was.n, (*cell.get()).n]); + out.extend([u8::from(ptr::eq(at_x, &**y.as_ptr())), Rc::strong_count(&count) as u8]); + }, + _ => out.push(n), + } + } + out.extend(num.into_inner().to_le_bytes()); + out.extend([held.into_inner().n, Rc::strong_count(&count) as u8]); + out.extend(slots.num.into_inner().to_le_bytes()); + drop(slots.held); + out.extend([whole.n, Rc::strong_count(&count) as u8]); + out.extend(elems.iter().flat_map(|e| e.to_le_bytes())); +} + +thread_local! { + /// The cell `Reentrant`'s `default` and `eq` write. + static REENTERED: Cell = const { Cell::new(Reentrant(1, 1)) }; +} + +/// A struct Rust copies whose `default` and `eq` write the cell holding it. +#[derive(Clone, Copy)] +struct Reentrant(u8, u8); + +impl Default for Reentrant { + fn default() -> Self { + REENTERED.with(|c| c.set(Reentrant(7, 7))); + Reentrant(0, 0) + } +} + +impl PartialEq for Reentrant { + fn eq(&self, other: &Self) -> bool { + REENTERED.with(|c| c.set(Reentrant(9, 9))); + self.0 == other.0 + } +} + +/// What `Cell`s of a tuple, a struct Rust copies, one that owns a count, and arrays of bytes +/// and of numbers, and cells `Cell::from_mut` makes of a tuple and an array, hold after +/// `replace`, `set`, `swap` (but of the arrays), `take`, and `update`, each read back +/// through a pointer `as_ptr` gave before, and what each gives back and drops; and `take` +/// and `==` of a cell its value's `default` and `eq` write. +pub fn cell_writes(data: &[u8], out: &mut Vec) { + let count = Rc::new(()); + let held = |n: u8| Held { + n, + count: Rc::clone(&count), + }; + let pair = Cell::new((1u8, 2u16)); + let duo = Cell::new(Duo(3, 4)); + let owner = Cell::new(held(5)); + let bytes = Cell::new([6u8, 7]); + let wide = Cell::new([8u16, 9]); + let (to_pair, to_duo, to_owner) = (pair.as_ptr(), duo.as_ptr(), owner.as_ptr()); + let (to_bytes, to_wide) = (bytes.as_ptr(), wide.as_ptr()); + let mut lent = (10u8, 11u16); + let mut lent_bytes = [12u8, 13]; + for &op in data { + let n = op / 8; + match op % 8 { + 0 => { + let old = pair.replace((n, u16::from(n) << 8)); + out.extend([old.0, duo.replace(Duo(n, !n)).1, owner.replace(held(n)).n]); + out.extend(bytes.replace([n, 1])); + out.extend(wide.replace([u16::from(n), 2])[1].to_le_bytes()); + } + 1 => { + pair.set((n ^ 1, 3)); + duo.set(Duo(n ^ 2, 4)); + owner.set(held(n ^ 3)); + bytes.set([n ^ 4, 5]); + wide.set([6, u16::from(n) << 4]); + } + 2 => { + pair.swap(&Cell::new((n, 7))); + let other = Cell::new(Duo(8, n)); + duo.swap(&other); + out.extend([other.get().0, other.get().1]); + let other = Cell::new(held(n ^ 5)); + owner.swap(&other); + out.push(other.into_inner().n); + } + 3 => { + out.push(pair.take().0); + out.extend(bytes.take()); + out.extend(wide.take()[0].to_le_bytes()); + } + 4 => { + pair.update(|(a, b)| (a.wrapping_add(n), b ^ 1)); + duo.update(|Duo(a, b)| Duo(b, a ^ n)); + bytes.update(|[a, b]| [b, a.wrapping_mul(n)]); + wide.update(|[a, b]| [b.rotate_left(u32::from(n)), a]); + } + 6 => REENTERED.with(|c| { + c.set(Reentrant(n, 1)); + let taken = c.take(); + out.extend([taken.0, c.get().0]); + c.set(Reentrant(n, 1)); + let same = *c == Cell::new(Reentrant(n, 2)); + out.extend([u8::from(same), c.get().0]); + }), + 5 => unsafe { + let c = Cell::from_mut(&mut lent); + let p = c.as_ptr(); + c.set((n, 1)); + let old = c.replace((n ^ 1, 2)); + c.swap(&Cell::new((n ^ 2, 3))); + c.update(|(a, b)| (a ^ 4, b)); + out.extend([old.0, (*p).0, c.take().0]); + let c = Cell::from_mut(&mut lent_bytes); + let p = c.as_ptr(); + let old = c.replace([n, 5]); + c.update(|[a, b]| [b, a]); + out.extend(old); + out.extend(*p); + out.extend([lent.0, lent_bytes[0]]); + }, + _ => out.push(n), + } + unsafe { + out.extend([(*to_pair).0, (*to_duo).0, (*to_duo).1, (*to_owner).n]); + out.extend((*to_pair).1.to_le_bytes()); + out.extend(*to_bytes); + out.extend((*to_wide)[1].to_le_bytes()); + } + out.push(Rc::strong_count(&count) as u8); + } + out.extend([pair.get().0, duo.get().1, owner.into_inner().n, bytes.get()[1]]); + out.push(Rc::strong_count(&count) as u8); +} + +/// A struct holding a cell beside a number. +struct Celled { + c: UnsafeCell, + n: u8, +} + +/// Whole writes of values holding cells into a cell, a tuple, and a struct, each read back +/// through a pointer saved into an inner cell before: `UnsafeCell::replace`, `ptr::replace`, +/// `ptr::write`, `ptr::swap`, `Cell`'s writes, and assignments through a raw pointer; a +/// value `ptr::read` copies out before one, and before a write into a part holding no +/// cell; `ptr::write`s into memory not written yet; and pointers `UnsafeCell::raw_get` +/// makes into such memory before the write. +pub fn nested_cells(data: &[u8], out: &mut Vec) { + let nest = UnsafeCell::new(UnsafeCell::new(1u32)); + let deep = UnsafeCell::new(UnsafeCell::new(UnsafeCell::new(2u32))); + let pair = UnsafeCell::new((UnsafeCell::new(3u32), 4u8)); + let strukt = UnsafeCell::new(Celled { + c: UnsafeCell::new(5), + n: 6, + }); + let obj = UnsafeCell::new(UnsafeCell::new((7u8, 8u8))); + let cell = Cell::new((UnsafeCell::new(9u32), 10u8)); + let wrapped = Cell::new(UnsafeCell::new(11u32)); + unsafe { + let to_wrapped = (*wrapped.as_ptr()).get(); + let to_nest = (*nest.get()).get(); + let to_deep = (*(*deep.get()).get()).get(); + let to_pair = (*pair.get()).0.get(); + let to_strukt = (*strukt.get()).c.get(); + let to_obj = (*obj.get()).get(); + let to_cell = (*cell.as_ptr()).0.get(); + for &op in data { + let n = op / 8; + match op % 8 { + 0 => { + let old = nest.replace(UnsafeCell::new(u32::from(n))); + out.push(old.into_inner() as u8); + let old = deep.replace(UnsafeCell::new(UnsafeCell::new(u32::from(n) + 1))); + out.push(old.into_inner().into_inner() as u8); + let old = pair.replace((UnsafeCell::new(u32::from(n) + 2), n)); + out.extend([old.0.into_inner() as u8, old.1]); + let old = strukt.replace(Celled { + c: UnsafeCell::new(u32::from(n) + 3), + n, + }); + out.extend([old.c.into_inner() as u8, old.n]); + let old = obj.replace(UnsafeCell::new((n, n ^ 1))); + out.push(old.into_inner().1); + } + 1 => { + let old = ptr::replace(nest.get(), UnsafeCell::new(u32::from(n) ^ 1)); + out.push(old.into_inner() as u8); + let old = ptr::replace(pair.get(), (UnsafeCell::new(u32::from(n) ^ 2), n)); + out.push(old.0.into_inner() as u8); + } + 2 => { + ptr::write(nest.get(), UnsafeCell::new(u32::from(n) ^ 3)); + ptr::write( + strukt.get(), + Celled { + c: UnsafeCell::new(u32::from(n) ^ 4), + n, + }, + ); + } + 3 => { + let other = UnsafeCell::new(UnsafeCell::new(u32::from(n) ^ 5)); + ptr::swap(nest.get(), other.get()); + out.push(other.into_inner().into_inner() as u8); + let mut other = Celled { + c: UnsafeCell::new(u32::from(n) ^ 12), + n: !n, + }; + ptr::swap(strukt.get(), &raw mut other); + out.extend([other.c.into_inner() as u8, other.n]); + } + 4 => { + let old = cell.replace((UnsafeCell::new(u32::from(n) ^ 6), n)); + out.push(old.0.into_inner() as u8); + cell.set((UnsafeCell::new(u32::from(n) ^ 7), n)); + } + 5 => { + *to_nest = u32::from(n) * 3; + *to_pair = u32::from(n) * 5; + let kept = ptr::read(nest.get()); + ptr::write(nest.get(), UnsafeCell::new(u32::from(n) + 7)); + out.push(kept.into_inner() as u8); + } + 6 => { + let old = wrapped.replace(UnsafeCell::new(u32::from(n) ^ 8)); + out.push(old.into_inner() as u8); + wrapped.set(UnsafeCell::new(u32::from(n) ^ 9)); + let mut fresh = MaybeUninit::>::uninit(); + ptr::write(fresh.as_mut_ptr(), UnsafeCell::new(u32::from(n) ^ 10)); + let mut parts = MaybeUninit::<(UnsafeCell, u8)>::uninit(); + ptr::write(parts.as_mut_ptr(), (UnsafeCell::new(u32::from(n) ^ 11), n)); + out.extend([ + *fresh.assume_init_ref().get() as u8, + *parts.assume_init_ref().0.get() as u8, + ]); + let mut slot = MaybeUninit::>::uninit(); + let mut pair_slot = MaybeUninit::>::uninit(); + let to_slot = slot.as_mut_ptr(); + let to_pair_slot = pair_slot.as_mut_ptr(); + let (early, early_pair) = (UnsafeCell::raw_get(to_slot), UnsafeCell::raw_get(to_pair_slot)); + ptr::write(to_slot, UnsafeCell::new(u32::from(n) ^ 17)); + ptr::write(to_pair_slot, UnsafeCell::new((n, !n))); + out.extend([*early as u8, (*early_pair).1]); + let mut uninit = MaybeUninit::new(UnsafeCell::new(u32::from(n))); + let read_out = uninit.assume_init_read(); + ptr::write(uninit.as_mut_ptr(), UnsafeCell::new(u32::from(n) ^ 19)); + out.extend([read_out.into_inner() as u8, *uninit.assume_init_ref().get() as u8]); + let src = UnsafeCell::new((UnsafeCell::new(u32::from(n)), (2u32, 3u32))); + let copy = ptr::read(src.get()); + (*src.get()).1.0 = 9; + out.extend([copy.1.0 as u8, (*src.get()).1.0 as u8]); + } + _ => { + *nest.get() = UnsafeCell::new(u32::from(n) ^ 13); + *deep.get() = UnsafeCell::new(UnsafeCell::new(u32::from(n) ^ 14)); + } + } + out.extend([*to_nest as u8, *to_deep as u8, *to_pair as u8, *to_strukt as u8]); + out.extend([(*to_obj).0, (*to_obj).1, *to_cell as u8, *to_wrapped as u8]); + out.extend([(*nest.get()).get().read() as u8, (*pair.get()).1, (*strukt.get()).n]); + } + } +} + /// Bytes whose `&raw` the body takes, a parameter's included: raw, mutable, and shared /// slices of each, and pointers to arrays cast from them by each route, are views of /// where the byte is, so a write through one reaches it and `offset_from` measures them. diff --git a/ts/fixtures/lang/pointers/ts.toml b/ts/fixtures/lang/pointers/ts.toml index 5cb50e220..cc97ae162 100644 --- a/ts/fixtures/lang/pointers/ts.toml +++ b/ts/fixtures/lang/pointers/ts.toml @@ -1,2 +1,2 @@ package = "lang-pointers-fixture" -roots = ["harness::run", "harness::op"] +roots = ["harness::run", "harness::op", "cell_slice"] diff --git a/ts/fixtures/lang/sorts/expected/lib.ts b/ts/fixtures/lang/sorts/expected/lib.ts index 36b0d81f2..557052212 100644 --- a/ts/fixtures/lang/sorts/expected/lib.ts +++ b/ts/fixtures/lang/sorts/expected/lib.ts @@ -3,6 +3,10 @@ import * as rs from "./rs.ts"; import { sorts, disorders, btrees } from "./sorts.ts"; +export function copy$tuple2_u32_u32(v: [rs.u32, rs.u32]): [rs.u32, rs.u32] { + return [v[0], v[1]]; +} + /** * Each case's name and what it runs. The first two bytes, big-endian, pick one modulo * their count, so a case added at the end moves no other. diff --git a/ts/fixtures/lang/sorts/expected/sorts.ts b/ts/fixtures/lang/sorts/expected/sorts.ts index 5f885871e..a0f877e27 100644 --- a/ts/fixtures/lang/sorts/expected/sorts.ts +++ b/ts/fixtures/lang/sorts/expected/sorts.ts @@ -1,6 +1,7 @@ // Generated by rust2-ts. Do not edit. import * as rs from "./rs.ts"; +import { copy$tuple2_u32_u32 } from "./lib.ts"; import { unwrapOr$1fr498u as option_unwrapOr$1fr498u, mapOr$0z4nmg2 as option_mapOr$0z4nmg2 } from "./core/option.ts"; import type * as Held from "./sorts.Held.ts"; import * as Item from "./sorts.Item.ts"; @@ -14,13 +15,13 @@ export function LOG$init(): rs.Cell<[rs.u32, rs.u32]> { /** Forgets what an earlier case logged, which its panic may have left. */ export function begin(): void { ((log: rs.Cell<[rs.u32, rs.u32]>): undefined => { - rs.cellSet(log, [2166136261, 0]); + rs.ptrWrite(log.v, [2166136261, 0]); })(LOG.get()); } export function note(what: rs.u8, a: rs.u16, b: rs.u16): void { ((log: rs.Cell<[rs.u32, rs.u32]>): undefined => { - const _52: [rs.u32, rs.u32] = log.v; + const _52: [rs.u32, rs.u32] = copy$tuple2_u32_u32(log.v); let hash: rs.u32 = _52[0]; const count: rs.u32 = _52[1]; const iter: rs.Iter = rs.iterSlice(Uint8Array.of(what, a & 0xff, (a >> 8) & 0xff, b & 0xff, (b >> 8) & 0xff)); @@ -31,14 +32,18 @@ export function note(what: rs.u8, a: rs.u16, b: rs.u16): void { } hash = rs.u32WrappingMul((hash ^ _24 as rs.u32) >>> 0, 16777619); } - rs.cellSet(log, [hash, rs.u32Add(count, 1)] as [rs.u32, rs.u32]); + const _33: [rs.u32, rs.u32] = [hash, rs.u32Add(count, 1)]; + rs.ptrWrite(log.v, _33); })(LOG.get()); } /** Puts the log's hash and count, then each tag in order, or a hash of them past 64. */ export function put$Cell_u32(v: rs.Slice>>, out: rs.ByteVec): void { const _5: [rs.u32, rs.u32] = ((log: rs.Cell<[rs.u32, rs.u32]>): [rs.u32, rs.u32] => { - return rs.cellReplace(log, [2166136261, 0]); + const pointer = log.v; + const old = rs.objectCopy(pointer); + rs.ptrWrite(pointer, [2166136261, 0]); + return old; })(LOG.get()); const hash: rs.u32 = _5[0]; const count: rs.u32 = _5[1]; @@ -58,7 +63,10 @@ export function put$Cell_u32(v: rs.Slice>>, out: rs.By /** Puts the log's hash and count, then each tag in order, or a hash of them past 64. */ export function put$array10_u32(v: rs.Slice>, out: rs.ByteVec): void { const _5: [rs.u32, rs.u32] = ((log: rs.Cell<[rs.u32, rs.u32]>): [rs.u32, rs.u32] => { - return rs.cellReplace(log, [2166136261, 0]); + const pointer = log.v; + const old = rs.objectCopy(pointer); + rs.ptrWrite(pointer, [2166136261, 0]); + return old; })(LOG.get()); const hash: rs.u32 = _5[0]; const count: rs.u32 = _5[1]; @@ -78,7 +86,10 @@ export function put$array10_u32(v: rs.Slice>, out: rs.ByteVe /** Puts the log's hash and count, then each tag in order, or a hash of them past 64. */ export function put$array1100_u32(v: rs.Slice>, out: rs.ByteVec): void { const _5: [rs.u32, rs.u32] = ((log: rs.Cell<[rs.u32, rs.u32]>): [rs.u32, rs.u32] => { - return rs.cellReplace(log, [2166136261, 0]); + const pointer = log.v; + const old = rs.objectCopy(pointer); + rs.ptrWrite(pointer, [2166136261, 0]); + return old; })(LOG.get()); const hash: rs.u32 = _5[0]; const count: rs.u32 = _5[1]; @@ -98,7 +109,10 @@ export function put$array1100_u32(v: rs.Slice>, out: rs.Byte /** Puts the log's hash and count, then each tag in order, or a hash of them past 64. */ export function put$array22_u32(v: rs.Slice>, out: rs.ByteVec): void { const _5: [rs.u32, rs.u32] = ((log: rs.Cell<[rs.u32, rs.u32]>): [rs.u32, rs.u32] => { - return rs.cellReplace(log, [2166136261, 0]); + const pointer = log.v; + const old = rs.objectCopy(pointer); + rs.ptrWrite(pointer, [2166136261, 0]); + return old; })(LOG.get()); const hash: rs.u32 = _5[0]; const count: rs.u32 = _5[1]; @@ -118,7 +132,10 @@ export function put$array22_u32(v: rs.Slice>, out: rs.ByteVe /** Puts the log's hash and count, then each tag in order, or a hash of them past 64. */ export function put$array30_u32(v: rs.Slice>, out: rs.ByteVec): void { const _5: [rs.u32, rs.u32] = ((log: rs.Cell<[rs.u32, rs.u32]>): [rs.u32, rs.u32] => { - return rs.cellReplace(log, [2166136261, 0]); + const pointer = log.v; + const old = rs.objectCopy(pointer); + rs.ptrWrite(pointer, [2166136261, 0]); + return old; })(LOG.get()); const hash: rs.u32 = _5[0]; const count: rs.u32 = _5[1]; @@ -138,7 +155,10 @@ export function put$array30_u32(v: rs.Slice>, out: rs.ByteVe /** Puts the log's hash and count, then each tag in order, or a hash of them past 64. */ export function put$sorts_Held(v: rs.Slice>, out: rs.ByteVec): void { const _5: [rs.u32, rs.u32] = ((log: rs.Cell<[rs.u32, rs.u32]>): [rs.u32, rs.u32] => { - return rs.cellReplace(log, [2166136261, 0]); + const pointer = log.v; + const old = rs.objectCopy(pointer); + rs.ptrWrite(pointer, [2166136261, 0]); + return old; })(LOG.get()); const hash: rs.u32 = _5[0]; const count: rs.u32 = _5[1]; @@ -158,7 +178,10 @@ export function put$sorts_Held(v: rs.Slice>, out: rs.ByteVe /** Puts the log's hash and count, then each tag in order, or a hash of them past 64. */ export function put$unit(v: rs.Slice>, out: rs.ByteVec): void { const _5: [rs.u32, rs.u32] = ((log: rs.Cell<[rs.u32, rs.u32]>): [rs.u32, rs.u32] => { - return rs.cellReplace(log, [2166136261, 0]); + const pointer = log.v; + const old = rs.objectCopy(pointer); + rs.ptrWrite(pointer, [2166136261, 0]); + return old; })(LOG.get()); const hash: rs.u32 = _5[0]; const count: rs.u32 = _5[1]; diff --git a/ts/fixtures/reject/census.txt b/ts/fixtures/reject/census.txt index 5dbe12ffc..f7530611f 100644 --- a/ts/fixtures/reject/census.txt +++ b/ts/fixtures/reject/census.txt @@ -10,8 +10,36 @@ 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_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 +fixtures/reject/src/alloc.rs:cell_of_objects+7:15: `Cell::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 +fixtures/reject/src/alloc.rs:cell_of_objects+8:34: `array::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 +fixtures/reject/src/alloc.rs:cell_pointer_kept+2:45: a raw pointer to `std::cell::UnsafeCell` behind a reference, which is the object and not where it is kept +fixtures/reject/src/alloc.rs:cell_pointer_reassigned+2:10: a raw pointer to `std::cell::UnsafeCell` in a variable assigned again while it may point there +fixtures/reject/src/alloc.rs:cell_raw_reassigned+4:19: a raw pointer to `std::cell::UnsafeCell` in a variable assigned again while it may point there +fixtures/reject/src/alloc.rs:cell_raw_reassigned+6:19: a raw pointer to `std::cell::UnsafeCell` in a variable assigned again while it may point there +fixtures/reject/src/alloc.rs:cell_raw_reassigned+7:25: a raw pointer to `std::cell::UnsafeCell` in a variable assigned again while it may point there +fixtures/reject/src/alloc.rs:cell_raw_reassigned+9:19: `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_reassigned+11:19: `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_reassigned+13:19: a raw pointer to `std::mem::MaybeUninit>` in a variable assigned again while it may point there +fixtures/reject/src/alloc.rs:cell_raw_unknown+5:15: `UnsafeCell::raw_get` of a pointer not made of a place of `std::cell::UnsafeCell<(u32, u32)>`, 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+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: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_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 +fixtures/reject/src/alloc.rs:wrapped_cells+9:22: a whole write of `std::mem::ManuallyDrop>`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds +fixtures/reject/src/alloc.rs:wrapped_cells+10:3: a whole write of `(std::mem::MaybeUninit>, u32)`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds +fixtures/reject/src/alloc.rs:wrapped_cells+11:8: a whole write of `std::mem::ManuallyDrop>`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds +fixtures/reject/src/alloc.rs:wrapped_cells+12:3: a whole write of `std::mem::ManuallyDrop>`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds fixtures/reject/src/alloc.rs:zeroed+1:12: 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:zeroed+1:13: unsupported call to `std::alloc::alloc_zeroed` fixtures/reject/src/buffers.rs:blank_bytes+1:2: `Buf::copy_to_bytes` of `buffers::Blank`, a value JS copies, which is not supported @@ -50,18 +78,16 @@ fixtures/reject/src/kept.rs:collected_parts+2:22: a reference through which a ra fixtures/reject/src/kept.rs:collected_parts+2:44: a reference through which a raw pointer may be made into `[u8; 2]` in `kept::Collected`, which the crate may put another object in place of fixtures/reject/src/kept.rs:collected_parts+7:14: a raw pointer to `(u8, u8)` in `kept::Collected`, which the crate may put another object in place of fixtures/reject/src/kept.rs:impl Clone for Copied+2:31: a raw pointer to `(u16, u16)` in `kept::Copied`, which the crate may put another object in place of -fixtures/reject/src/kept.rs:keep_part+1:43: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Escaped`, which the crate may put another object in place of +fixtures/reject/src/kept.rs:keep_part+1:43: a raw pointer to `(u16, u16)` in `std::cell::UnsafeCell<(u16, u16)>`, which the crate may put another object in place of fixtures/reject/src/kept.rs:kept_across_iterations+10:18: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Repeated`, which the crate may put another object in place of -fixtures/reject/src/kept.rs:kept_across_writes+9:26: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Looped`, which the crate may put another object in place of +fixtures/reject/src/kept.rs:kept_across_writes+9:26: a raw pointer to `(u16, u16)` in `std::cell::UnsafeCell<(u16, u16)>`, which the crate may put another object in place of fixtures/reject/src/kept.rs:kept_boxed+5:35: a raw pointer to `std::cell::UnsafeCell` in `kept::ByBox`, which the crate may put another object in place of fixtures/reject/src/kept.rs:kept_called+6:35: a raw pointer to `std::cell::UnsafeCell` in `kept::ByClosure`, which the crate may put another object in place of fixtures/reject/src/kept.rs:kept_instance+6:35: a raw pointer to `std::cell::UnsafeCell` in `kept::ByInstance`, which the crate may put another object in place of fixtures/reject/src/kept.rs:kept_object+6:35: a raw pointer to `std::cell::UnsafeCell` in `kept::ByObject`, which the crate may put another object in place of -fixtures/reject/src/kept.rs:kept_part+1:28: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Called`, which the crate may put another object in place of +fixtures/reject/src/kept.rs:kept_part+1:28: a raw pointer to `(u16, u16)` in `std::cell::UnsafeCell<(u16, u16)>`, which the crate may put another object in place of fixtures/reject/src/kept.rs:kept_read+6:35: a raw pointer to `std::cell::UnsafeCell` in `kept::ByRead`, which the crate may put another object in place of fixtures/reject/src/kept.rs:kept_replaced+6:35: a raw pointer to `std::cell::UnsafeCell` in `kept::ByReplace`, which the crate may put another object in place of -fixtures/reject/src/kept.rs:kept_swapped+7:35: a raw pointer to `std::cell::UnsafeCell` in `kept::BySwap`, which the crate may put another object in place of -fixtures/reject/src/kept.rs:kept_written+6:35: a raw pointer to `std::cell::UnsafeCell` in `kept::ByWrite`, which the crate may put another object in place of fixtures/reject/src/kept.rs:key_replaced+2:55: a raw pointer to `kept::ByKeyReplace` in `(u16, kept::ByKeyReplace)`, which the crate may put another object in place of fixtures/reject/src/kept.rs:key_set+2:51: a raw pointer to `kept::ByKeySet` in `(u16, kept::ByKeySet)`, which the crate may put another object in place of fixtures/reject/src/kept.rs:key_taken+1:52: a raw pointer to `kept::ByKeyTake` in `(u16, kept::ByKeyTake)`, which the crate may put another object in place of @@ -75,8 +101,8 @@ fixtures/reject/src/kept.rs:ref_taken+2:32: a raw pointer to `kept::ByRefTake` i fixtures/reject/src/kept.rs:reversed+3:13: a raw pointer to `(u16, u16)` in `kept::Reversed`, which the crate may put another object in place of fixtures/reject/src/kept.rs:rezipped_parts+8:16: a reference through which a raw pointer may be made into `[u8; 3]` in `[[u8; 3]; 2]`, which the crate may put another object in place of fixtures/reject/src/kept.rs:uninit_rewritten+3:47: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Rewritten`, which the crate may put another object in place of -fixtures/reject/src/kept.rs:written_through_alias+3:29: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Aliased`, which the crate may put another object in place of -fixtures/reject/src/kept.rs:written_through_loaded+3:29: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Loaded`, which the crate may put another object in place of +fixtures/reject/src/kept.rs:written_through_alias+3:29: a raw pointer to `(u16, u16)` in `std::cell::UnsafeCell<(u16, u16)>`, which the crate may put another object in place of +fixtures/reject/src/kept.rs:written_through_loaded+3:29: a raw pointer to `(u16, u16)` in `std::cell::UnsafeCell<(u16, u16)>`, which the crate may put another object in place of fixtures/reject/src/kept.rs:zipped_parts+2:22: a reference through which a raw pointer may be made into `[u8; 2]` in `kept::Zipped`, which the crate may put another object in place of fixtures/reject/src/kept.rs:zipped_parts+2:44: a reference through which a raw pointer may be made into `[u8; 2]` in `kept::Zipped`, which the crate may put another object in place of fixtures/reject/src/kept.rs:zipped_parts+6:14: a raw pointer to `(u8, u8)` in `kept::Zipped`, which the crate may put another object in place of diff --git a/ts/fixtures/reject/expected.txt b/ts/fixtures/reject/expected.txt index 04cd4ee91..6c7b82dbc 100644 --- a/ts/fixtures/reject/expected.txt +++ b/ts/fixtures/reject/expected.txt @@ -14,8 +14,36 @@ 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_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 +fixtures/reject/src/alloc.rs:cell_of_objects+7:15: `Cell::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 +fixtures/reject/src/alloc.rs:cell_of_objects+8:34: `array::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 +fixtures/reject/src/alloc.rs:cell_pointer_kept+2:45: a raw pointer to `std::cell::UnsafeCell` behind a reference, which is the object and not where it is kept +fixtures/reject/src/alloc.rs:cell_pointer_reassigned+2:10: a raw pointer to `std::cell::UnsafeCell` in a variable assigned again while it may point there +fixtures/reject/src/alloc.rs:cell_raw_reassigned+4:19: a raw pointer to `std::cell::UnsafeCell` in a variable assigned again while it may point there +fixtures/reject/src/alloc.rs:cell_raw_reassigned+6:19: a raw pointer to `std::cell::UnsafeCell` in a variable assigned again while it may point there +fixtures/reject/src/alloc.rs:cell_raw_reassigned+7:25: a raw pointer to `std::cell::UnsafeCell` in a variable assigned again while it may point there +fixtures/reject/src/alloc.rs:cell_raw_reassigned+9:19: `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_reassigned+11:19: `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_reassigned+13:19: a raw pointer to `std::mem::MaybeUninit>` in a variable assigned again while it may point there +fixtures/reject/src/alloc.rs:cell_raw_unknown+5:15: `UnsafeCell::raw_get` of a pointer not made of a place of `std::cell::UnsafeCell<(u32, u32)>`, 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+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: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_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 +fixtures/reject/src/alloc.rs:wrapped_cells+9:22: a whole write of `std::mem::ManuallyDrop>`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds +fixtures/reject/src/alloc.rs:wrapped_cells+10:3: a whole write of `(std::mem::MaybeUninit>, u32)`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds +fixtures/reject/src/alloc.rs:wrapped_cells+11:8: a whole write of `std::mem::ManuallyDrop>`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds +fixtures/reject/src/alloc.rs:wrapped_cells+12:3: a whole write of `std::mem::ManuallyDrop>`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds fixtures/reject/src/alloc.rs:zeroed+1:12: 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:zeroed+1:13: unsupported call to `std::alloc::alloc_zeroed` fixtures/reject/src/buffers.rs:blank_bytes+1:2: `Buf::copy_to_bytes` of `buffers::Blank`, a value JS copies, which is not supported @@ -53,18 +81,16 @@ fixtures/reject/src/kept.rs:collected_parts+2:22: a reference through which a ra fixtures/reject/src/kept.rs:collected_parts+2:44: a reference through which a raw pointer may be made into `[u8; 2]` in `kept::Collected`, which the crate may put another object in place of fixtures/reject/src/kept.rs:collected_parts+7:14: a raw pointer to `(u8, u8)` in `kept::Collected`, which the crate may put another object in place of fixtures/reject/src/kept.rs:impl Clone for Copied+2:31: a raw pointer to `(u16, u16)` in `kept::Copied`, which the crate may put another object in place of -fixtures/reject/src/kept.rs:keep_part+1:43: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Escaped`, which the crate may put another object in place of +fixtures/reject/src/kept.rs:keep_part+1:43: a raw pointer to `(u16, u16)` in `std::cell::UnsafeCell<(u16, u16)>`, which the crate may put another object in place of fixtures/reject/src/kept.rs:kept_across_iterations+10:18: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Repeated`, which the crate may put another object in place of -fixtures/reject/src/kept.rs:kept_across_writes+9:26: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Looped`, which the crate may put another object in place of +fixtures/reject/src/kept.rs:kept_across_writes+9:26: a raw pointer to `(u16, u16)` in `std::cell::UnsafeCell<(u16, u16)>`, which the crate may put another object in place of fixtures/reject/src/kept.rs:kept_boxed+5:35: a raw pointer to `std::cell::UnsafeCell` in `kept::ByBox`, which the crate may put another object in place of fixtures/reject/src/kept.rs:kept_called+6:35: a raw pointer to `std::cell::UnsafeCell` in `kept::ByClosure`, which the crate may put another object in place of fixtures/reject/src/kept.rs:kept_instance+6:35: a raw pointer to `std::cell::UnsafeCell` in `kept::ByInstance`, which the crate may put another object in place of fixtures/reject/src/kept.rs:kept_object+6:35: a raw pointer to `std::cell::UnsafeCell` in `kept::ByObject`, which the crate may put another object in place of -fixtures/reject/src/kept.rs:kept_part+1:28: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Called`, which the crate may put another object in place of +fixtures/reject/src/kept.rs:kept_part+1:28: a raw pointer to `(u16, u16)` in `std::cell::UnsafeCell<(u16, u16)>`, which the crate may put another object in place of fixtures/reject/src/kept.rs:kept_read+6:35: a raw pointer to `std::cell::UnsafeCell` in `kept::ByRead`, which the crate may put another object in place of fixtures/reject/src/kept.rs:kept_replaced+6:35: a raw pointer to `std::cell::UnsafeCell` in `kept::ByReplace`, which the crate may put another object in place of -fixtures/reject/src/kept.rs:kept_swapped+7:35: a raw pointer to `std::cell::UnsafeCell` in `kept::BySwap`, which the crate may put another object in place of -fixtures/reject/src/kept.rs:kept_written+6:35: a raw pointer to `std::cell::UnsafeCell` in `kept::ByWrite`, which the crate may put another object in place of fixtures/reject/src/kept.rs:key_replaced+2:55: a raw pointer to `kept::ByKeyReplace` in `(u16, kept::ByKeyReplace)`, which the crate may put another object in place of fixtures/reject/src/kept.rs:key_set+2:51: a raw pointer to `kept::ByKeySet` in `(u16, kept::ByKeySet)`, which the crate may put another object in place of fixtures/reject/src/kept.rs:key_taken+1:52: a raw pointer to `kept::ByKeyTake` in `(u16, kept::ByKeyTake)`, which the crate may put another object in place of @@ -78,8 +104,8 @@ fixtures/reject/src/kept.rs:ref_taken+2:32: a raw pointer to `kept::ByRefTake` i fixtures/reject/src/kept.rs:reversed+3:13: a raw pointer to `(u16, u16)` in `kept::Reversed`, which the crate may put another object in place of fixtures/reject/src/kept.rs:rezipped_parts+8:16: a reference through which a raw pointer may be made into `[u8; 3]` in `[[u8; 3]; 2]`, which the crate may put another object in place of fixtures/reject/src/kept.rs:uninit_rewritten+3:47: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Rewritten`, which the crate may put another object in place of -fixtures/reject/src/kept.rs:written_through_alias+3:29: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Aliased`, which the crate may put another object in place of -fixtures/reject/src/kept.rs:written_through_loaded+3:29: a raw pointer to `std::cell::UnsafeCell<(u16, u16)>` in `kept::Loaded`, which the crate may put another object in place of +fixtures/reject/src/kept.rs:written_through_alias+3:29: a raw pointer to `(u16, u16)` in `std::cell::UnsafeCell<(u16, u16)>`, which the crate may put another object in place of +fixtures/reject/src/kept.rs:written_through_loaded+3:29: a raw pointer to `(u16, u16)` in `std::cell::UnsafeCell<(u16, u16)>`, which the crate may put another object in place of fixtures/reject/src/kept.rs:zipped_parts+2:22: a reference through which a raw pointer may be made into `[u8; 2]` in `kept::Zipped`, which the crate may put another object in place of fixtures/reject/src/kept.rs:zipped_parts+2:44: a reference through which a raw pointer may be made into `[u8; 2]` in `kept::Zipped`, which the crate may put another object in place of fixtures/reject/src/kept.rs:zipped_parts+6:14: a raw pointer to `(u8, u8)` in `kept::Zipped`, which the crate may put another object in place of diff --git a/ts/fixtures/reject/src/alloc.rs b/ts/fixtures/reject/src/alloc.rs index dd4e03d8b..d3ec2b5ea 100644 --- a/ts/fixtures/reject/src/alloc.rs +++ b/ts/fixtures/reject/src/alloc.rs @@ -1,5 +1,7 @@ //! Memory from `alloc` and raw pointers read as other types' bytes or as addresses. +use std::pin::Pin; + use crate::pointers::Halves; /// A pointer read as another type's bytes. @@ -30,6 +32,131 @@ pub fn vec_pointer(v: &mut Vec) -> usize { unsafe { (*p).len() } } +/// `UnsafeCell`s of objects a pointer is the place of, which a whole write through `get` +/// lands in, so a value `replace` reads out before would change too or be a copy, and a +/// `Cell` and an array of a pinned `Box`, whose copy is another allocation. +pub fn cell_of_objects(v: &mut Vec, s: &mut String, p: &mut Pin>, q: &mut Pin>) -> u8 { + let v = std::cell::UnsafeCell::from_mut(v); + let s = std::cell::UnsafeCell::from_mut(s); + let p = std::cell::UnsafeCell::from_mut(p); + let first = unsafe { + v.replace(Vec::new()).len() as u8 ^ s.replace(String::new()).len() as u8 ^ p.replace(Box::pin((3, 4))).0 + }; + let second = std::cell::Cell::from_mut(q).replace(Box::pin((5, 6))).0; + let [third] = std::mem::replace(std::array::from_mut(q), [Box::pin((7, 8))]); + first ^ second ^ third.0 +} + +/// A pointer to a cell behind a reference, made before a call that `UnsafeCell::raw_get` +/// comes after, which reads it in its place only right after it is made. +pub fn cell_pointer_kept(c: &std::cell::UnsafeCell, n: u32) -> u32 { + let x = n.wrapping_mul(3); + let p: *const std::cell::UnsafeCell = c; + let y = vec_pointer(&mut vec![0; x as usize]); + unsafe { *std::cell::UnsafeCell::raw_get(p) + y as u32 } +} + +/// A pointer `UnsafeCell::raw_get` makes of a reference to a cell, read after the variable +/// holding the cell is given another. +pub fn cell_pointer_reassigned(n: u32) -> u32 { + let mut c = std::cell::UnsafeCell::new(n); + let p = std::cell::UnsafeCell::raw_get(&c); + c = std::cell::UnsafeCell::new(n ^ 1); + let _ = &c; + unsafe { *p } +} + +/// Pointers `UnsafeCell::raw_get` makes of a raw pointer to a cell, of one to either of +/// two, of one to it or else null or a parameter, and of a `MaybeUninit`'s, and `get` +/// through the first, read after the variable holding the cell is given another. +pub fn cell_raw_reassigned(n: u32, given: *const std::cell::UnsafeCell) -> u32 { + let mut c = std::cell::UnsafeCell::new(n); + let d = std::cell::UnsafeCell::new(n ^ 2); + let to = &raw const c; + let p = unsafe { std::cell::UnsafeCell::raw_get(to) }; + let either = if n > 3 { &raw const c } else { &raw const d }; + let q = unsafe { std::cell::UnsafeCell::raw_get(either) }; + let r = unsafe { (*to).get() }; + let or_null = if n > 5 { &raw const c } else { std::ptr::null() }; + let s = unsafe { std::cell::UnsafeCell::raw_get(or_null) }; + let or_given = if n > 7 { &raw const c } else { given }; + let t = unsafe { std::cell::UnsafeCell::raw_get(or_given) }; + let mut slot = std::mem::MaybeUninit::new(std::cell::UnsafeCell::new(n ^ 3)); + let u = unsafe { std::cell::UnsafeCell::raw_get(slot.as_ptr()) }; + c = std::cell::UnsafeCell::new(n ^ 1); + slot = std::mem::MaybeUninit::new(std::cell::UnsafeCell::new(n ^ 4)); + let _ = (&c, &d, &slot); + unsafe { *p ^ *q ^ *r ^ *s ^ *t ^ *u } +} + +/// `UnsafeCell::raw_get` of pointers no known place of a cell makes: into an empty `Vec`'s +/// room for cells of a tuple and of a number, which hold no cell yet, past an array's first +/// cell by arithmetic, and through a parameter. +pub fn cell_raw_unknown(n: u32, given: *const std::cell::UnsafeCell) -> u32 { + let mut pairs = Vec::>::with_capacity(1); + let mut nums = Vec::>::with_capacity(1); + let cells = [std::cell::UnsafeCell::new(n), std::cell::UnsafeCell::new(n ^ 1)]; + unsafe { + let empty = std::cell::UnsafeCell::raw_get(pairs.as_mut_ptr()).is_null(); + std::cell::UnsafeCell::raw_get(nums.as_mut_ptr()).write(7); + nums.set_len(1); + let next = *std::cell::UnsafeCell::raw_get(cells.as_ptr()).add(1); + let at = *std::cell::UnsafeCell::raw_get(&raw const (*given)); + u32::from(empty) ^ *nums[0].get() ^ next ^ at + } +} + +/// A `MaybeUninit` of a cell, whose `assume_init_mut` is the place the cell is kept in, lent +/// as the value by `get_mut`. +pub fn uninit_cell_lent(n: u32) -> u32 { + let mut slot = std::mem::MaybeUninit::new(std::cell::UnsafeCell::new(n)); + unsafe { *slot.assume_init_mut().get_mut() + 1 } +} + +/// Whole writes of values holding a cell in a `MaybeUninit` or `ManuallyDrop`, which would +/// put another cell in place of one a pointer `get` gave points into: `UnsafeCell::replace` +/// of a wrapped tuple and of a wrapped cell, `ptr::write` of a tuple holding one, +/// `Cell::set`, and an assignment through a raw pointer. +pub fn wrapped_cells(n: u32) -> u32 { + use std::cell::{Cell, UnsafeCell}; + use std::mem::{ManuallyDrop, MaybeUninit}; + let tuple = UnsafeCell::new(MaybeUninit::new((UnsafeCell::new(n), n))); + let manual = UnsafeCell::new(ManuallyDrop::new(UnsafeCell::new(n))); + let mut pair = (MaybeUninit::new(UnsafeCell::new(n)), n); + let cell = Cell::new(ManuallyDrop::new(UnsafeCell::new(n))); + unsafe { + let old = tuple.replace(MaybeUninit::new((UnsafeCell::new(1), 1))); + let older = manual.replace(ManuallyDrop::new(UnsafeCell::new(2))); + std::ptr::write(&raw mut pair, (MaybeUninit::new(UnsafeCell::new(3)), 3)); + cell.set(ManuallyDrop::new(UnsafeCell::new(4))); + *manual.get() = ManuallyDrop::new(UnsafeCell::new(5)); + old.assume_init().1 ^ ManuallyDrop::into_inner(older).into_inner() ^ pair.1 + } +} + +/// 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] }; + let (x, y) = ( + std::cell::Cell::new([[1u16, 2]; 2]), + std::cell::Cell::new([[3u16, 4]; 2]), + ); + 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 +} + +/// 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 { + let old = std::mem::replace(c.get_mut(), Box::pin((1, 2))); + let older = std::mem::replace(unsafe { c.as_mut_unchecked() }, Box::pin((3, 4))); + old.0 ^ older.0 +} + /// Casts between pointers to bytes and to values outside memory from `alloc`, which read /// the bytes of one type as another: of an array's bytes to `u32`s, of memory from /// `alloc` to the crate's struct, which JS keeps as an object, and of a pointer to values diff --git a/ts/fixtures/reject/src/kept.rs b/ts/fixtures/reject/src/kept.rs index 5a8e93ab3..c420f5f15 100644 --- a/ts/fixtures/reject/src/kept.rs +++ b/ts/fixtures/reject/src/kept.rs @@ -208,10 +208,6 @@ pub fn pushed_part_kept(n: u16) -> u16 { /// may still be read. pub struct ByRead(pub std::cell::UnsafeCell); -pub struct ByWrite(pub std::cell::UnsafeCell); - -pub struct BySwap(pub std::cell::UnsafeCell); - pub struct ByReplace(pub std::cell::UnsafeCell); pub struct ByBox(pub std::cell::UnsafeCell); @@ -260,31 +256,6 @@ pub fn kept_read(n: u16) -> u16 { unsafe { *part } } -/// Read back from memory, then written whole by `ptr::write`. -pub fn kept_written(n: u16) -> u16 { - let mut whole = ByWrite(cell(n)); - let mut kept = Kept { - at: std::ptr::null_mut(), - }; - kept.at = &raw mut whole; - let part = unsafe { (*kept.at).0.get() }; - unsafe { kept.at.write(ByWrite(cell(0))) }; - unsafe { *part } -} - -/// Read back from memory, then swapped whole by `ptr::swap`. -pub fn kept_swapped(n: u16) -> u16 { - let mut whole = BySwap(cell(n)); - let mut other = BySwap(cell(0)); - let mut kept = Kept { - at: std::ptr::null_mut(), - }; - kept.at = &raw mut whole; - let part = unsafe { (*kept.at).0.get() }; - unsafe { std::ptr::swap(kept.at, &raw mut other) }; - unsafe { *part } -} - /// Read back from memory, then replaced whole by `mem::replace` through a `&mut`. pub fn kept_replaced(n: u16) -> u16 { let mut whole = ByReplace(cell(n)); diff --git a/ts/fixtures/reject/ts.toml b/ts/fixtures/reject/ts.toml index ae956cc1c..ae0d56fcd 100644 --- a/ts/fixtures/reject/ts.toml +++ b/ts/fixtures/reject/ts.toml @@ -4,8 +4,17 @@ roots = [ "alloc::alloc_retyped", "alloc::allocated", "alloc::bytes_as_values", + "alloc::cell_of_arrays", + "alloc::cell_of_objects", + "alloc::cell_pointer_kept", + "alloc::cell_pointer_reassigned", + "alloc::cell_raw_reassigned", + "alloc::cell_raw_unknown", + "alloc::pinned_lent", "alloc::reinterpreted", + "alloc::uninit_cell_lent", "alloc::vec_pointer", + "alloc::wrapped_cells", "alloc::zeroed", "bound_ranges", "buffers::blank_bytes", @@ -50,8 +59,6 @@ roots = [ "kept::kept_object", "kept::kept_read", "kept::kept_replaced", - "kept::kept_swapped", - "kept::kept_written", "kept::key_replaced", "kept::key_set", "kept::key_taken", diff --git a/ts/fixtures/task/expected/drops/called.ts b/ts/fixtures/task/expected/drops/called.ts index 868d8b4f9..96d79fb7c 100644 --- a/ts/fixtures/task/expected/drops/called.ts +++ b/ts/fixtures/task/expected/drops/called.ts @@ -437,7 +437,7 @@ export function called(log: Log.Log, id: rs.u32, arg: rs.u8): void { }); rs.cellUpdate(new rs.Cell(1), rs.once(add)); const pair: rs.Cell = new rs.Cell([1, 2]); - rs.cellUpdate(pair, (p: rs.u32[]): rs.u32[] => { + const _510: (a0: rs.u32[]) => rs.u32[] = (p: rs.u32[]): rs.u32[] => { p = copy$array_u32(p); p[0] = rs.u32Add(p[0], 10); const _155: rs.u32[] = copy$array_u32(pair.v); @@ -446,7 +446,9 @@ export function called(log: Log.Log, id: rs.u32, arg: rs.u8): void { const args76 = [(f: rs.Formatter) => rs.u32Display(part2, f), (f: rs.Formatter) => rs.u32Display(part3, f)]; Log.note(log, rs.fmtFormat(["pair ", args76[0], " ", args76[1]])); return copy$array_u32(p); - }); + }; + const pointer = rs.sliceFrom(pair.v); + 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)])); const part5 = rs.refCellReplaceWith(cell2, rs.once(doubled), true); diff --git a/ts/runtime/rs/task.ts b/ts/runtime/rs/task.ts index a16e5d952..019616f4e 100644 --- a/ts/runtime/rs/task.ts +++ b/ts/runtime/rs/task.ts @@ -921,21 +921,20 @@ export function cellOfArraySlice(r: ArraySlice, copy?: El } /** - * `Cell::from_mut` of the object or the bytes a `&mut` is: a read is a copy, as a `Cell` - * only moves or copies its value out, and a write lands in place, a JS array's taking - * the new one's length. A read copies as `objectCopy` copies to `depth`. + * `Cell::from_mut` of an object a `&mut` is, which a pointer to is a place of: a read is + * a copy, as a `Cell` only moves or copies its value out, and a write lands in place. */ -export function cellIn(p: T, depth = 0): Cell { +export function cellIn(p: T): Cell { const write = partPlace(p); - return cellOfPlace(place(() => objectCopy(p, depth), (value) => (write.v = value))); + return cellOfPlace(place(() => objectCopy(p), (value) => (write.v = value))); } /** * `PartialEq`, `PartialOrd`, or `Ord` of `Cell`s or places, or `PartialEq` of `OnceCell`s - * or `OnceLock`s, by `f` of what each holds. + * or `OnceLock`s, by `f` of what each holds, or of its `copy`, as a `Cell`'s `get` gives. */ -export function cellBy(f: (a: T, b: T) => R): (a: { v: T }, b: { v: T }) => R { - return (a, b) => f(a.v, b.v); +export function cellBy(f: (a: T, b: T) => R, copy?: (v: T) => T): (a: { v: T }, b: { v: T }) => R { + return copy ? (a, b) => f(copy(a.v), copy(b.v)) : (a, b) => f(a.v, b.v); } /** `Cell::replace`: the value it held, `v` in its place. */ diff --git a/ts/src/census.rs b/ts/src/census.rs index 151e6dd00..47e3fda6d 100644 --- a/ts/src/census.rs +++ b/ts/src/census.rs @@ -146,6 +146,7 @@ const VERBATIM: &[&str] = &[ "Buf::copy_to_bytes", "BufMut::put", "BytesMut", + "Cell::swap", "Copy", "Debug", "Display", @@ -158,6 +159,9 @@ const VERBATIM: &[&str] = &[ "Location", "LowerExp", "MAY_HAVE_SIDE_EFFECT", + "ManuallyDrop", + "MaybeUninit", + "MaybeUninit::assume_init_mut", "None", "Octal", "Option", @@ -169,6 +173,8 @@ const VERBATIM: &[&str] = &[ "Reborrow", "Result", "Some", + "UnsafeCell::from_mut", + "UnsafeCell::raw_get", "UpperExp", "Vec::into_flattened", "Vec::splice", diff --git a/ts/src/lower/collections.rs b/ts/src/lower/collections.rs index 5a1b759e0..ad10ad4ea 100644 --- a/ts/src/lower/collections.rs +++ b/ts/src/lower/collections.rs @@ -1235,7 +1235,7 @@ pub fn test_fn<'tcx>(b: &mut Body<'_, '_, 'tcx>, ty: Ty<'tcx>, test: &str, span: } ty::Adt(..) if let Some((inner, by)) = cell_of(b, ty) => { let f = test_fn(b, inner, test, span); - cell_by(b, by, f, test) + cell_by(b, ty, by, f, test, span) } _ => { let f = trait_fn(tcx, "PartialOrd", test); @@ -3047,11 +3047,18 @@ fn cell_of<'tcx>(b: &Body<'_, '_, 'tcx>, ty: Ty<'tcx>) -> Option<(Ty<'tcx>, &'st /// The runtime's `by` of `f`, as [`cell_of`] says a cell compares, for its `method`: given /// where a `RefCell`'s borrows, in a program with a panic hook. -fn cell_by(b: &Body<'_, '_, '_>, by: &str, f: Expr, method: &str) -> Expr { +/// A `Cell`'s values are compared as copies, as its `get` gives them, since a comparison +/// may write the cell, and a write lands in an object it holds. +fn cell_by<'tcx>(b: &mut Body<'_, '_, 'tcx>, ty: Ty<'tcx>, by: &str, f: Expr, method: &str, span: Span) -> Expr { let mut values = vec![f]; if by == "refCellBy" && b.t.hooked { values.extend(super::caller::cell_sites(b.t.tcx, method)); } + if let ty::Adt(_, args) = ty.kind() + && b.t.std_of(ty) == Some(Std::Cell) + { + values.extend(b.t.copy_fn(args.type_at(0), span)); + } Expr::rs(by, values) } @@ -3091,7 +3098,7 @@ pub fn cmp_fn<'tcx>(b: &mut Body<'_, '_, 'tcx>, ty: Ty<'tcx>, partial: bool, spa ty::Adt(..) if let Some(inner) = arc_of(b, ty) => Expr::rs("cmpArc", vec![cmp_fn(b, inner, partial, span)]), ty::Adt(..) if let Some((inner, by)) = cell_of(b, ty) => { let cmp = cmp_fn(b, inner, partial, span); - cell_by(b, by, cmp, if partial { "partial_cmp" } else { "cmp" }) + cell_by(b, ty, by, cmp, if partial { "partial_cmp" } else { "cmp" }, span) } // An `rs.Place` compares by its value, as std's impl on `&mut` does by what it points at. ty::Ref(..) if let Some(inner) = b.t.place_pointee(ty) => { @@ -3189,7 +3196,7 @@ pub fn eq_fn<'tcx>(b: &mut Body<'_, '_, 'tcx>, ty: Ty<'tcx>, span: Span) -> Expr // Whose `ne` is `!eq`, which compares what it holds by `eq`. ty::Adt(..) if let Some((inner, by)) = cell_of(b, ty) => { let eq = eq_fn(b, inner, span); - cell_by(b, by, eq, "eq") + cell_by(b, ty, by, eq, "eq", span) } ty::Ref(..) if let Some(inner) = b.t.place_pointee(ty) => Expr::rs("cellBy", vec![eq_fn(b, inner, span)]), _ if by_own(b, ty) || derived_std(b, ty) || b.t.std_of(ty).is_some_and(Std::record) => { diff --git a/ts/src/lower/copy.rs b/ts/src/lower/copy.rs index 1d4924d77..05253cecd 100644 --- a/ts/src/lower/copy.rs +++ b/ts/src/lower/copy.rs @@ -540,6 +540,7 @@ impl<'tcx> Writes<'tcx> { } BodyWrites { tcx, + t, body, def_id, writes: &mut writes, @@ -658,8 +659,8 @@ fn by_value<'tcx>(tcx: TyCtxt<'tcx>, env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>) -> /// The value std's `def_id`, given `this` as its `self`, writes whole through that shared /// reference, putting another object in its place: the value of the `RefCell` it is, or -/// that a thread-local's `RefCell` holds. A `Cell`'s are left out, as none of its methods -/// that translate lends a reference into its value. +/// that a thread-local's `RefCell` holds. A `Cell`'s and an `UnsafeCell`'s are left out, +/// as each writes into the object it holds, which [`cell_writes`] says. fn replaces<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, this: Ty<'tcx>) -> Option> { let (owner, name) = super::library::key(tcx, def_id)?; let replaces = matches!( @@ -682,6 +683,35 @@ fn replaces<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, this: Ty<'tcx>) -> Option(tcx: TyCtxt<'tcx>, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Option> { + let (owner, name) = super::library::key(tcx, def_id)?; + let writes = match owner.as_str() { + // Refused of an array. + "Cell" if name == "swap" && args.type_at(0).is_array() => false, + "Cell" if super::array_slice::of_arrays(args.type_at(0)) => false, + "Cell" => matches!(name.as_str(), "replace" | "set" | "swap" | "take" | "update"), + "UnsafeCell" => name == "replace", + _ => false, + }; + (writes && super::library::is_std(tcx, def_id)).then(|| args.type_at(0)) +} + +/// The type std's `def_id` writes whole through a raw pointer to one, by the runtime's +/// write of a pointer's value: `ptr::write`, `replace`, or `swap`. +fn pointer_writes<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Option> { + let (owner, name) = super::library::key(tcx, def_id)?; + let writes = owner == "ptr" + && matches!( + name.as_str(), + "write" | "write_unaligned" | "write_volatile" | "replace" | "swap" + ); + (writes && super::library::is_std(tcx, def_id)).then(|| args.type_at(0)) +} + /// The place each local of `body` borrows, where its one assignment is a borrow and /// nothing borrows the local itself, through which it could be pointed elsewhere. fn borrows<'tcx>(body: &mir::Body<'tcx>) -> IndexVec>> { @@ -928,6 +958,7 @@ impl<'tcx> Visitor<'tcx> for UsesOf<'_> { /// The writes of one body. struct BodyWrites<'w, 'm, 'a, 'tcx> { tcx: TyCtxt<'tcx>, + t: &'m Translator<'a, 'tcx>, body: &'m mir::Body<'tcx>, def_id: DefId, writes: &'w mut Writes<'tcx>, @@ -958,6 +989,30 @@ impl<'tcx> BodyWrites<'_, '_, '_, 'tcx> { } } + /// A whole `ty` written into in place by the runtime's write of a cell's value, which + /// keeps each cell it [keeps](Translator::keeps_cells), writing into it in place too, + /// and replaces the rest as [`Self::replace`] does. + fn replace_kept(&mut self, ty: Ty<'tcx>) { + use super::pointer::KeptCells; + self.insert(ty); + match self.t.kept_cells(ty) { + Some(KeptCells::Cell(held)) => self.replace_kept(held), + Some(KeptCells::Fields(fields)) => { + for (i, (field, kept)) in fields.into_iter().enumerate() { + match kept { + true => self.replace_kept(field), + false => { + let holders = self.writes.holders.entry(Some(FieldIdx::from_usize(i))).or_default(); + holders.insert(self.tcx, self.def_id, ty); + self.replace(field); + } + } + } + } + None => self.replace(ty), + } + } + /// `ty` and each type it holds by value, at any depth, a part of which may be kept as a /// JS object. fn parts(&self, ty: Ty<'tcx>) -> Vec> { @@ -1220,8 +1275,16 @@ impl<'tcx> Visitor<'tcx> for BodyWrites<'_, '_, '_, 'tcx> { { self.replace(value); } + if let Some(held) = cell_writes(self.tcx, def_id, args.skip_binder()) { + self.replace_kept(held); + } + // A pointer's whole write keeps the cells a value keeps, as a cell's does. + let kept = pointer_writes(self.tcx, def_id, args.skip_binder()).filter(|&ty| self.t.keeps_cells(ty)); + if let Some(ty) = kept { + self.replace_kept(ty); + } // Those that point a pointer elsewhere or read through it replace nothing. - let replace = !super::pointer::keeps(self.tcx, def_id, args.skip_binder()); + let replace = kept.is_none() && !super::pointer::keeps(self.tcx, def_id, args.skip_binder()); // A call's argument may point into memory nothing else points into yet. let body = self.body; let call = match &body[location.block].terminator().kind { diff --git a/ts/src/lower/lend.rs b/ts/src/lower/lend.rs index 01f0593d7..f629db886 100644 --- a/ts/src/lower/lend.rs +++ b/ts/src/lower/lend.rs @@ -75,7 +75,7 @@ pub fn plan<'tcx>(t: &Translator<'_, 'tcx>, def_id: DefId, args: GenericArgsRef< ("mem", "swap" | "replace" | "take") | ("Clone", "clone_from") | ("ToOwned", "clone_into") - | ("raw" | "array" | "Cell" | "ptr", "from_mut") + | ("raw" | "array" | "Cell" | "UnsafeCell" | "ptr", "from_mut") | ("Option", "get_or_insert" | "get_or_insert_with" | "get_or_insert_default" | "insert") => true, // `Clone::clone`, which takes the slice, and an array as a slice, which it is. ("ToOwned", "to_owned") => true, diff --git a/ts/src/lower/mir/call.rs b/ts/src/lower/mir/call.rs index 1e32932ec..ac23a39ef 100644 --- a/ts/src/lower/mir/call.rs +++ b/ts/src/lower/mir/call.rs @@ -347,9 +347,65 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { if let Some(err) = self.std_places(def_id, gargs, result, span) { return err; } + // `raw_get`'s pointer must be made of places of its cell, as one into memory + // holding no cell yet, such as a `Vec`'s room past its length, or one moved off + // the cell it was made of, has no cell to give. Each is judged as `get` of it. + if library::key(tcx, def_id).is_some_and(|(o, n)| o == "UnsafeCell" && n == "raw_get") { + let cell = tcx.type_of(tcx.parent(def_id)).instantiate(tcx, gargs).skip_norm_wip(); + let origins = args[0] + .node + .place() + .and_then(|p| self.raw_origins(p.as_local()?, &mut Vec::new())) + .filter(|o| { + o.iter().all(|at| { + // Or a `MaybeUninit` of it, which `as_ptr` points into. + let ty = at.ty(&self.mir.local_decls, tcx).ty; + ty == cell + || matches!(ty.kind(), ty::Adt(adt, args) if Std::of(tcx, adt.did()) == Some(Std::MaybeUninit) && args.type_at(0) == cell) + }) + }); + let Some(origins) = origins else { + return self.err( + span, + format!( + "`UnsafeCell::raw_get` of a pointer not made of a place of `{cell}`, such as a parameter, a vector's or a slice's, or one moved by arithmetic, which may point where no cell is" + ), + ); + }; + let judged = + origins + .into_iter() + .find_map(|at| match at.ty(&self.mir.local_decls, tcx).ty == cell { + true => self.made_out_of_step(def_id, gargs, at), + // What holds the slot, which holds the cell, is judged whole. + false => self.out_of_step(at, true), + }); + if let Some(why) = judged { + return self.err(span, why); + } + } + // The cell `get`'s reference points at is judged as each place the pointer it + // reborrows, as `(*p).get()` does, may have been made of, where all are known, + // and else as what the reference points at. + let reborrowed = |l: rustc_middle::mir::Local| match self.def_rvalue(l) { + Some(rustc_middle::mir::Rvalue::Ref(_, _, at)) + if self.defs[l] == 1 && at.projection.as_slice() == [ProjectionElem::Deref] => + { + Some(at.local) + } + _ => None, + }; if crate::lower::pointer::from_reference(tcx, def_id, gargs) - && let Some(why) = self.made_out_of_step(def_id, gargs, &args[0].node) - { + && let Some(why) = args[0].node.place().and_then(|p| { + let origins = p + .as_local() + .and_then(reborrowed) + .and_then(|l| self.raw_origins(l, &mut Vec::new())); + origins + .unwrap_or_else(|| vec![tcx.mk_place_deref(p)]) + .into_iter() + .find_map(|at| self.made_out_of_step(def_id, gargs, at)) + }) { return self.err(span, why); } crate::lower::pointer::pointees(self.b.t, def_id, gargs) @@ -541,6 +597,25 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { { done(p, false) } + // `get` of the cell a reference points at, which the pointer it was made into + // would only be where that cell is kept. + ("UnsafeCell", "raw_get") + if let Some(cell) = args[0] + .node + .place() + .and_then(|p| self.raw_cells.get(&p.as_local()?).copied()) => + { + if let Some(why) = self.made_out_of_step(def_id, gargs, cell) { + return Some(Some((self.err(span, why), false))); + } + let cell = self.place_expr(cell, span, out); + let get = tcx + .associated_items(tcx.parent(def_id)) + .filter_by_name_unhygienic(rustc_span::Symbol::intern("get")) + .next()? + .def_id; + done(self.b.call_def(get, gargs, vec![cell], span, out), false) + } // A place of no bytes has nothing to read or write, and every value of its type // is the one it holds. What made the `&mut` still runs, as its unread temporary. ("mem", "take" | "replace" | "swap") if self.b.t.zero_sized(targ(0)?) => match name.as_str() { @@ -583,7 +658,7 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { && let (Some((s, i)), Some((t, j))) = (self.element_in(&a, ty), self.element_in(&c, ty)) { let mut made = vec![s, i, t, j]; - made.extend(self.copy_depth(ty)); + made.extend(self.b.t.copy_depth(ty)); out.push(StmtKind::Expr(Expr::rs("sliceSwapAcross", made)).at(None)); return done(Expr::undefined(), false); } @@ -725,10 +800,10 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { } // A slice or an array of the one value, or a cell of it, read and written where the // `&mut` points. - ("raw" | "array", "from_mut") | ("Cell", "from_mut") + ("raw" | "array" | "Cell" | "UnsafeCell", "from_mut") if owner != "raw" || library::std_path(tcx, def_id) == ["slice", "raw", "from_mut"] => { - let made = self.one_of(owner == "Cell", targ(0)?, &args[0].node, span, out)?; + let made = self.one_of(&owner, targ(0)?, &args[0].node, span, out)?; done(made, true) } // A range of numbers steps in place, with nothing between it and the loop. @@ -1418,6 +1493,109 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { Some(borrowed) } + /// The places the raw pointer `local` may have been made of: by `&raw` or a reference of + /// one, through copies and casts, or by `MaybeUninit::as_ptr` or `as_mut_ptr` of one, + /// which points at its value. `None` if it is a parameter, is written through, or any + /// assignment of it is something else. + fn raw_origins( + &self, + local: rustc_middle::mir::Local, + seen: &mut Vec, + ) -> Option>> { + use rustc_middle::mir::{Rvalue, StatementKind, TerminatorKind}; + let tcx = self.tcx; + // A cycle, whose places the path to it already has. + if seen.contains(&local) { + return Some(Vec::new()); + } + seen.push(local); + if (1..=self.mir.arg_count).contains(&local.as_usize()) || self.mutated[local] { + return None; + } + let (mut found, mut origins) = (0, Vec::new()); + for (bb, data) in self.mir.basic_blocks.iter_enumerated() { + for (i, stmt) in data.statements.iter().enumerate() { + let StatementKind::Assign(assign) = &stmt.kind else { + continue; + }; + let (place, rvalue) = &**assign; + if place.as_local() != Some(local) + || self.noops.contains(&(bb, i)) + || self.in_ignored(stmt.source_info.span) + { + continue; + } + found += 1; + match rvalue { + Rvalue::RawPtr(_, made) | Rvalue::Ref(_, _, made) => { + origins.extend(self.place_origins(*made, seen)?) + } + Rvalue::Use(Operand::Copy(from) | Operand::Move(from), _) + | Rvalue::Cast(_, Operand::Copy(from) | Operand::Move(from), _) => { + origins.extend(self.raw_origins(from.as_local()?, seen)?) + } + _ => return None, + } + } + let TerminatorKind::Call { + func, + args, + destination, + .. + } = &data.terminator().kind + else { + continue; + }; + if destination.as_local() != Some(local) { + continue; + } + found += 1; + let ty::FnDef(def_id, _) = *func.ty(&self.mir.local_decls, tcx).kind() else { + return None; + }; + let as_ptr = library::is_std(tcx, def_id) + && library::key(tcx, def_id) + .is_some_and(|(o, n)| o == "MaybeUninit" && matches!(n.as_str(), "as_ptr" | "as_mut_ptr")); + let r = args + .first()? + .node + .place()? + .as_local() + .filter(|&r| as_ptr && self.defs[r] == 1)?; + let Some(Rvalue::Ref(_, _, made)) = self.def_rvalue(r) else { + return None; + }; + origins.extend(self.place_origins(*made, seen)?); + } + // Off the path, as another branch may reach it again. + seen.pop(); + (found == self.defs[local]).then_some(origins) + } + + /// The places `made`, which a pointer is made of, may be: itself, or where it derefs a + /// raw pointer first, each place that one may have been made of, projected the same way. + /// `None` if it derefs a raw pointer of unknown origin, or one anywhere else. + fn place_origins(&self, made: Place<'tcx>, seen: &mut Vec) -> Option>> { + let tcx = self.tcx; + let raw = |i: usize| { + made.projection[i] == ProjectionElem::Deref + && Place::ty_from(made.local, &made.projection[..i], &self.mir.local_decls, tcx) + .ty + .is_raw_ptr() + }; + match (0..made.projection.len()).find(|&i| raw(i)) { + None => return Some(vec![made]), + Some(0) => {} + Some(_) => return None, + } + let rest = &made.projection[1..]; + let mut places = Vec::new(); + for at in self.raw_origins(made.local, seen)? { + places.extend(self.place_origins(at.project_deeper(rest, tcx), seen)?); + } + Some(places) + } + /// The slice `place`, an array a reference points at, is, whose copy `read` /// [`Self::borrowed_place`] made of it. fn borrowed_slice(&mut self, read: Expr, place: Place<'tcx>, span: Span, out: &mut Vec) -> Expr { @@ -1427,15 +1605,17 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { } } - /// `slice::from_mut`, `array::from_mut`, or with `cell`, `Cell::from_mut` of `op`, a - /// `&mut` to a `ty`: of the `rs.Place` it is or of the place it names, or else in place - /// of the bytes or the object it is, which a cell reads a copy of, as a `Cell` only - /// moves or copies a value out, and a slice writes its element into. A slice of one - /// byte no array holds is refused, as is either of an object JS can't write a whole - /// value into. + /// `slice::from_mut`, `array::from_mut`, or `from_mut` of `owner`, `Cell` or + /// `UnsafeCell`, of `op`, a `&mut` to a `ty`: of the `rs.Place` it is or of the place it + /// names, or else in place of the bytes or the object it is, which a cell lends as itself, + /// as its `get` or `as_ptr` points at it, but a `Cell` of an object a pointer is the + /// place of reads a copy of, as its writes replace the value it read, and a slice writes + /// its element into. A slice of one byte no array holds is refused, as is any of an + /// object JS can't write a whole value into, an `UnsafeCell` of an object a pointer is + /// the place of, such as a `Vec`, and any of a pinned `Box`. fn one_of( &mut self, - cell: bool, + owner: &str, ty: Ty<'tcx>, op: &Operand<'tcx>, span: Span, @@ -1445,16 +1625,31 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { let place = op.place().filter(|p| p.projection.is_empty())?; let deref = tcx.mk_place_deref(place); // `array::from_mut` makes a `&mut [T; 1]`, which is a slice as a `&mut [T]` is. - let (of_place, of_object) = match cell { - true => ("cellOfPlace", "cellIn"), - false => ("sliceOfPlace", "sliceIn"), + let of_place = match owner { + "Cell" | "UnsafeCell" => "cellOfPlace", + _ => "sliceOfPlace", }; let of = |made: Expr| Expr::rs(of_place, vec![made]); + let place_of = self.b.t.pointee(ty) == crate::lower::pointer::Pointee::Place; + let of_object = |object: Expr| match owner { + "Cell" if place_of => Expr::rs("cellIn", vec![object]), + "Cell" | "UnsafeCell" => of(Expr::rs("partPlace", vec![object])), + _ => Expr::rs("sliceIn", vec![object]), + }; + let cell = owner != "raw" && owner != "array"; // A `&mut [T; N]` is the slice it views: a slice of it is the array slice of that one, and a // cell of an array of arrays reads a copy of the arrays it views and writes into them. 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); @@ -1472,20 +1667,27 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { "a slice of one byte's place, which a byte slice can view only in an array of bytes", )); } + // A whole write through what this makes lands in the object, so a value read out + // before would change with it unless copied, as a `Cell`'s or a slice's read is, but + // a pinned `Box`'s copy is another allocation. + if owner == "UnsafeCell" && place_of && self.b.t.write_in(ty).is_some() || self.b.t.boxed_object(ty) { + let path = if owner == "raw" { "slice" } else { owner }; + return Some(self.err( + span, + format!( + "`{path}::from_mut` of `{ty}`, 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" + ), + )); + } if self.in_array(deref) { let slice = self.place_expr(deref, span, out); - let mut made = vec![self.b.t.array_rs(ty, "View").call(vec![slice])]; - if cell { - made.extend(self.copy_depth(ty)); - } - return Some(Expr::rs(of_object, made)); + return Some(of_object(self.b.t.array_rs(ty, "View").call(vec![slice]))); } - // A cell of an object reads a copy wherever it is, as its place may be one a write - // lands in, such as an element of a slice of one. + // 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. if cell && self.b.t.write_in(ty).is_some() { - let mut made = vec![self.operand(op, span, out)]; - made.extend(self.copy_depth(ty)); - return Some(Expr::rs("cellIn", made)); + let object = self.operand(op, span, out); + return Some(of_object(object)); } if let Slot::Alias(Some(target)) = &self.slots[place.local] && assignable(target) @@ -1501,7 +1703,7 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { } if self.b.t.write_in(ty).is_some() { let object = self.operand(op, span, out); - return Some(Expr::rs(of_object, vec![object])); + return Some(of_object(object)); } Some(self.err( span, @@ -1818,12 +2020,12 @@ 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]; - made.extend(self.copy_depth(ty)); + made.extend(self.b.t.copy_depth(ty)); Expr::rs("replaceIn", made) } None => { let mut made = vec![place.0, value]; - made.extend(self.copy_depth(ty)); + made.extend(self.b.t.copy_depth(ty)); Expr::rs("replaceIn", made) } }; @@ -1842,7 +2044,7 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { let name = self.b.fresh(base); if let Some((slice, index)) = self.element_in(&place, ty) { let mut made = vec![slice, index, value]; - made.extend(self.copy_depth(ty)); + made.extend(self.b.t.copy_depth(ty)); let old = Expr::rs("sliceReplace", made); out.push(StmtKind::decl(false, name.clone(), None, Some(old)).at(None)); return Expr::ident(name); @@ -1897,21 +2099,6 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { Some(((**slice).clone(), (**index).clone())) } - /// How many levels of arrays of objects a write may land in `ty` nests, whose items a - /// copy of a view of one copies too, unlike references, which move as they are: the - /// runtime's `depth`, if any. - fn copy_depth(&self, ty: Ty<'tcx>) -> Option { - let mut depth = 0; - let mut at = ty; - while let ty::Array(elem, _) = at.kind() - && self.b.t.write_in(*elem).is_some() - { - depth += 1; - at = *elem; - } - (depth > 0).then(|| Expr::lit(depth.to_string())) - } - /// Set what a `&mut` borrows to `value`. fn set_borrowed(&mut self, (read, place): &Borrowed<'tcx>, value: Expr, span: Span, out: &mut Vec) { match place { diff --git a/ts/src/lower/mir/mod.rs b/ts/src/lower/mir/mod.rs index 87a9bf89c..de65c8e1d 100644 --- a/ts/src/lower/mir/mod.rs +++ b/ts/src/lower/mir/mod.rs @@ -443,8 +443,13 @@ pub struct Fx<'m, 'b, 'a, 'tcx> { idx_of: FxHashMap>, /// The halves a `|` joins into a `u64`, by the local of the shift that is its left side. halves: FxHashMap, &'m Operand<'tcx>)>, - /// Temporaries of those joins, whose assignments go unlowered. + /// Temporaries of those joins, and the pointers of `raw_cells`, whose assignments go + /// unlowered. joined: FxHashSet, + /// Pointers made of a reference to an `UnsafeCell` that only `UnsafeCell::raw_get` + /// reads, right after, by the place the reference points at, which it reads in their + /// place: the cell itself, where a raw pointer to it would be where it is kept. + raw_cells: FxHashMap>, /// The paths a switch lowered so far tests the variant of, with the enum it tests, /// which `tsc` narrows in its arms. An `Option`'s `Some` is the path itself, so it /// may be tested as both. @@ -545,6 +550,7 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { idx_of: FxHashMap::default(), halves: FxHashMap::default(), joined: FxHashSet::default(), + raw_cells: FxHashMap::default(), switched: FxHashSet::default(), tested: IndexVec::from_elem_n(false, n), widened: FxHashSet::default(), @@ -727,6 +733,7 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { self.find_stepped(); self.unborrow_passed(); self.find_halves(); + self.find_raw_cells(); self.find_slotted_calls(); self.find_scalars(); self.find_returning(); @@ -1477,6 +1484,57 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { } } + /// Find the pointers [`Self::raw_cells`] holds: `&raw const *r` of a reference `r`, + /// read once, as the argument of the `UnsafeCell::raw_get` its own block ends in, with + /// nothing but storage markers between. + fn find_raw_cells(&mut self) { + let mir: &'m mir::Body<'tcx> = self.mir; + let tcx = self.tcx; + for (bb, data) in mir.basic_blocks.iter_enumerated() { + let TerminatorKind::Call { func, args, .. } = &data.terminator().kind else { + continue; + }; + let ty::FnDef(def_id, _) = *func.ty(&mir.local_decls, tcx).kind() else { + continue; + }; + if !crate::lower::library::is_std(tcx, def_id) + || crate::lower::library::key(tcx, def_id) + .is_none_or(|(owner, name)| (owner.as_str(), name.as_str()) != ("UnsafeCell", "raw_get")) + { + continue; + } + let Some(Operand::Copy(p) | Operand::Move(p)) = args.first().map(|a| &a.node) else { + continue; + }; + let Some(local) = p.as_local().filter(|&l| self.defs[l] == 1 && self.uses[l] == 1) else { + continue; + }; + let Some((_, i)) = self.def_at[local].filter(|&(at, _)| at == bb) else { + continue; + }; + let Some(Rvalue::RawPtr(mir::RawPtrKind::Const | mir::RawPtrKind::Mut, cell)) = self.def_rvalue(local) + else { + continue; + }; + let behind_ref = match cell.projection.as_slice() { + [rest @ .., mir::ProjectionElem::Deref] => { + Place::ty_from(cell.local, rest, &mir.local_decls, tcx).ty.is_ref() + } + _ => false, + }; + let next = data.statements[i + 1..].iter().all(|s| { + matches!( + s.kind, + StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::Nop + ) + }); + if behind_ref && next { + self.raw_cells.insert(local, *cell); + self.joined.insert(local); + } + } + } + /// Mark the locals whose variant a switch or a library call's test tests, that a /// closure or async block captures and could test, or that std takes, whose runtime /// function infers its type parameters from them, and what references to them borrow. diff --git a/ts/src/lower/mir/origin.rs b/ts/src/lower/mir/origin.rs index 2b59e635c..839924a07 100644 --- a/ts/src/lower/mir/origin.rs +++ b/ts/src/lower/mir/origin.rs @@ -433,7 +433,9 @@ impl<'tcx> Fx<'_, '_, '_, 'tcx> { ("ptr" | "NonNull", "cast_const" | "cast_mut") | ("NonNull", "as_ptr" | "new_unchecked") => { self.arc_pointer(&args.first()?.node) } - ("UnsafeCell", "get") | ("Cell", "as_ptr") | ("MaybeUninit", "as_ptr" | "as_mut_ptr") => Some(false), + ("UnsafeCell", "get" | "raw_get") | ("Cell", "as_ptr") | ("MaybeUninit", "as_ptr" | "as_mut_ptr") => { + Some(false) + } _ => None, } } diff --git a/ts/src/lower/mir/place.rs b/ts/src/lower/mir/place.rs index 7818dca0b..8ba93d11e 100644 --- a/ts/src/lower/mir/place.rs +++ b/ts/src/lower/mir/place.rs @@ -856,6 +856,24 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> { out.push(self.store_in_slice(place, target, value, span)); return out; } + // A whole write through a raw pointer keeps the cells a value keeps, as `ptr::write` + // does, and is refused where it would not. + if let [ProjectionElem::Deref] = place.projection.as_slice() + && matches!(self.mir.local_decls[place.local].ty.kind(), ty::RawPtr(..)) + && let pointee = place.ty(&self.mir.local_decls, self.tcx).ty + { + if self.b.t.wraps_cells(pointee) { + let err = crate::lower::pointer::wrapped_write(self.b, pointee, span); + out.push(StmtKind::Expr(err).at(self.b.t.loc(span))); + return out; + } + if self.b.t.keeps_cells(pointee) { + let at = self.place_expr(place, span, &mut out); + let at = self.path(at, "kept", &mut out); + crate::lower::pointer::write_kept_at(self.b, at, value, pointee, span, &mut out); + return out; + } + } // `*r = v` replaces the object `r` points at in place, which other references and // captures share. An alias of a borrowed place assigns the place, and an `rs.Place` // its `v`. @@ -2431,25 +2449,26 @@ impl<'tcx> Fx<'_, '_, '_, 'tcx> { } /// Whether a raw pointer to a `ty` is, or is a slice of, the object JS keeps it in, or - /// with `cells`, is or holds an `rs.Cell`. Only an instance decides what a parameter is. + /// with `cells`, is or holds an `rs.Cell`, through any `MaybeUninit`s, which JS keeps as + /// what they hold. Only an instance decides what a parameter is. fn pointed_object(&self, ty: Ty<'tcx>, cells: bool) -> bool { let t = &self.b.t; !(t.polymorphic() && ty.has_param()) - && (t.pointee(ty) != crate::lower::pointer::Pointee::Place || cells && t.std_of(ty) == Some(Std::Cell)) + && (t.pointee(ty) != crate::lower::pointer::Pointee::Place + || cells && t.std_of(t.uninit_inner(ty)) == Some(Std::Cell)) } - /// Why the pointer std's `def_id` makes of what `reference` points at would not keep - /// pointing where Rust's does, if it would not, judged as [`Self::out_of_step`] judges a - /// raw pointer: `UnsafeCell::get`'s, holding a `T`, is the `rs.Cell` itself or the - /// object it holds. + /// Why the pointer std's `def_id` makes of `pointee`, what a reference points at, would + /// not keep pointing where Rust's does, if it would not, judged as [`Self::out_of_step`] + /// judges a raw pointer: `UnsafeCell::get`'s, holding a `T`, is the `rs.Cell` itself or + /// the object it holds. pub(super) fn made_out_of_step( &self, def_id: rustc_hir::def_id::DefId, gargs: ty::GenericArgsRef<'tcx>, - reference: &Operand<'tcx>, + pointee: Place<'tcx>, ) -> Option { let tcx = self.tcx; - let pointee = tcx.mk_place_deref(reference.place()?); let owner = library::key(tcx, def_id).map(|(owner, _)| owner); let cell = matches!(owner.as_deref(), Some("UnsafeCell" | "Cell")); let held = gargs.type_at(0); diff --git a/ts/src/lower/mod.rs b/ts/src/lower/mod.rs index 7777c21e3..0a4cfac16 100644 --- a/ts/src/lower/mod.rs +++ b/ts/src/lower/mod.rs @@ -1427,6 +1427,22 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { erased } + /// Whether `ty` is a `Box` of an object a whole write lands in, through any `Pin`s and + /// `AssertUnwindSafe`s, as a pinned `Box` is: a copy of the value there is another + /// allocation. + pub fn boxed_object(&self, ty: Ty<'tcx>) -> bool { + use library::Std; + let mut at = ty; + while let ty::Adt(adt, args) = at.kind() { + match Std::of(self.tcx, adt.did()) { + Some(Std::Box) => return self.write_in(ty).is_some(), + Some(Std::Pin | Std::AssertUnwindSafe) => at = args.type_at(0), + _ => break, + } + } + false + } + /// The kind of a `pointee`'s object, through the `Pin`s, `Box`es, and `AssertUnwindSafe`s /// JS erases, where a whole value of it can be written into the object in place: one only /// its owner holds, unlike an `Arc`'s or a `LocalKey`'s, which its copies share, and whose @@ -1459,6 +1475,21 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { } } + /// How many levels of arrays of objects a write may land in `ty` nests, whose items a + /// copy of a view of one copies too, unlike references, which move as they are: the + /// runtime's `depth`, if any. + pub fn copy_depth(&self, ty: Ty<'tcx>) -> Option { + let mut depth = 0; + let mut at = ty; + while let ty::Array(elem, _) = at.kind() + && self.write_in(*elem).is_some() + { + depth += 1; + at = *elem; + } + (depth > 0).then(|| ts::Expr::lit(depth.to_string())) + } + /// What `ty` points at, if it is a `&mut` that is an `rs.Place`. pub fn place_pointee(&self, ty: Ty<'tcx>) -> Option> { match ty.kind() { diff --git a/ts/src/lower/pointer.rs b/ts/src/lower/pointer.rs index d4538b033..4c3fc6dbd 100644 --- a/ts/src/lower/pointer.rs +++ b/ts/src/lower/pointer.rs @@ -38,6 +38,14 @@ use super::library::{Call, Std, targ}; use super::{AdtRepr, ObjectKind, Translator}; use crate::ts::{Expr, Key, Stmt, StmtKind, Type}; +/// What a type that [keeps cells](Translator::keeps_cells) holds. +pub enum KeptCells<'tcx> { + /// A cell's value. + Cell(Ty<'tcx>), + /// Each field's type, and whether it keeps cells. + Fields(Vec<(Ty<'tcx>, bool)>), +} + /// What a raw pointer to a type is in JS. #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum Pointee { @@ -156,6 +164,54 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { ty } + /// Whether a whole write of a `ty` through the pointer helpers below keeps each + /// `rs.Cell` it holds, writing into it in place, so a pointer `get` gave into one before + /// sees the write: a cell, or a tuple or a crate's struct a pointer is the object of, a + /// field of which keeps cells. Any other part is given the new value's, one object deep. + pub fn keeps_cells(&self, ty: Ty<'tcx>) -> bool { + self.kept_cells(ty).is_some() + } + + /// What a `ty` that [keeps cells](Self::keeps_cells) holds: a cell's value, or each + /// field of a tuple or struct, and whether it keeps cells too. + pub fn kept_cells(&self, ty: Ty<'tcx>) -> Option> { + let (fields, cell) = self.kept_parts(ty)?; + if cell { + return Some(KeptCells::Cell(fields[0])); + } + let fields: Vec<_> = fields.into_iter().map(|f| (f, self.keeps_cells(f))).collect(); + (self.pointee(ty) == Pointee::Object && fields.iter().any(|&(_, kept)| kept)) + .then_some(KeptCells::Fields(fields)) + } + + /// What a write keeping cells reaches in `ty`, and whether `ty` is a cell: a cell's + /// value, or each field of a tuple or a crate's struct. + fn kept_parts(&self, ty: Ty<'tcx>) -> Option<(Vec>, bool)> { + match ty.kind() { + ty::Adt(adt, args) if Std::of(self.tcx, adt.did()) == Some(Std::Cell) => { + Some((vec![args.type_at(0)], true)) + } + ty::Tuple(tys) => Some((tys.to_vec(), false)), + ty::Adt(adt, args) if adt.is_struct() && Std::of(self.tcx, adt.did()).is_none() && self.own(adt.did()) => { + Some((adt.all_fields().map(|f| self.field_ty(f.did, args)).collect(), false)) + } + _ => None, + } + } + + /// Whether a whole write of a `ty` would put other cells in place of those a + /// `MaybeUninit` or `ManuallyDrop` in it holds, which a write keeps nowhere, so a pointer + /// `get` gave into one would not see it: one of them holding a value that + /// [keeps cells](Self::keeps_cells), or a part such a write reaches holding one. + pub fn wraps_cells(&self, ty: Ty<'tcx>) -> bool { + let inner = self.uninit_inner(ty); + if inner != ty { + return self.keeps_cells(inner) || self.wraps_cells(inner); + } + self.kept_parts(ty) + .is_some_and(|(parts, _)| parts.into_iter().any(|part| self.wraps_cells(part))) + } + /// Whether only an instance decides what a pointer or reference to `ty` is, as in a /// generic type's definition: `ty` a type parameter, an array of one, either through /// `MaybeUninit`s, or a binding's generic type, which an instance decides is `Copy`. @@ -242,13 +298,20 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { } let ty = self.uninit_inner(ty); match (self.pointee(ty), ty.kind()) { + // A cell, so a pointer `raw_get` makes into it before a write sees the write, + // which lands in it. + (_, ty::Adt(adt, args)) if Std::of(self.tcx, adt.did()) == Some(Std::Cell) => Expr::New( + Box::new(Expr::Rs("Cell".into())), + vec![self.shell(args.type_at(0), span)], + ), (Pointee::Object, ty::Tuple(tys)) => Expr::Array(tys.iter().map(|t| self.shell(t, span)).collect()), (Pointee::Array, ty::Array(elem, len)) => { let len = Expr::lit(len.try_to_target_usize(self.tcx).unwrap_or(0).to_string()); + let cell = matches!(elem.kind(), ty::Adt(adt, _) if Std::of(self.tcx, adt.did()) == Some(Std::Cell)); match (super::byte(*elem), self.pointee(*elem)) { (true, _) => Expr::New(Box::new(Expr::ident("Uint8Array")), vec![len]), - (_, Pointee::Place) => Expr::New(Box::new(Expr::ident("Array")), vec![len]), - (_, Pointee::Object | Pointee::Array | Pointee::Slice) => { + (_, Pointee::Place) if !cell => Expr::New(Box::new(Expr::ident("Array")), vec![len]), + (_, Pointee::Place | Pointee::Object | Pointee::Array | Pointee::Slice) => { let elem_ty = self.ty(*elem, span); let each = Expr::Arrow( Vec::new(), @@ -346,7 +409,10 @@ pub fn derives(tcx: ty::TyCtxt<'_>, def_id: rustc_hir::def_id::DefId) -> Option< | ("NonNull", "dangling" | "add" | "sub" | "offset" | "write") | ("MaybeUninit", "new" | "uninit" | "assume_init") | ("ManuallyDrop", "new" | "into_inner") - | ("UnsafeCell", "new" | "get" | "raw_get" | "get_mut" | "into_inner") + | ( + "UnsafeCell", + "new" | "get" | "raw_get" | "get_mut" | "as_ref_unchecked" | "as_mut_unchecked" | "into_inner", + ) | ("Cell", "as_ptr" | "get_mut") | ("Box", "new") => Some(Derives::Other), ("ptr", "read" | "read_unaligned" | "read_volatile") @@ -382,12 +448,15 @@ pub fn allocates(tcx: ty::TyCtxt<'_>, def_id: rustc_hir::def_id::DefId) -> bool /// Which of std's `def_id`'s arguments are `&mut`s whose lowering may give what they /// borrow another value, rather than writing into it, where one is an alias of a borrowed /// place: the place is assigned again, as `mem::replace`, `clone_from`, and `clone_into` -/// assign it, and a whole write of what `slice::from_mut`, `array::from_mut`, or -/// `Cell::from_mut` makes does. `mem::replace`'s value is no such one. +/// assign it, and a whole write of what `slice::from_mut`, `array::from_mut`, +/// `Cell::from_mut`, or `UnsafeCell::from_mut` makes does. `mem::replace`'s value is no +/// such one. pub fn rebinds(tcx: ty::TyCtxt<'_>, def_id: rustc_hir::def_id::DefId) -> &'static [usize] { match super::library::key(tcx, def_id) { Some((owner, name)) => match (owner.as_str(), name.as_str()) { - ("mem", "replace" | "take") | ("Clone", "clone_from") | ("raw" | "array" | "Cell", "from_mut") => &[0], + ("mem", "replace" | "take") + | ("Clone", "clone_from") + | ("raw" | "array" | "Cell" | "UnsafeCell", "from_mut") => &[0], ("ToOwned", "clone_into") => &[1], ("mem", "swap") => &[0, 1], _ => &[], @@ -406,6 +475,7 @@ pub fn lends(tcx: ty::TyCtxt<'_>, def_id: rustc_hir::def_id::DefId) -> bool { ("MaybeUninit", "as_mut_ptr" | "write" | "assume_init_mut" | "assume_init_drop") | ("ManuallyDrop", "drop" | "take") | ("UnsafeCell" | "Cell", "get_mut") + | ("UnsafeCell", "as_mut_unchecked") | ("NonNull" | "ptr", "as_mut") | ("Box", "leak") ) @@ -433,8 +503,10 @@ pub fn keeps<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: rustc_hir::def_id::DefId, args | "cast_mut" | "eq" | "read" | "read_unaligned" | "read_volatile" | "drop_in_place" ) | ("Box", "into_raw" | "leak" | "from_raw") | ("ManuallyDrop", "new" | "into_inner" | "drop" | "take") - | ("UnsafeCell", "new" | "get" | "get_mut" | "into_inner") - | ("Cell", "as_ptr" | "get_mut") + | ( + "UnsafeCell", + "new" | "get" | "raw_get" | "get_mut" | "as_ref_unchecked" | "as_mut_unchecked" | "into_inner" + ) | ("Cell", "as_ptr" | "get_mut") ) || owner == "Atomic" && super::library::is_std(tcx, def_id) ); keeps || from_reference(tcx, def_id, args) @@ -534,7 +606,7 @@ pub fn call<'tcx>( ("ptr", "null" | "null_mut") => Expr::Rs("NULL".into()), // A pointer to `()` is an identity, which the `rs.Place` of a place or a reference // is not. A box of one holds nothing, so its pointer is dangling. - ("MaybeUninit", "as_ptr" | "as_mut_ptr") | ("UnsafeCell", "get") | ("Cell", "as_ptr") + ("MaybeUninit", "as_ptr" | "as_mut_ptr") | ("UnsafeCell", "get" | "raw_get") | ("Cell", "as_ptr") if b.t.identity_pointee(pointee()) => { b.err( @@ -593,6 +665,24 @@ pub fn call<'tcx>( deref(pointee(), arg(), name == "as_ref") } ("NonNull", "as_mut") if array(b, pointee()) => to_reference(b, 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") + if b.t.needs_place( + b.t.tcx + .type_of(b.t.tcx.parent(call.def_id)) + .instantiate(b.t.tcx, gargs) + .skip_norm_wip(), + ) && !b.t.needs_place(pointee()) => + { + let ty = pointee(); + b.err( + span, + format!( + "`MaybeUninit::assume_init_mut` of `{ty}`, whose mutable reference is the object, but the uninitialized value's is the place it is kept in" + ), + ) + } // The same pointer, as another type of the same pointee. ("ptr", "cast_const" | "cast_mut") | ("NonNull", "as_ptr" | "new_unchecked" | "cast_const" | "cast_mut") @@ -738,11 +828,11 @@ pub fn call<'tcx>( }, ("ptr", "read" | "read_unaligned" | "read_volatile") => { let p = arg(); - read(b, p, pointee(), span) + read(b, p, pointee(), span, out) } ("ptr", "write" | "write_unaligned" | "write_volatile") => { let (p, value) = (arg(), arg()); - write(b, p, value, pointee(), span) + write(b, p, value, pointee(), span, out) } // A place of no bytes has nothing to read or write, and every value of its type is // the one it holds. @@ -752,22 +842,12 @@ pub fn call<'tcx>( } ("ptr", "swap") if b.t.zero_sized(pointee()) => Expr::undefined(), ("ptr", "replace") => { - let p = b.spill(arg(), "pointer", out); - let value = arg(); - let old = read(b, p.clone(), pointee(), span); - let old = b.spill(old, "old", out); - let write = write(b, p, value, pointee(), span); - out.push(StmtKind::Expr(write).at(None)); - old + let (p, value) = (arg(), arg()); + replace(b, p, value, pointee(), span, out) } ("ptr", "swap") => { - let (x, y) = (b.spill(arg(), "x", out), b.spill(arg(), "y", out)); - let old = read(b, x.clone(), pointee(), span); - let old = b.spill(old, "old", out); - let from_y = read(b, y.clone(), pointee(), span); - let into_x = write(b, x, from_y, pointee(), span); - out.push(StmtKind::Expr(into_x).at(None)); - write(b, y, old, pointee(), span) + let (x, y) = (arg(), arg()); + swap(b, x, y, pointee(), span, out) } ("ptr", "drop_in_place") => { let p = arg(); @@ -815,7 +895,7 @@ pub fn call<'tcx>( let value = arg(); let write = match array(b, pointee()) { true => Expr::rs("ptrWrite", vec![p.clone(), value]), - false => write(b, p.clone(), value, pointee(), span), + false => write(b, p.clone(), value, pointee(), span, out), }; out.push(StmtKind::Expr(write).at(None)); p @@ -831,7 +911,7 @@ pub fn call<'tcx>( let p = b.spill(boxed, "uninit", out); let write = match array(b, pointee()) { true => Expr::rs("ptrWrite", vec![p.clone(), value]), - false => write(b, p.clone(), value, pointee(), span), + false => write(b, p.clone(), value, pointee(), span, out), }; out.push(StmtKind::Expr(write).at(None)); p @@ -839,6 +919,7 @@ pub fn call<'tcx>( } } // A shared reference to a value JS copies is the value. + ("MaybeUninit", "assume_init_read") if b.t.keeps_cells(pointee()) => copy_kept(b, arg(), pointee(), span, out), ("MaybeUninit", "assume_init_read") => b.t.snapshot(arg(), pointee(), span), ("MaybeUninit", "assume_init_drop") | ("ManuallyDrop", "drop") => { let p = arg(); @@ -855,15 +936,61 @@ pub fn call<'tcx>( Some(Pointee::Place) => p.member("v"), _ => p, }; - b.t.snapshot(value, pointee(), span) + match b.t.keeps_cells(pointee()) { + true => copy_kept(b, value, pointee(), span, out), + false => b.t.snapshot(value, pointee(), span), + } } // An `rs.Cell`, a `Cell`'s too, which is the place a pointer to a value JS copies is, // and holds the object a pointer to any other is. ("UnsafeCell", "new") => Expr::New(Box::new(Expr::Rs("Cell".into())), vec![arg()]), - ("UnsafeCell", "get") | ("Cell", "as_ptr") if kind(b, pointee()) == Some(Pointee::Place) => arg(), - ("UnsafeCell", "get") | ("Cell", "as_ptr") if array(b, pointee()) => to_pointer(b, arg().member("v")), - ("UnsafeCell" | "Cell", "get_mut") if b.t.needs_place(pointee()) => arg(), - ("UnsafeCell", "get" | "get_mut" | "into_inner") | ("Cell", "as_ptr" | "get_mut") => arg().member("v"), + ("UnsafeCell", "get") | ("Cell", "as_ptr") => { + let cell = arg(); + cell_pointer(b, cell, pointee()) + } + // `get` of the cell the pointer points at: the cell itself where a pointer to one is + // the object, or else the cell in the `rs.Place` of where it is kept. Only a pointer + // made of a known place gets here, so the cell is there. + ("UnsafeCell", "raw_get") => { + let tcx = b.t.tcx; + let cell = tcx + .type_of(tcx.parent(call.def_id)) + .instantiate(tcx, gargs) + .skip_norm_wip(); + let p = arg(); + let cell = match b.t.pointee(cell) { + Pointee::Object => p, + _ => p.member("v"), + }; + cell_pointer(b, cell, pointee()) + } + // `ptr::replace` of the pointer `get` gives. + ("UnsafeCell", "replace") if b.t.zero_sized(pointee()) => { + let _ = arg(); + arg() + } + ("UnsafeCell", "replace") => { + let cell = arg(); + let p = cell_pointer(b, cell, pointee()); + let value = arg(); + replace(b, p, value, pointee(), span, out) + } + // A whole write through the `&mut` lands in the allocation, which a value read out + // before could keep only as a copy, another allocation. + ("UnsafeCell" | "Cell", "get_mut") | ("UnsafeCell", "as_mut_unchecked") if b.t.boxed_object(pointee()) => { + let ty = pointee(); + b.err( + span, + format!( + "`{owner}::{name}` of `{ty}`, an object a whole write through the reference changes in place, so a value read out before would be a copy at another address" + ), + ) + } + // 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(), + ("UnsafeCell", "get_mut" | "as_ref_unchecked" | "as_mut_unchecked" | "into_inner") | ("Cell", "get_mut") => { + arg().member("v") + } // Into the UTF-8 of a `str`, which JS keeps as text: an encoding no write may reach. ("str", "as_ptr") => Expr::rs("strAsPtr", vec![arg()]), // Pointers into an array: `rs.AtIndex`es, which a `Vec`'s and a slice's give. @@ -1168,8 +1295,30 @@ pub fn raw_pointee<'tcx>(tcx: ty::TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option } } +/// The pointer an `rs.Cell` holding a `ty` gives to it, as `UnsafeCell::get` and +/// `Cell::as_ptr` do: the cell, the place of a value JS copies, or else the object, array, +/// or slice it holds. +pub(super) fn cell_pointer<'tcx>(b: &Body<'_, '_, 'tcx>, cell: Expr, ty: Ty<'tcx>) -> Expr { + let pointee = b.t.pointee(ty); + if pointee == Pointee::Place { + return cell; + } + let held = cell.member("v"); + match (pointee, b.t.uninit_inner(ty).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]), + (Pointee::Slice, _) => Expr::rs("rawSliceOf", vec![held]), + _ => held, + } +} + /// The value `p`, a pointer to `ty`, points at, as a value of its own. -fn read<'tcx>(b: &mut Body<'_, '_, 'tcx>, p: Expr, ty: Ty<'tcx>, span: Span) -> Expr { +pub(super) fn read<'tcx>(b: &mut Body<'_, '_, 'tcx>, p: Expr, ty: Ty<'tcx>, span: Span, out: &mut Vec) -> Expr { + if b.t.keeps_cells(ty) { + let at = pointed(b, p, ty); + return copy_kept(b, at, ty, span, out); + } let value = match b.t.pointee(ty) { Pointee::Place => p.member("v"), Pointee::Object => p, @@ -1182,11 +1331,85 @@ fn read<'tcx>(b: &mut Body<'_, '_, 'tcx>, p: Expr, ty: Ty<'tcx>, span: Span) -> b.t.snapshot(value, ty, span) } +/// `ptr::replace` of `p`, a pointer to `ty`, with `value`: what it held, as a value of its +/// own. +pub(super) fn replace<'tcx>( + b: &mut Body<'_, '_, 'tcx>, + p: Expr, + value: Expr, + ty: Ty<'tcx>, + span: Span, + out: &mut Vec, +) -> Expr { + let p = b.spill(p, "pointer", out); + let old = copied_out(b, p.clone(), ty, span, out); + let old = b.spill(old, "old", out); + let write = write(b, p, value, ty, span, out); + out.push(StmtKind::Expr(write).at(None)); + old +} + +/// 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 +/// 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)) => + { + 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()) + } + _ => read(b, p, ty, span, out), + } +} + +/// `ptr::swap` of `x` and `y`, pointers to `ty`. +pub(super) fn swap<'tcx>( + b: &mut Body<'_, '_, 'tcx>, + x: Expr, + y: Expr, + ty: Ty<'tcx>, + span: Span, + out: &mut Vec, +) -> Expr { + let (x, y) = (b.spill(x, "x", out), b.spill(y, "y", out)); + let old = copied_out(b, x.clone(), ty, span, out); + let old = b.spill(old, "old", out); + let from_y = copied_out(b, y.clone(), ty, span, out); + let into_x = write(b, x, from_y, ty, span, out); + out.push(StmtKind::Expr(into_x).at(None)); + write(b, y, old, ty, span, out) +} + /// The write of `value`, a `ty`, where `p` points. -fn write<'tcx>(b: &mut Body<'_, '_, 'tcx>, p: Expr, value: Expr, ty: Ty<'tcx>, span: Span) -> Expr { +pub(super) fn write<'tcx>( + b: &mut Body<'_, '_, 'tcx>, + p: Expr, + value: Expr, + ty: Ty<'tcx>, + span: Span, + out: &mut Vec, +) -> Expr { if b.t.zero_sized(ty) { return Expr::undefined(); } + if b.t.wraps_cells(ty) { + return wrapped_write(b, ty, span); + } + if b.t.keeps_cells(ty) { + let at = match b.t.pointee(ty) { + Pointee::Object => p, + _ => b.spill(p, "pointer", out).member("v"), + }; + write_kept_at(b, at, value, ty, span, out); + return Expr::undefined(); + } match b.t.pointee(ty) { Pointee::Place => p.member("v").assign(value), Pointee::Object => Expr::rs("ptrWrite", vec![p, value]), @@ -1195,6 +1418,149 @@ fn write<'tcx>(b: &mut Body<'_, '_, 'tcx>, p: Expr, value: Expr, ty: Ty<'tcx>, s } } +/// The refusal of a whole write of a `ty` that [wraps cells](Translator::wraps_cells). +pub(super) fn wrapped_write<'tcx>(b: &mut Body<'_, '_, 'tcx>, ty: Ty<'tcx>, span: Span) -> Expr { + b.err( + span, + format!( + "a whole write of `{ty}`, which would put another cell in place of one a `MaybeUninit` or `ManuallyDrop` holds" + ), + ) +} + +/// The JS value of the `ty` that `p` points at: a cell's `rs.Cell`, which a pointer to +/// it is the place of, or the object a pointer to it is. +fn pointed<'tcx>(b: &Body<'_, '_, 'tcx>, p: Expr, ty: Ty<'tcx>) -> Expr { + match b.t.pointee(ty) { + Pointee::Place => p.member("v"), + _ => p, + } +} + +/// The write of `value`, a `ty` that keeps cells, where `at` names its JS value: into the +/// cells there in place, or whole where memory not written yet, as `ptr::write` may fill, +/// holds no cell to keep. `at` is read more than once. +pub(super) fn write_kept_at<'tcx>( + b: &mut Body<'_, '_, 'tcx>, + at: Expr, + value: Expr, + ty: Ty<'tcx>, + span: Span, + out: &mut Vec, +) { + if b.t.pointee(ty) == Pointee::Object { + return write_kept(b, at, value, ty, span, out); + } + let value = b.spill(value, "value", out); + let mut kept = Vec::new(); + write_kept(b, at.clone(), value.clone(), ty, span, &mut kept); + let whole = StmtKind::Expr(at.clone().assign(value)).at(None); + let cond = at.binary("===", Expr::undefined()); + out.push( + StmtKind::If { + cond, + then: vec![whole], + els: kept, + } + .at(None), + ); +} + +/// The write of `value` into `at`, the JS value of a `ty` that keeps cells, in place: a +/// cell's value written into the cell, as a write through its `get` would be, and a +/// tuple's or struct's other fields given `value`'s, as is a cell field of one not +/// written yet. +fn write_kept<'tcx>(b: &mut Body<'_, '_, 'tcx>, at: Expr, value: Expr, ty: Ty<'tcx>, span: Span, out: &mut Vec) { + match b.t.kept_cells(ty) { + Some(KeptCells::Cell(held)) if b.t.keeps_cells(held) => { + write_kept(b, at.member("v"), value.member("v"), held, span, out) + } + Some(KeptCells::Cell(held)) => { + let p = cell_pointer(b, at, held); + let write = write(b, p, value.member("v"), held, span, out); + out.push(StmtKind::Expr(write).at(None)); + } + Some(KeptCells::Fields(fields)) => { + let (at, value) = (b.spill(at, "object", out), b.spill(value, "value", out)); + let kept: Vec<_> = (fields.iter().enumerate()) + .filter(|(_, (_, kept))| *kept) + .map(|(i, &(field, _))| { + let part = object_field(b, at.clone(), ty, i, span); + (i, field, b.spill(part, "cell", out)) + }) + .collect(); + out.push(StmtKind::Expr(Expr::rs("ptrWrite", vec![at.clone(), value.clone()])).at(None)); + for (i, field, cell) in kept { + let part = object_field(b, at.clone(), ty, i, span); + let mut then = vec![StmtKind::Expr(part.assign(cell.clone())).at(None)]; + let from = object_field(b, value.clone(), ty, i, span); + write_kept(b, cell.clone(), from, field, span, &mut then); + let cond = cell.binary("!==", Expr::undefined()); + out.push( + StmtKind::If { + cond, + then, + els: Vec::new(), + } + .at(None), + ); + } + } + None => unreachable!("`{ty}` keeps no cells"), + } +} + +/// A copy of `at`, the JS value of a `ty` that keeps cells, with a cell of its own for +/// each it keeps, so a write into those in place leaves the copy be, and each other part +/// copied as a read copies it. +fn copy_kept<'tcx>(b: &mut Body<'_, '_, 'tcx>, at: Expr, ty: Ty<'tcx>, span: Span, out: &mut Vec) -> Expr { + match b.t.kept_cells(ty) { + Some(KeptCells::Cell(held)) => { + let value = match (b.t.keeps_cells(held), b.t.pointee(held)) { + (true, _) => copy_kept(b, at.member("v"), held, span, out), + (false, Pointee::Object) if let Some(copy) = b.t.snapshot_fn(held, span) => { + copy.call(vec![at.member("v")]) + } + (false, _) => { + let p = cell_pointer(b, at, held); + copied_out(b, p, held, span, out) + } + }; + Expr::New(Box::new(Expr::Rs("Cell".into())), vec![value]) + } + Some(KeptCells::Fields(fields)) => { + let at = b.spill(at, "object", out); + let copy = b.spill(Expr::rs("objectCopy", vec![at.clone()]), "copy", out); + for (i, &(field, kept)) in fields.iter().enumerate() { + let from = object_field(b, at.clone(), ty, i, span); + let value = match kept { + true => copy_kept(b, from, field, span, out), + false => match b.t.snapshot_fn(field, span) { + Some(copy) => copy.call(vec![from]), + None => continue, + }, + }; + let part = object_field(b, copy.clone(), ty, i, span); + out.push(StmtKind::Expr(part.assign(value)).at(None)); + } + copy + } + None => unreachable!("`{ty}` keeps no cells"), + } +} + +/// Field `i` of `object`, the JS object of a tuple or a crate's struct `ty`. +fn object_field<'tcx>(b: &mut Body<'_, '_, 'tcx>, object: Expr, ty: Ty<'tcx>, i: usize, span: Span) -> Expr { + match ty.kind() { + ty::Tuple(_) => object.index(Expr::lit(i.to_string())), + ty::Adt(adt, _) => match b.t.adt(*adt, span).repr { + AdtRepr::Struct { fields, .. } => Translator::read_field(object, fields[i]), + _ => unreachable!("`{ty}` is a struct"), + }, + _ => unreachable!("`{ty}` is a tuple or a struct"), + } +} + /// Whether `ty` is `[u8]`, one of `MaybeUninit`, or an `UninitSlice`, whose slices are /// `rs.ByteSlice`s. pub fn slice_of_bytes(ty: Ty<'_>) -> bool { diff --git a/ts/src/lower/task.rs b/ts/src/lower/task.rs index e46390a12..8b6197e5c 100644 --- a/ts/src/lower/task.rs +++ b/ts/src/lower/task.rs @@ -589,26 +589,80 @@ fn cell<'tcx>( args: Vec, out: &mut Vec, ) -> Result, Vec> { + use super::pointer::{self, Pointee}; let tcx = b.t.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; + 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) + }; let e = match name { + "set" | "replace" | "take" | "update" | "swap" if b.t.wraps_cells(ty) => pointer::wrapped_write(b, ty, span), "new" => Expr::New(Box::new(Expr::Rs("Cell".into())), args), - "get" => b.t.copied(first(args).member("v"), ty, call.span), + "get" => b.t.copied(first(args).member("v"), ty, span), "into_inner" => first(args).member("v"), // As its `UnsafeCell`'s `get` and `get_mut`, the same `rs.Cell`. "as_ptr" | "get_mut" => return Err(args), + // With what drops the value it replaces. + "set" if in_place => { + let [cell, value] = two(args); + let p = pointer::cell_pointer(b, cell, ty); + match b.t.drops(ty) { + true => { + let old = pointer::replace(b, p, value, ty, span, out); + b.t.drop_value(old, ty, span).unwrap_or_else(Expr::undefined) + } + false => pointer::write(b, p, value, ty, span, out), + } + } + "replace" | "take" if in_place => { + let [cell, value] = two(args); + // Made before the value it replaces is read, as `Default` may write the cell. + let value = match name { + "take" => { + let value = default(b, out); + b.spill(value, "value", out) + } + _ => value, + }; + let p = pointer::cell_pointer(b, cell, ty); + pointer::replace(b, p, value, ty, span, out) + } + "update" if in_place => { + let [cell, f] = two(args); + let p = b.spill(pointer::cell_pointer(b, cell, ty), "pointer", out); + let new = f.call(vec![pointer::read(b, p.clone(), ty, span, out)]); + pointer::write(b, p, new, ty, span, out) + } + // Rust panics on cells that partially overlap, which only arrays' can. + "swap" if b.t.pointee(ty) == Pointee::Array => b.err( + span, + format!("`Cell::swap` of `{ty}`, an array, whose cells may partially overlap, which Rust panics on"), + ), + "swap" => { + let [x, y] = two(args); + let (x, y) = (pointer::cell_pointer(b, x, ty), pointer::cell_pointer(b, y, ty)); + pointer::swap(b, x, y, ty, span, out) + } "replace" => Expr::rs("cellReplace", args), "update" => Expr::rs("cellUpdate", args), // With what drops the value it replaces. "set" => { - let Some(droppers) = b.t.droppers([ty], call.span) else { + let Some(droppers) = b.t.droppers([ty], span) else { return Ok(Some(Expr::undefined())); }; Expr::rs("cellSet", args.into_iter().chain(droppers).collect()) } "take" => { - let f = super::collections::trait_fn(tcx, "Default", "default"); - let value = b.call_def(f, tcx.mk_args(&[ty.into()]), Vec::new(), call.span, out); + let value = default(b, out); Expr::rs("cellReplace", vec![first(args), value]) } _ => return Ok(None),