From 9e8b8fd4324fed3afff797d7faade428d2397257 Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Wed, 4 Nov 2026 12:39:12 -0800 Subject: [PATCH 1/2] quest: plan the model refusals the moq pin bump added Co-Authored-By: Claude Opus 5.5 --- quest/m2/ts-model/README.md | 11 +++++++++++ quest/m2/ts-model/begin-panic.md | 15 +++++++++++++++ quest/m2/ts-model/const-generics.md | 15 +++++++++++++++ quest/m2/ts-model/scheduler-hints.md | 14 ++++++++++++++ quest/m2/ts-model/str-as-ptr.md | 15 +++++++++++++++ .../ts-model/uninit-slices.md} | 4 ++-- quest/m2/ts-model/unit-option-fields.md | 18 ++++++++++++++++++ quest/m3/README.md | 2 +- quest/m3/ts-panic-payload-capacity.md | 16 ++++++++++++++++ 9 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 quest/m2/ts-model/begin-panic.md create mode 100644 quest/m2/ts-model/const-generics.md create mode 100644 quest/m2/ts-model/scheduler-hints.md create mode 100644 quest/m2/ts-model/str-as-ptr.md rename quest/{m3/ts-uninit-slices.md => m2/ts-model/uninit-slices.md} (84%) create mode 100644 quest/m2/ts-model/unit-option-fields.md create mode 100644 quest/m3/ts-panic-payload-capacity.md diff --git a/quest/m2/ts-model/README.md b/quest/m2/ts-model/README.md index 0b67acd93..649f79578 100644 --- a/quest/m2/ts-model/README.md +++ b/quest/m2/ts-model/README.md @@ -55,11 +55,22 @@ refuses for good, and smallvec's union over a type parameter and raw parts (10) [unsafe](/quest/m3/ts-unsafe.md), so both need safe `cfg(rust2_ts)` twins or bindings there, as does the `unsafe` slice of `model/frame.rs`'s `Filled`. +Decided with the maintainer on 2026-11-04, from a census at the bumped pin +(moq-dev/rust2#390): the refusals no quest owned became the children below. ✅ arrayvec's +`ArrayString` needs three of them (const generic types, `begin_panic`, `str::as_ptr`), +kept separate since each lands alone; rejected: one quest for `ArrayString`. + ## Required - [Iterators into a crate's own collections](/quest/m2/ts-model/from-iterator.md) - `collect`, `flat_map`, and `flatten` through moq-pattern's `Patterns` - [Bytes from an owner that drops](/quest/m2/ts-model/bytes-owner.md) - `Bytes::from_owner` of a frame's segment - [rangemap](/quest/m2/ts-model/rangemap.md) - B-tree ranges by a borrowed key, and std's iterators in a crate's fields - [Addresses as identity](/quest/m2/ts-model/addresses.md) - `Arc::as_ptr(a) as usize` as a key, which needs a decision +- [Option fields at a unit instance](/quest/m2/ts-model/unit-option-fields.md) - `Idle<()>`'s `Option` field tells `Some(())` from `None` +- [Const generic types](/quest/m2/ts-model/const-generics.md) - `ArrayString` and other types with const parameters +- [panic! in a 2015 or 2018 crate](/quest/m2/ts-model/begin-panic.md) - the `begin_panic` mapping keyed by its defining module +- [A string's bytes through its pointer](/quest/m2/ts-model/str-as-ptr.md) - `str::as_ptr` reads the string's UTF-8 +- [Scheduler hints](/quest/m2/ts-model/scheduler-hints.md) - `thread::yield_now` and `hint::spin_loop` translate to nothing +- [Slices not yet written](/quest/m2/ts-model/uninit-slices.md) - `Box::new_uninit_slice` of a frame's segment Public API: the translator's output for moq-net's model. diff --git a/quest/m2/ts-model/begin-panic.md b/quest/m2/ts-model/begin-panic.md new file mode 100644 index 000000000..deb6f6020 --- /dev/null +++ b/quest/m2/ts-model/begin-panic.md @@ -0,0 +1,15 @@ +# [XS] panic! in a 2015 or 2018 crate + +## Goal + +[rust2-ts](/ts/README.md) translates `panic!("literal")` in a 2015 or 2018 edition crate, +which expands to `std::rt::begin_panic`, as it does in 2021, proven by a 2018-edition +panics fixture against native Rust. Today arrayvec's is refused. + +## Plan + +The mapping is keyed by `("rt", "begin_panic")`, but `library::key` builds keys from the +defining module, and std defines `begin_panic` in `std::panicking` and only re-exports it +from `rt`, so the mapping never matches. No fixture used a pre-2021 `panic!`. + +Public API: the translator's output. diff --git a/quest/m2/ts-model/const-generics.md b/quest/m2/ts-model/const-generics.md new file mode 100644 index 000000000..22a822376 --- /dev/null +++ b/quest/m2/ts-model/const-generics.md @@ -0,0 +1,15 @@ +# [M] Const generic types + +## Goal + +[rust2-ts](/ts/README.md) translates structs and enums with const parameters, such as +arrayvec's `ArrayString` and `ArrayVec`, so each instance's body reads its own +`N`, proven by differential tests against native Rust. At the moq pin it refuses once in +the model (`Path::join`'s `ArrayString`) and 8 times in moq-net whole. + +## Plan + +Functions with const parameters already translate per instance; types do not yet. Check +how the choice interacts with a type's class being shared across instances. + +Public API: the translator's output. diff --git a/quest/m2/ts-model/scheduler-hints.md b/quest/m2/ts-model/scheduler-hints.md new file mode 100644 index 000000000..ad0d2ebe9 --- /dev/null +++ b/quest/m2/ts-model/scheduler-hints.md @@ -0,0 +1,14 @@ +# [XS] Scheduler hints + +## Goal + +[rust2-ts](/ts/README.md) translates `thread::yield_now` and `hint::spin_loop` to nothing, +as neither promises anything observable, proven by a differential test against native +Rust. At the moq pin `model/frame.rs`'s `attach` refuses on `yield_now`. + +## Plan + +A spin loop that waits on another thread hangs natively on one thread too, so translating +the hint to nothing matches Rust. + +Public API: the translator's output. diff --git a/quest/m2/ts-model/str-as-ptr.md b/quest/m2/ts-model/str-as-ptr.md new file mode 100644 index 000000000..0eaa25187 --- /dev/null +++ b/quest/m2/ts-model/str-as-ptr.md @@ -0,0 +1,15 @@ +# [S] A string's bytes through its pointer + +## Goal + +[rust2-ts](/ts/README.md) translates `str::as_ptr` as a read-only pointer to the string's +UTF-8, so `ptr::copy_nonoverlapping` and `slice::from_raw_parts` read what Rust reads, +proven by differential tests against native Rust. At the moq pin arrayvec's +`ArrayString` refuses it once in the model and 3 times in moq-net whole. + +## Plan + +`rs.String` keeps a JS string (#574), so the bytes are an encoding of it; a pointer into +them must not let a write through it go unnoticed, which Rust forbids anyway for a `&str`. + +Public API: the translator's output. diff --git a/quest/m3/ts-uninit-slices.md b/quest/m2/ts-model/uninit-slices.md similarity index 84% rename from quest/m3/ts-uninit-slices.md rename to quest/m2/ts-model/uninit-slices.md index 6e0af7aed..e9950b938 100644 --- a/quest/m3/ts-uninit-slices.md +++ b/quest/m2/ts-model/uninit-slices.md @@ -11,5 +11,5 @@ differential tests against native Rust. A `MaybeUninit` is a `T` in JS, and one of a byte is the byte, so a `[MaybeUninit]` is an `rs.ByteSlice`; `write_copy_of_slice` and a slice's `assume_init_ref` and `assume_init_mut` already map. `write_clone_of_slice` clones in without dropping what was -there, unlike `clone_from_slice`. Found translating `spare_capacity_mut`; no consumer calls -either yet. +there, unlike `clone_from_slice`. Found translating `spare_capacity_mut`. moq-net's `model/frame.rs` calls +`Box::<[u8]>::new_uninit_slice` in `Segment::new` at the moq pin. diff --git a/quest/m2/ts-model/unit-option-fields.md b/quest/m2/ts-model/unit-option-fields.md new file mode 100644 index 000000000..3c411dd22 --- /dev/null +++ b/quest/m2/ts-model/unit-option-fields.md @@ -0,0 +1,18 @@ +# [S] Option fields of a generic type at a unit instance + +## Goal + +[rust2-ts](/ts/README.md) translates a generic type's `Option` or `Poll` field at an +instance whose `T` is itself `undefined` or pending in JS, such as moq-net's `Idle<()>` +(`util/idle.rs`'s `parked`) and tokio's `oneshot::Inner<()>`, proven by differential +tests against native Rust. At the moq pin it refuses 16 times in the model and 24 in +moq-net whole. + +## Plan + +The type's definition types the field `T | undefined`, which loses `Some(())` against +`None` at `T = ()`; the field needs `rs.None` (or `rs.OuterPending`) where an instance +can already be the bare value. Decide it per field from the instances the crate uses, not +per type, and keep the bare form for every other instance. + +Public API: the translator's output. diff --git a/quest/m3/README.md b/quest/m3/README.md index 5c21d0873..d4be3829d 100644 --- a/quest/m3/README.md +++ b/quest/m3/README.md @@ -22,8 +22,8 @@ generic std gap is planned here even when moq never calls it. - [rs.Slice](/quest/m3/ts-slice-object.md) - references to arrays of other values are a runtime slice too, and pointers compare by where they point - [Writes through iter_mut without a Place per item](/quest/m3/ts-iter-mut-places.md) - a loop over `iter_mut()` of copy values writes the slice's array by index - [rs.String](/quest/m3/ts-string-capacity.md) - `String`, `Box`, and `&str` are a runtime type holding std's capacity -- [Slices not yet written](/quest/m3/ts-uninit-slices.md) - `Box::new_uninit_slice` and `write_clone_of_slice` translate - [Throw only where Rust panics](/quest/m3/ts-runtime-throws.md) - no runtime `rust2-ts:` error where native Rust goes on: an exact slower path, or a refusal at translation - [rust2-ts with no ts.toml](/quest/m3/ts-configless.md) - a crate's whole `pub` API translates with no config and no bound items - [Buf on a deque of bytes](/quest/m3/ts-vecdeque-buf.md) - `bytes`' `Buf` for a deque of bytes translates +- [std's panic messages hold std's capacity](/quest/m3/ts-panic-payload-capacity.md) - a hook reads native's `String` capacity from std's own formatted panics - [A B-tree drops as std's does](/quest/m3/ts-btree-drop-order.md) - keys and values drop node by node, in std's order diff --git a/quest/m3/ts-panic-payload-capacity.md b/quest/m3/ts-panic-payload-capacity.md new file mode 100644 index 000000000..1cfa62e53 --- /dev/null +++ b/quest/m3/ts-panic-payload-capacity.md @@ -0,0 +1,16 @@ +# [M] std's panic messages hold std's capacity + +## Goal + +A panic hook in code [rust2-ts](/ts/README.md) generates reads the same `String` capacity +from std's own formatted panic messages (such as `slice index starts at {} but ends at +{}`) as native Rust, proven by the panics fixture's hook against native Rust. + +## Plan + +Found in #574: the runtime passes std's formatted messages as one string, so their +capacity differs from std's, which builds them piece by piece (37 against 44 for that +message). About 64 runtime sites pass such a message. Build each as std's `format!` does, +without slowing the paths that never panic. + +Public API: the runtime's panic sites, not their messages. From 8d996cee1441890b2fcc6692b716461e2f76d9d1 Mon Sep 17 00:00:00 2001 From: Luke Curley <432854+kixelated@users.noreply.github.com> Date: Wed, 4 Nov 2026 12:42:39 -0800 Subject: [PATCH 2/2] quest: the panic capacity quest waits on rs.String Co-Authored-By: Claude Opus 5.5 --- quest/m2/ts-model/str-as-ptr.md | 2 +- quest/m3/ts-panic-payload-capacity.md | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/quest/m2/ts-model/str-as-ptr.md b/quest/m2/ts-model/str-as-ptr.md index 0eaa25187..2c079ee74 100644 --- a/quest/m2/ts-model/str-as-ptr.md +++ b/quest/m2/ts-model/str-as-ptr.md @@ -9,7 +9,7 @@ proven by differential tests against native Rust. At the moq pin arrayvec's ## Plan -`rs.String` keeps a JS string (#574), so the bytes are an encoding of it; a pointer into +A `&str` stays a JS string (decided on #574), so the bytes are an encoding of it; a pointer into them must not let a write through it go unnoticed, which Rust forbids anyway for a `&str`. Public API: the translator's output. diff --git a/quest/m3/ts-panic-payload-capacity.md b/quest/m3/ts-panic-payload-capacity.md index 1cfa62e53..372284152 100644 --- a/quest/m3/ts-panic-payload-capacity.md +++ b/quest/m3/ts-panic-payload-capacity.md @@ -8,9 +8,13 @@ from std's own formatted panic messages (such as `slice index starts at {} but e ## Plan -Found in #574: the runtime passes std's formatted messages as one string, so their +Found in #574, which gives `String` its capacity: the runtime passes std's formatted messages as one string, so their capacity differs from std's, which builds them piece by piece (37 against 44 for that message). About 64 runtime sites pass such a message. Build each as std's `format!` does, without slowing the paths that never panic. Public API: the runtime's panic sites, not their messages. + +## Required + +- [rs.String](/quest/m3/ts-string-capacity.md) - `String` holds std's capacity, which a hook then reads