Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions quest/m3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
15 changes: 15 additions & 0 deletions quest/m3/ts-empty-places.md
Original file line number Diff line number Diff line change
@@ -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.
24 changes: 24 additions & 0 deletions quest/m3/ts-guard-leftovers.md
Original file line number Diff line number Diff line change
@@ -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.
19 changes: 19 additions & 0 deletions quest/m3/ts-lazy-writes.md
Original file line number Diff line number Diff line change
@@ -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.
17 changes: 17 additions & 0 deletions quest/m3/ts-option-slot.md
Original file line number Diff line number Diff line change
@@ -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<Option<u64>, 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.
20 changes: 20 additions & 0 deletions quest/m3/ts-span-precision.md
Original file line number Diff line number Diff line change
@@ -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.