From e77dc6c60f17a48e20d67e39e450b301d34b57f5 Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Sun, 1 Nov 2026 08:14:51 -0800 Subject: [PATCH] chore(quest): plan the 2026-11-01 follow-ups Co-Authored-By: Claude Opus 5.5 --- quest/m3/README.md | 5 +++++ quest/m3/ts-empty-places.md | 15 +++++++++++++++ quest/m3/ts-guard-leftovers.md | 24 ++++++++++++++++++++++++ quest/m3/ts-lazy-writes.md | 19 +++++++++++++++++++ quest/m3/ts-option-slot.md | 17 +++++++++++++++++ quest/m3/ts-span-precision.md | 20 ++++++++++++++++++++ 6 files changed, 100 insertions(+) create mode 100644 quest/m3/ts-empty-places.md create mode 100644 quest/m3/ts-guard-leftovers.md create mode 100644 quest/m3/ts-lazy-writes.md create mode 100644 quest/m3/ts-option-slot.md create mode 100644 quest/m3/ts-span-precision.md diff --git a/quest/m3/README.md b/quest/m3/README.md index 2f5429677..05b305a08 100644 --- a/quest/m3/README.md +++ b/quest/m3/README.md @@ -35,3 +35,8 @@ generic std gap is planned here even when moq never calls it. - [The rest of a guard's methods](/quest/m3/ts-guard-rest.md) - `Debug` of `RefCell` and `RwLock` guards, `MutexGuard::map`, and the guards' `try_map` translate - [Aborts in the differential](/quest/m3/ts-abort-differential.md) - the lang differential compares wasm32's aborts, so an `RwLock` locked again while held is tested - [A reversed zip's per-pair cost](/quest/m3/ts-zip-rev-overhead.md) - a reversed by-index zip costs per pair what a forward one does, or the gap is explained +- [Whole writes into a lazy cell or thread-local key](/quest/m3/ts-lazy-writes.md) - a whole write through a `&mut` to a `LazyCell`, `LazyLock`, or `LocalKey` keeps its state +- [A guard's downgrade, leak, and whole byte-array map](/quest/m3/ts-guard-leftovers.md) - `downgrade`, `Ref::leak`, `RefMut::leak`, and a guard's map over a whole `[u8; N]` translate +- [Type errors at the Rust that made them](/quest/m3/ts-span-precision.md) - a `tsc` error on output names the tail expression or call argument that made it +- [An empty iterator of mutable references](/quest/m3/ts-empty-places.md) - `iter::empty::<&mut T>()` given to `zip` or `chain` translates +- [An Option of numbers in the result slot](/quest/m3/ts-option-slot.md) - `varint_opt`'s `Option` comes back through the slot with no object per call diff --git a/quest/m3/ts-empty-places.md b/quest/m3/ts-empty-places.md new file mode 100644 index 000000000..75b112948 --- /dev/null +++ b/quest/m3/ts-empty-places.md @@ -0,0 +1,15 @@ +# [XS] An empty iterator of mutable references + +## Goal + +[rust2-ts](/ts/README.md) translates `std::iter::empty::<&mut T>()` for a `T` JS copies, +as given to `zip` or `chain`, proven by a differential test against native Rust. + +## Plan + +Found by [#391](https://github.com/moq-dev/rust2/pull/391): the check that lets an +adaptor's argument lend places refuses `iter::empty`, though it yields nothing to write +through. Accept it in that check, so an empty iterator is a place source like a +`&mut` collection. + +Public API: the translator's output. diff --git a/quest/m3/ts-guard-leftovers.md b/quest/m3/ts-guard-leftovers.md new file mode 100644 index 000000000..f86842bb1 --- /dev/null +++ b/quest/m3/ts-guard-leftovers.md @@ -0,0 +1,24 @@ +# [S] A guard's downgrade, leak, and whole byte-array map + +## Goal + +[rust2-ts](/ts/README.md) translates `RwLockWriteGuard::downgrade`, `Ref::leak` and +`RefMut::leak`, and a guard's `map(|p| p)` that lends a whole `[u8; N]`, each holding or +releasing its lock or borrow as std's does, proven by differential tests against native Rust. + +## Plan + +Found by [#392](https://github.com/moq-dev/rust2/pull/392), which translated the rest of a +guard's maps and `Debug`: + +- `RwLockWriteGuard::map(guard, |p| p)` over a whole `[u8; N]` is refused with "a reference + to an array of bytes it is generic over". The refusal predates #392; check whether + `RefMut::map` over a whole byte array fails the same way, and fix both. +- `downgrade` (stable since 1.92) turns the write lock into a read lock without releasing + it, so a `try_write` between fails and a `try_read` succeeds. +- `leak` keeps the cell borrowed for the rest of the program, so a later `borrow_mut` + panics with wasm32's message. + +Reproduce each refusal first; any that already translate drop from this quest. + +Public API: the translator's output. diff --git a/quest/m3/ts-lazy-writes.md b/quest/m3/ts-lazy-writes.md new file mode 100644 index 000000000..d431b6860 --- /dev/null +++ b/quest/m3/ts-lazy-writes.md @@ -0,0 +1,19 @@ +# [S] Whole writes into a lazy cell or thread-local key + +## Goal + +[rust2-ts](/ts/README.md) translates a whole write through a `&mut` to a `LazyCell`, a +`LazyLock`, or a `LocalKey`, as `*r = LazyCell::new(f)` or `mem::swap` of two, keeping +whether each is initialized and what it holds, proven by differential tests against native +Rust that read each after the write. + +## Plan + +Found by [#386](https://github.com/moq-dev/rust2/pull/386), which refuses these writes with +a span in `Translator::write_in`: their runtime classes keep their state in `#private` +fields, which the field copy a whole write lowers to misses, so the write was silently +lost on `main` before. Copy that state across in the runtime (a method each class owns), +or write the object in place, rather than widening the field copy. `PollFn` is refused the +same way; fold it in if the same method fits. + +Public API: the translator's output. diff --git a/quest/m3/ts-option-slot.md b/quest/m3/ts-option-slot.md new file mode 100644 index 000000000..8c51ebf72 --- /dev/null +++ b/quest/m3/ts-option-slot.md @@ -0,0 +1,17 @@ +# [S] An Option of numbers in the result slot + +## Goal + +A translated function that returns an `Option` of numbers alone, as `Decoder::varint_opt`'s +`Result, E>`, makes no object per call, with every differential test passing +and no workload on `just ts bench` meaningfully slower in any engine. + +## Plan + +Left by [#385](https://github.com/moq-dev/rust2/pull/385), which returns a `Result` of +numbers alone through #160's slot: the slot can't carry an `Option`, so `varint_opt` still +makes an `rt.Ok` per call. moq-net calls it 8 times against 249 for `varint`, so this is +low value; take it when a profile or a new caller shows it matters, or with other work on +the slot. + +Public API: the translator's output. diff --git a/quest/m3/ts-span-precision.md b/quest/m3/ts-span-precision.md new file mode 100644 index 000000000..994fc1382 --- /dev/null +++ b/quest/m3/ts-span-precision.md @@ -0,0 +1,20 @@ +# [S] Type errors at the Rust that made them + +## Goal + +When translated output fails `tsc`, [rust2-ts](/ts/README.md) reports each error at the +Rust expression that made the failing TypeScript, not at a coarser span, proven by reject +fixture cases whose expected spans name the expression. + +## Plan + +Found by [#376](https://github.com/moq-dev/rust2/pull/376), which fails translation on +output `tsc` rejects at the span the source map names. The map is coarse in places: + +- A function's tail `return` maps to its closing `}`, not the tail expression. +- A method call maps to the method's name, not its receiver or the argument that failed. + +Give those nodes the span of the MIR statement or operand they come from. Measure that the +finer map does not grow the output or slow a moq-net translation. + +Public API: the translator's error spans.