Repository navigation
feat(ts): a byte local whose address is taken, in a buffer of its own - #640
Conversation
Quest-Claim: f91701bdecb3be7b
A `u8` or `MaybeUninit<u8>` local whose `&raw` the body takes, or that of a reference to it made there, is element 0 of a `Uint8Array` of its own, so its raw, mutable, and shared slices, and arrays cast from them, view it. The lone-byte refusals in origin.rs go; a byte in a field still throws at run time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # ts/README.md
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 44 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit de3b678 against base 76f9955.
No actionable findings identified in this static review. Giving address-taken byte locals stable one-byte buffers fixes their slice/view representation at its source. I checked Slot::Byte reads and writes, parameter entry copies without changing the numeric ABI, alias/place conversion, pointer origins, the guard against tracing redirected references, and the registered lone_bytes fixture and generated output. A separate inspection also checked pending-read ordering and stable buffer identity without finding a concrete regression.
Direction: retain the new differential and redirection coverage. The explicitly documented field-byte and call-only ptr::from_mut limitations remain runtime gaps; this review does not claim those routes are now supported.
Verification limits: GitHub source/diff inspection only. I did not execute the translator, TypeScript checks, native differential fixtures, quest checks, or just ci. Reported passing tests and mutation reproductions have not been independently reproduced. This is a COMMENT, not an approval.
(Written by review (OpenAI))
# Conflicts: # ts/README.md
…ing past a byte's own buffer Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # quest/m3/ts-runtime-throws.md # ts/README.md # ts/fixtures/reject/src/pointers.rs
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit 7a18933 against base 132d0ad, comparing the changes since my review of de3b678 while accounting for merged main changes.
No new actionable findings identified. The substantive follow-up replaces the buffered byte's unknown-length Array::Owned origin with Array::Byte(Local), retaining stable identity while making its length one. This restores body-visible bounds refusals, including write_bytes past the byte, without treating a shared slice of the buffered byte as a copied lone byte. The merged text-pointer origin remains separate. The other lowering and differential-test changes retain the previously reviewed behavior.
Direction: retain the written_bytes rejection coverage alongside lone_bytes and redirected-reference cases. The documented field-byte and call-only ptr::from_mut gaps remain outside this change.
Verification limits: GitHub source/diff inspection only; no translator, native differential tests, TypeScript checks, or CI executed. Reported passing runs were not independently reproduced. This is a COMMENT, not an approval.
(Written by review (OpenAI))

