Skip to content

feat(ts): translate panic::Location and #[track_caller] - #551

Merged
kixelated merged 6 commits into
mainfrom
quest/m3/ts-panic-location
Nov 3, 2026
Merged

kixelated merged 6 commits into
mainfrom
quest/m3/ts-panic-location

Conversation

@kixelated

@kixelated kixelated commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

rust2-ts refused panic::Location with a span (left by #538), so Location::caller, its accessors, and #[track_caller] didn't translate.

Approach

  • Location is a new Std::Location, an immutable rt.Location { file, line, col } (runtime/rt/location.ts) with std's Display, Debug, ==, Ord, and Hash, usable as a key in std's collections. file, line, and column read its fields.
  • A crate function rustc says requires its caller's location (InstanceKind::requires_caller_location) gets a trailing caller: rt.Location parameter (ts/src/lower/caller.rs). As in rustc's codegen, each call passes the location of the call's fn_span: the outermost macro call, with the file named as span_as_caller_location names it. Inside a tracked function, a call passes its own caller instead. Location::caller evaluates to that same location.
  • Closures, chains, trait methods (direct, generic, and Index), and trait objects are handled. A dyn method takes caller when the trait declares #[track_caller]. When only the impl does, the wrapper passes the impl's own location, as rustc's vtable shim does.
  • A function pointer to a tracked function (a reify cast, or a pointer constant) passes the function's definition span, as rustc's reify shim does.
  • A const or static of &Location is read out of its allocation.
  • Refused with a span, since natively the location is in std's source: a tracked function used as a value that std's Fn impls call (opt.map(tracked), iter.map(tracked), a generic impl Fn called with one), a crate call that reaches a tracked function only through std's code, a tracked method std calls by name (an iterator's next and other own methods, a Drop::drop), and Location::caller as a pointer. file_as_c_str falls to the usual refusal.
  • Only the crate's functions take a location. Std's tracked functions, such as unwrap, indexing, borrow_mut, and the from-MIR unwrap_or_else, take none, because nothing reads it: translated panics carry no location, and the hook is ts-panic-hook. So map(Option::unwrap) still translates.

Native results that set the rules above, checked with rustc: a fn pointer reports the definition span, Fn-trait calls report core/src/ops/function.rs, and an impl-only tracked method called through dyn reports the impl's span.