Claims quest/m3/ts-unsafe/lone-byte-buffers.md, planned in moq-dev/rust2#624, and deletes it.
Problem
JS kept a
u8local in no array of bytes, so a raw or mutable slice of it could not be a view of where it is. moq-dev/rust2#624 refused such slices, and casts of them to*const [u8; N], only on the routes itsraw_starttracer followed, and kept missing routes (&raw *s,NonNull::from,NonNull::new(p).unwrap()). The rest threw at run time.Approach
A
u8orMaybeUninit<u8>local whose&rawthe body takes, or whose reference made in the body is cast to a raw pointer (&mut b as *mut u8,let p: *const u8 = &b), is element 0 of aUint8Array(1)of its own (Slot::Byte). Every read and write isb[0], and every pointer to it isrs.arrayAsPtr(b). Its raw, mutable, and shared slices, and casts of them to*const [u8; N], are views of that buffer on every route, andoffset_frombetween its pointers measures them. Its pointers' origin isArray::Byte, a buffer of length 1, so a pointer, slice, copy, orwrite_bytesthe body shows reaching past it is still refused at translation, as for any value in no array. A parameter keeps its name in the signature and is copied into the buffer on entry.The lone-byte refusals are removed:
Fx::lone_byte_arraywith itsraw_starttracer, andstray's refusal of a raw or mutable slice of a lone byte.Array::Copystays for bytes still in no array, where a shared slice is still an exact copy.Proven by the differential case
pointers::lone_bytesagainst native Rust. It covers each slice and cast route, a parameter,&mut b as *mut u8, a coercion from&c, and aMaybeUninit<u8>.Decisions
.await) throws at run time. Throw only where Rust panics records the gap and owns replacing it with a translation or a refusal: a buffer for each address-takenu8field. Rejected: keeping the refusals for fields only, which is partial route tracing that would be deleted later. Rejected: giving field bytes buffers in this PR.Choices made without asking
&rawthe body takes. A&rawof*r, whereris a reference to the local made once in the body, buffers the local too, unless the body takes a&muttor(or&raw mut r), which could redirect it to another byte. That is what&mut b as *mut u8and a coercion to a raw pointer compile to, and without it the most common spelling kept throwing. Calls such asptr::from_mut(&mut b)are not traced and still throw, as they did before this PR (originnever traced them).ts-runtime-throws.mdlists that as well.write_bytesshowed that a buffered byte's origin,Array::Owned, had no known length. That silenced its refusal of(&raw mut b).write_bytes(0xff, 2)(fixtures/reject/src/pointers.rs:written_bytes), and every other "reaching past" refusal for a buffered byte. At run timeAtIndex.reachwould still have thrown. The origin is nowArray::Byte, of length 1, which keeps the refusals and main's expected lines unchanged. A write within the buffer is exact, but a write past it has no native meaning (it is UB), so the refusal stays.MaybeUninit<u8>locals are buffered too, sincecrate::lower::bytecounts them as bytes.Overlaps
&raw const *rfor any value JS copies. This PR handles it only for a buffered byte, in the sameRawPtrarm ofrvalue.rs. Whichever lands second resolves the conflict and keeps both: the buffered byte's arm first, then feat(ts): translate a raw pointer behind a reference #621's general one.quest/m3/ts-runtime-throws.md's gap list, and plansslice::from_mut(&mut b)as a quest of its own (that call is refused, not thrown).Caused by
raw_starttracedImpact
Uint8Arrayin generated code, and constructs the reject fixture refused (lone_byte_slices,lone_byte_arrays) now translate. No runtime or wire change.Alternatives
lone_byte_arrayfor bytes in fields: rejected, see Decisions.&mutborrows, which would also cover call routes likeptr::from_mut(&mut b): not taken. It changes the output of every&mut u8local for routes no consumer uses.Validation
quest gate just ci origin/mainon head de3b678 (origin/main at 76f9955ca merged in): passed. That includeslang::pointers' new differential casepointers::lone_bytesagainst native Rust (89 fixture tests).UPDATE_EXPECT=1 just ts testleft every snapshot unchanged,dynsandpanics/hookincluded.&mut rbeing traced to its first borrow. The new redirect case reproduced it (145 differences against native Rust) before the fix and passes after.ts/README.md's pointer row. Resolved by keeping this PR's row and applying moq-dev/rust2#642'swrite_bytesedits to it.rejectandreject_censusthen failed on the lostwritten_bytesrefusal, fixed above. The rebound lines in that failure were only a shifted diff window: expected and actual agree oncewritten_bytesis refused, and no snapshot was regenerated.quest gate nix develop -c just ciafter the fix: passed (89 fixture tests, includingpointers::lone_bytesagainst native Rust). Run again after the conflict-free merge of origin/main at f82788274, which round 3 reviewed against: passed.str::as_ptr): three conflicts, resolved by hand.ts/README.md's pointer row is this PR's row plus feat(ts): translate str::as_ptr as a read-only pointer into its UTF-8 #634'sstr::as_ptrsentence.fixtures/reject/src/pointers.rskeeps feat(ts): translate str::as_ptr as a read-only pointer into its UTF-8 #634'stext_apartandtext_beforeand dropslone_byte_slicesandlone_byte_arraysas before.quest/m3/ts-runtime-throws.md's gap list keeps both the substring-read gap and the field-byte gap.origin.rsauto-merged feat(ts): translate str::as_ptr as a read-only pointer into its UTF-8 #634'sArray::TextbesideArray::Byte.quest gate nix develop -c just cipassed afterwards.ffi/andquest/.quest check --fix: ok. Review round 4 covered this head.quest check --fix: ok.Follow-ups
Models
Size: M
Implementer: Claude Code, claude-opus-5-5, high effort
Review
Rewritten by
quest reviewafter each round.01a1b680-72a7-7f00-93a9-494d8a478eed, round 4The merge resolutions preserve byte-buffer and text-pointer behavior, and differential reruns passed 22,358 cases with no differences.