Proof: ts/fixtures/lang/panics/src/located.rs runs differentially against native wasm32. It covers every case above, plus {:>60} (which std doesn't pad), {:#?}, {:x?}, ordering, dedup, BTreeSet and HashSet, a Location held in a struct and an Option, and a panic message carrying the location. Refusals are in fixtures/reject/src/panics.rs.

Cost

Measured by output, not timing: the moq-net codec (just ts moq) and both bench fixtures (fixtures/codec, fixtures/task) contain no tracked function, and their translations are byte-identical to main (no rt.Location in the output, snapshots unchanged). So just ts bench times the same code, and hot paths pay nothing. The cost of passing a location into std's runtime calls (unwrap, indexing) is left to the hook quest, the first place one is read.

Impact

  • Translator output: a crate's tracked function, and a dyn method its trait tracks, takes an extra last rt.Location argument. A TS caller or implementer of such a trait object passes or accepts it. No existing output changes otherwise.
  • Runtime: new rt.Location, locationEq, locationCmp, locationHash, fmtLocationDisplay, fmtLocationDebug.
  • Not breaking: nothing that translated before changes shape.

Alternatives

  • Passing a location to every runtime panic too (rt.unwrap(o, loc), rt.index(..., loc)): that is what the hook needs, but nothing reads it yet, and it would cost every hot call. Left to ts-panic-hook, whose plan now says so.
  • Passing std's Fn-impl location for a tracked fn item called through Fn: it names the native build's sysroot path, which translation can't know. Refused instead.

Follow-ups

  • ts-panic-hook, updated: std's runtime-mapped tracked functions and std-internal panic paths.

Review

quest review, Codex gpt-6.1-sol, medium effort. Round 2 on head 88604e185 reported no findings. Round 1 (head c95095cfb) had three findings:

  • A #[track_caller] Iterator::next or other own iterator method is called by the runtime's protocol with no location. Fixed: a tracked crate function that std's code calls by symbol (iterator protocol, collect, drop glue's Drop::drop) is refused at its definition (caller::refuse_std_call). Covered in fixtures/reject.
  • A reified pointer to a () function was typed void where values are undefined. Fixed: cast as fn_value does, covered by a [fn(bool); 2] in the fixture.
  • Display should write in parts, as std's write! does. Fixed: it now goes through fmtWriteFmt. Refuted the request for a capped-writer differential case: translation already refuses placeholders written into a crate's own fmt::Write (reproduced while adding the case), and the runtime's writers never fail, so translated code can't observe it.

Since then: a conflict-free merge of origin/main (head 7117ecc02).

🤖 Generated with Claude Code

@kixelated kixelated changed the title A panic's Location feat(ts): translate panic::Location and #[track_caller] Nov 3, 2026
kixelated and others added 2 commits November 3, 2026 13:30
…ified pointer as a value, and write a Location's Display in parts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated marked this pull request as ready for review November 3, 2026 21:36
@pullfrog

pullfrog Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

This run was cancelled before it finished.

Pullfrog  | View workflow run | via Pullfrog

@coderabbitai

coderabbitai Bot commented Nov 3, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You'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 54 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 35d7ec18-5a53-4c45-a0d4-18997ae307ec
Commits

Reviewing files that changed from the base of the PR and between 1b0fe64 and 7117ecc.

Files selected for processing: 36
  • quest/m3/README.md
  • quest/m3/ts-panic-hook.md
  • quest/m3/ts-panic-location.md
  • ts/README.md
  • ts/fixtures/lang/panics/expected/core/bool.ts
  • ts/fixtures/lang/panics/expected/core/cmp.ts
  • ts/fixtures/lang/panics/expected/core/option.ts
  • ts/fixtures/lang/panics/expected/lib.ts
  • ts/fixtures/lang/panics/expected/located.Held$read.ts
  • ts/fixtures/lang/panics/expected/located.Inherits.ts
  • ts/fixtures/lang/panics/expected/located.Own.ts
  • ts/fixtures/lang/panics/expected/located.Places.ts
  • ts/fixtures/lang/panics/expected/located.Tracked.ts
  • ts/fixtures/lang/panics/expected/located.Untracked.ts
  • ts/fixtures/lang/panics/expected/located.ts
  • ts/fixtures/lang/panics/src/lib.rs
  • ts/fixtures/lang/panics/src/located.rs
  • ts/fixtures/reject/census.txt
  • ts/fixtures/reject/expected.txt
  • ts/fixtures/reject/src/panics.rs
  • ts/fixtures/reject/ts.toml
  • ts/runtime/rt.ts
  • ts/runtime/rt/location.ts
  • ts/src/lower/body.rs
  • ts/src/lower/caller.rs
  • ts/src/lower/collections.rs
  • ts/src/lower/drop.rs
  • ts/src/lower/dynamic.rs
  • ts/src/lower/fmt.rs
  • ts/src/lower/iter.rs
  • ts/src/lower/library.rs
  • ts/src/lower/mir/mod.rs
  • ts/src/lower/mir/place.rs
  • ts/src/lower/mir/rvalue.rs
  • ts/src/lower/mod.rs
  • ts/src/program.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

Share

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.

@kixelated
kixelated added this pull request to the merge queue Nov 3, 2026
Merged via the queue into main with commit 349dd3c Nov 3, 2026
7 of 8 checks passed
@kixelated
kixelated deleted the quest/m3/ts-panic-location branch November 3, 2026 21:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant