Skip to content

Enable -Zpolonius=next and remove NLL borrow-checker workarounds - #36951

Open
robobun wants to merge 15 commits into
mainfrom
farm/d896e148/polonius-cleanups
Open

Enable -Zpolonius=next and remove NLL borrow-checker workarounds#36951
robobun wants to merge 15 commits into
mainfrom
farm/d896e148/polonius-cleanups

Conversation

@robobun

@robobun robobun commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Enables the polonius borrow checker (-Zpolonius=next) for all Rust compilation and deletes the workarounds it makes unnecessary.

Context

Polonius alpha became the default borrow checker on nightly starting with nightly-2026-08-06 (rust-lang/rust#159343, via compiler-team MCP 1015), so bun's next toolchain bump switches borrow checkers regardless. On the currently pinned nightly-2026-07-20 it is opt-in, which is what the flag does here. The flag is worth keeping even after a bump: upstream has said it will flip the default back off if problems turn up while the alpha bakes (two soundness reports of the "accepts code it should reject" kind are open, rust-lang/rust#160669 and #160670), and a toolchain bump should not silently change which borrow checker builds bun.

A bump to nightly-2026-08-11 was tried on this branch (750fa2d) and reverted (24ac600): it moves rust-lld to LLVM 23 while the prebuilt WebKit LTO bitcode is still produced by LLVM 21, and the windows-x64 cross-language LTO link then fails with undefined WTF symbols (build 91851). That is independent of this change and belongs in its own PR.

What polonius buys

It accepts NLL "problem case 3": a borrow returned or escaping on one control-flow path no longer blocks use or mutation of the borrowed place on the other paths. The workspace had accumulated workarounds for exactly this: unsafe raw-pointer reborrows, contains_key-then-get double lookups, index/len round-trips instead of returning a borrow, and a bool-plus-out-param helper signature.

Changes

  • scripts/build/rust.ts: -Zpolonius=next in the ninja cargo edge (CARGO_ENCODED_RUSTFLAGS), so bun bd and CI builds use it.
  • scripts/build/cargo-config.ts: the flag in every generated [target.*] rustflags section, including new rustflags-only sections for the windows-msvc triples (previously omitted entirely), so plain cargo check, rust:check-all, cargo miri, clippy and rust-analyzer accept the same code the build does.
  • src: 25 files. Seven unsafe raw-pointer reborrow blocks deleted (bun_which, the open command's editor detection), editor helpers return Option<&[u8]> instead of bool plus out-param, double hash lookups collapsed to single lookups (test_runner snapshots, WorkspacePackageJSONCache), and about twenty more sites lose their index/len/copy scaffolding (node:path, env loader, ConsoleObject, linear_fifo, patchPackage, elf writer, node_fs readdir, postgres DataCell, and others). Several of these require polonius (bun_collections, bun_dotenv and bun_install fail under stock NLL); the rest turned out to be removable under NLL too and simply lost dead scaffolding.
  • Tests: coverage for the rewritten sites (Bun.which across PATH segments, path.win32.toNamespacedPath branches, console.table column discovery order). No existing expectations changed.

Cost and risk

  • cargo check --workspace cold: 55.7s without the flag, 56.6s with it (8 cores), about 2%.
  • The toolchain is already pinned nightly; no channel change.
  • Everything the flag newly accepts here is code the stock checker rejected only for imprecision. If a future bump regresses one of these sites, the fix is local to that site.

Verification

  • cargo check --workspace clean under the flag on x86_64-linux, x86_64-windows-msvc and aarch64-darwin targets; without the flag it fails as expected (linear_fifo.rs E0499 first, then env_loader.rs, patchPackage.rs, WorkspacePackageJSONCache.rs as each crate is unblocked).
  • Full bun bd build green; standalone --compile smoke test (exercises the elf writer change).
  • cargo test -p bun_collections (34 pass, covers linear_fifo); cargo miri test -p bun_collections clean.
  • bun bd test: node/path suite, cli/run/env, web/console, fs readdir-recursive-leak, web/fetch/body, cli/install/bun-patch, cli/install/isolated-install all pass.
  • CI: the src changes plus the flag were green across the full matrix (including clippy and miri) on builds 91643 through 91766; the current head re-runs the same shape after the bump revert.

no test proof · iteration 5 · Platform-specific test(s) that do not run on this machine. Deferring to CI, which covers all platforms: test/js/bun/util/which.test.ts test/js/node/path/to-namespaced-path.test.js

robobun added 3 commits August 5, 2026 09:48
Requires building with -Zpolonius=next. Deletes 7 unsafe raw-pointer
reborrows in bun_which and the open command's editor detection, converts
the editor helpers from bool plus out-param to returned Option borrows,
and replaces two contains_key-then-get double lookups with single
lookups.
Wires the polonius alpha borrow checker into the ninja cargo edge and the
generated .cargo/config.toml (including new sections for the windows-msvc
triples, which previously had none) so bun bd, CI, plain cargo check,
rust:check-all, and rust-analyzer all accept the same code. The pinned
toolchain is already nightly. Measured cost: ~2% on a cold cargo check of
the workspace.
Rewrites 25 borrow-checker workaround sites to their natural form:
single lookups instead of contains_key-then-get, direct early returns
of borrows instead of index/len round-trips, plain reborrows instead
of raw-pointer reborrows. Several sites (linear_fifo, env_loader,
patchPackage, Chunk, fmt) now require the polonius borrow checker
enabled in the previous commit; the rest simply lost their scaffolding.
robobun and others added 2 commits August 5, 2026 10:20
Adds cases for Bun.which PATH-segment iteration (hit in a later segment
after misses), path.win32.toNamespacedPath branch coverage (long-path
fall-through, device root, UNC conversion, dot-dot resolution), and
inspect.table column discovery across heterogeneous rows.
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

The PR enables Polonius in Rust builds and simplifies slice, buffer, cache, path, lookup, bundler, and DNS handling. Tests cover table column discovery, PATH traversal, and Windows namespaced paths.

Borrow simplification and runtime cleanup

Layer / File(s) Summary
Polonius build configuration
scripts/build/cargo-config.ts, scripts/build/rust.ts
Build flags now include -Zpolonius=next for Windows and non-Windows targets.
Core buffer and collection simplification
src/bun_core/fmt.rs, src/collections/*, src/dotenv/env_loader.rs, src/exe_format/elf.rs, src/install/PackageManager/WorkspacePackageJSONCache.rs, src/install/isolated_install.rs, src/jsc/ConsoleObject.rs, src/runtime/api/bun/spawn/stdio.rs, src/runtime/bake/production.rs, src/runtime/test_runner/snapshot.rs, src/runtime/webcore/Body.rs, src/sql_jsc/postgres/DataCell.rs
Core operations now retain direct slices or existing results instead of reconstructing values or allocating temporary buffers.
Installation and filesystem path ownership
src/install/PackageManager/patchPackage.rs, src/install/isolated_install/Hardlinker.rs, src/runtime/node/node_fs.rs
Package lookup, Windows hardlinking, and recursive deletion now use borrowed path slices, with ownership created at return boundaries.
Runtime path and executable resolution
src/runtime/node/path.rs, src/runtime/node/types.rs, src/runtime/socket/Listener.rs, src/runtime/cli/open.rs, src/runtime/cli/upgrade_command.rs, src/which/lib.rs, test/js/bun/console/bun-inspect-table.test.ts, test/js/bun/util/which.test.ts, test/js/node/path/to-namespaced-path.test.js
Path, editor, executable, and named-pipe resolution now consume direct slices. Tests cover table columns, PATH traversal, and Windows path conversion.
Bundler and DNS control flow
src/bundler/Chunk.rs, src/bundler/transpiler.rs, src/runtime/dns_jsc/dns.rs
CSS lookup returns referenced chunks directly, cache invalidation uses one computed path, and DNS poll entries publish only after successful initialization.

Possibly related PRs

  • oven-sh/bun#34782: Both changes modify Rust build configuration in scripts/build/rust.ts.
  • oven-sh/bun#36569: Both changes modify executable resolution in src/which/lib.rs.
  • oven-sh/bun#37052: Both changes modify shared slice-handling code in runtime path and parsing modules.

Suggested reviewers: jarred-sumner, dylan-conway

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main changes: enabling Polonius and removing obsolete borrow-checker workarounds.
Description check ✅ Passed The description explains the changes, context, risks, performance impact, and verification results in sufficient detail.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/js/bun/console/bun-inspect-table.test.ts`:
- Around line 21-23: Update the table test data to discover columns in a clearly
non-alphabetical first-seen order, and configure the relevant
inspection/snapshot calls to preserve that discovery order instead of sorting.
Keep the assertions as a regression test that distinguishes insertion order from
lexical sorting, including the affected snapshot expectations.

In `@test/js/bun/util/which.test.ts`:
- Around line 274-290: Replace the external chmod shell invocation in the test
around which("prog_in_third", { PATH }) with chmodSync(join(d,
"third/prog_in_third"), 0o755), retaining the existing !isWindows guard and
ensuring the required built-in filesystem import is available.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a35a3cd7-b490-459d-9444-e0eb409b25c3

📥 Commits

Reviewing files that changed from the base of the PR and between b58cd46 and a5dcc4d.

⛔ Files ignored due to path filters (1)
  • test/js/bun/console/__snapshots__/bun-inspect-table.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (30)
  • scripts/build/cargo-config.ts
  • scripts/build/rust.ts
  • src/bun_core/fmt.rs
  • src/bundler/Chunk.rs
  • src/bundler/transpiler.rs
  • src/collections/array_hash_map.rs
  • src/collections/linear_fifo.rs
  • src/dotenv/env_loader.rs
  • src/exe_format/elf.rs
  • src/install/PackageManager/WorkspacePackageJSONCache.rs
  • src/install/PackageManager/patchPackage.rs
  • src/install/isolated_install.rs
  • src/install/isolated_install/Hardlinker.rs
  • src/jsc/ConsoleObject.rs
  • src/runtime/api/bun/spawn/stdio.rs
  • src/runtime/bake/production.rs
  • src/runtime/cli/open.rs
  • src/runtime/cli/upgrade_command.rs
  • src/runtime/dns_jsc/dns.rs
  • src/runtime/node/node_fs.rs
  • src/runtime/node/path.rs
  • src/runtime/node/types.rs
  • src/runtime/socket/Listener.rs
  • src/runtime/test_runner/snapshot.rs
  • src/runtime/webcore/Body.rs
  • src/sql_jsc/postgres/DataCell.rs
  • src/which/lib.rs
  • test/js/bun/console/bun-inspect-table.test.ts
  • test/js/bun/util/which.test.ts
  • test/js/node/path/to-namespaced-path.test.js
💤 Files with no reviewable changes (2)
  • src/runtime/api/bun/spawn/stdio.rs
  • src/runtime/webcore/Body.rs

Comment thread test/js/bun/console/bun-inspect-table.test.ts Outdated
Comment thread test/js/bun/util/which.test.ts
Make the table column-discovery input non-alphabetical so the snapshot
distinguishes first-seen order from lexical sorting, add an unsorted
variant, and use chmodSync instead of shelling out.
@robobun

robobun commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed both review comments in 2851dd2: the table column-discovery input now uses a non-alphabetical first-seen order (d, b, a, c, e) with an additional unsorted snapshot so insertion order is distinguishable from lexical sorting, and the which test uses chmodSync instead of spawning chmod.

Comment thread scripts/build/rust.ts Outdated
Comment thread scripts/build/cargo-config.ts
@robobun

robobun commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

Status: merged main into the branch (9254173) to clear conflicts with #37052 in src/bun_core/fmt.rs and src/which/lib.rs. Resolution keeps this PR's shape at both sites and uses the highway helpers main now requires (strings::last_index_of_char / index_of_char_usize in format_ip, strings::tokenize in which_win). The one red lane in build 89156 (AsyncLocalStorage-tracking LSAN leak in RSA keygen) was a main break, fixed by #36986, so it should be gone on the rerun.

Verified after the merge: cargo check --workspace under -Zpolonius=next is clean (host target, plus bun_core/bun_which for x86_64-pc-windows-msvc since which_win is cfg(windows)), and test/internal/source-lints passes (75/75). Diff against main is unchanged otherwise: 31 files, +243/-312. Waiting on CI and a maintainer.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — both earlier comment nits (the dead grep polonius hint and the stale Windows-msvc docstring) are addressed in 850981a. I didn't find any bugs this pass, but this adopts an alpha borrow checker as a hard workspace dependency and rewrites control flow across 27 files in critical subsystems, so it needs a maintainer sign-off.

Checked: the dns.rs reordering (map value now written after uv_poll_init_socket) — value type is a raw pointer so swap_remove on the failure path is still a no-op drop; isolated_install.rs members borrow of scc_stacktruncate(start) runs after the last use; elf.rs strtab hoist — the mutable write only happens on the return path where strtab is dead.

Extended reasoning...

Overview

Enables -Zpolonius=next in both the ninja cargo edge (CARGO_ENCODED_RUSTFLAGS in rust.ts) and every generated .cargo/config.toml [target.*] section (cargo-config.ts, including new Windows-msvc rustflags-only sections). Then removes ~27 files' worth of NLL problem-case-3 workarounds: seven unsafe raw-pointer reborrow blocks (bun_which, open.rs, Hardlinker.rs), contains-then-get double lookups (snapshot.rs, WorkspacePackageJSONCache.rs), index/len round-trips instead of returned borrows (fmt.rs, path.rs, node_fs.rs, ConsoleObject.rs, linear_fifo.rs, Listener.rs, types.rs, elf.rs, DataCell.rs), a bool-plus-out-param signature reshaped to Option<&[u8]> (open.rs), an owned-Vec return collapsed to a borrowed &ZStr (patchPackage.rs), and dropped clones/Box::from in production.rs, isolated_install.rs, Chunk.rs, transpiler.rs, upgrade_command.rs, stdio.rs, Body.rs, env_loader.rs. Adds tests for the touched paths (console.table column discovery, which() PATH-segment iteration, path.win32.toNamespacedPath branches).

Security risks

None identified. The removed unsafe blocks were all raw-pointer reborrows working around NLL imprecision, not soundness holes; their replacements are straightforward safe borrows accepted by polonius. No auth/crypto/permission code touched.

Level of scrutiny

High. This is a toolchain-level architectural decision — the workspace now hard-requires an alpha borrow checker (linear_fifo.rs and others no longer compile under stock NLL), so every future nightly bump carries the risk of polonius acceptance changing at the margin. Combined with control-flow rewrites across 27 files spanning bundler, package manager, DNS resolver, node:fs/node:path, socket listener, ELF writer, and postgres — each change is small and mechanical in isolation, but the aggregate is well past the threshold for auto-approval.

Other factors

  • My two prior inline nits (dead grep polonius in src/ pointer; stale "Windows-msvc targets are omitted" docstring) were both addressed in commit 850981a.
  • I spot-checked the three reorderings with actual behavioral surface: (1) dns.rs*poll_entry.value_ptr = new_poll moved after the uv_poll_init_socket check. On the failure path, swap_remove(&fd) now removes a default-valued slot instead of a slot holding new_poll, but the value type is *mut UvDnsPoll (Copy, no Drop), so net state is identical. (2) isolated_install.rsmembers now borrows scc_stack[start..] instead of cloning; verified scc_stack.truncate(start) (line 1609) runs after the last use of members (line 1605), so no aliasing. (3) elf.rsstrtab hoisted out of the loop; the &mut self.data write only occurs on the return path where strtab is no longer live.
  • CodeRabbit's two minor test-quality comments were addressed in 2851dd2.
  • Tests were added, but the PR notes the platform-specific ones (which.test.ts on Windows, to-namespaced-path.test.js) defer to CI.

…s-cleanups

# Conflicts:
#	src/bun_core/fmt.rs
#	src/which/lib.rs
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/runtime/dns_jsc/dns.rs (1)

4833-4844: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Add a regression test for failed poll initialization.

Force uv_poll_init_socket to fail on Windows. Assert that polls contains no entry for fd after on_dns_socket_state returns. This protects the delayed-publication invariant.

As per coding guidelines, “Every behavioral change must include an automated regression test in the same change.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/runtime/dns_jsc/dns.rs` around lines 4833 - 4844, Add a Windows-specific
regression test covering on_dns_socket_state when uv_poll_init_socket fails:
force initialization to return an error, invoke the handler for a file
descriptor, and assert polls has no entry for that descriptor afterward. Keep
the test focused on the delayed-publication invariant and place it with the
existing DNS poll tests.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/build/rust.ts`:
- Around line 413-421: Add or extend a hermetic test covering
generateCargoConfig() and cargoBuildInvocation() for Windows MSVC and
non-Windows configurations. Assert Windows target sections contain ["-Z",
"polonius=next"], decode CARGO_ENCODED_RUSTFLAGS using \x1f and assert
-Zpolonius=next, and preserve assertions for existing non-Windows linker flags;
run it with bun bd test <test-file>.

---

Outside diff comments:
In `@src/runtime/dns_jsc/dns.rs`:
- Around line 4833-4844: Add a Windows-specific regression test covering
on_dns_socket_state when uv_poll_init_socket fails: force initialization to
return an error, invoke the handler for a file descriptor, and assert polls has
no entry for that descriptor afterward. Keep the test focused on the
delayed-publication invariant and place it with the existing DNS poll tests.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d476e2ae-09b5-4167-8f2d-35932b96e5bc

📥 Commits

Reviewing files that changed from the base of the PR and between 827475e and 9254173.

⛔ Files ignored due to path filters (1)
  • test/js/bun/console/__snapshots__/bun-inspect-table.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (30)
  • scripts/build/cargo-config.ts
  • scripts/build/rust.ts
  • src/bun_core/fmt.rs
  • src/bundler/Chunk.rs
  • src/bundler/transpiler.rs
  • src/collections/array_hash_map.rs
  • src/collections/linear_fifo.rs
  • src/dotenv/env_loader.rs
  • src/exe_format/elf.rs
  • src/install/PackageManager/WorkspacePackageJSONCache.rs
  • src/install/PackageManager/patchPackage.rs
  • src/install/isolated_install.rs
  • src/install/isolated_install/Hardlinker.rs
  • src/jsc/ConsoleObject.rs
  • src/runtime/api/bun/spawn/stdio.rs
  • src/runtime/bake/production.rs
  • src/runtime/cli/open.rs
  • src/runtime/cli/upgrade_command.rs
  • src/runtime/dns_jsc/dns.rs
  • src/runtime/node/node_fs.rs
  • src/runtime/node/path.rs
  • src/runtime/node/types.rs
  • src/runtime/socket/Listener.rs
  • src/runtime/test_runner/snapshot.rs
  • src/runtime/webcore/Body.rs
  • src/sql_jsc/postgres/DataCell.rs
  • src/which/lib.rs
  • test/js/bun/console/bun-inspect-table.test.ts
  • test/js/bun/util/which.test.ts
  • test/js/node/path/to-namespaced-path.test.js
💤 Files with no reviewable changes (2)
  • src/runtime/webcore/Body.rs
  • src/runtime/api/bun/spawn/stdio.rs

Comment thread scripts/build/rust.ts

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this PR and found no bugs (the two doc-pointer nits from the earlier pass were addressed in 850981a). Because this makes the entire workspace hard-depend on an alpha nightly compiler feature (-Zpolonius=next) and refactors borrow patterns across ~27 subsystems, a maintainer should sign off on the toolchain-policy decision.

What was reviewed:

  • Verified the dns.rs reorder (publish new_poll after init succeeds) is behavior-preserving on the failure path — value type is a raw pointer, swap_remove still cleans up the just-inserted slot.
  • Verified isolated_install.rs members borrow of scc_stack[start..] ends before scc_stack.truncate(start) at line 1613.
  • Checked elf.rs hoisted strtab borrow: dead before the write_u64_le(&mut self.data[..]) on the .interp match path, and the write region (section header table) does not overlap the string table.
  • Confirmed the build-config changes keep .cargo/config.toml and CARGO_ENCODED_RUSTFLAGS in sync across all targets including the new windows-msvc rustflags-only sections.
Extended reasoning...

Overview

This PR enables -Zpolonius=next (the alpha Polonius borrow checker) in both the ninja cargo edge (scripts/build/rust.ts) and every generated [target.*] section of .cargo/config.toml (scripts/build/cargo-config.ts), then removes the NLL "problem case 3" workarounds it makes unnecessary across 27 source files: raw-pointer reborrows in bun_which and open.rs, contains_key-then-get double lookups in snapshot.rs and WorkspacePackageJSONCache.rs, index/len round-trips in node:path, fmt.rs, linear_fifo.rs, ConsoleObject.rs, elf.rs, and others, plus a bool+out-param → Option<&[u8]> signature change in open.rs. Net: 31 files, +243/−312. Tests are added for Bun.which PATH-segment iteration, path.win32.toNamespacedPath branch coverage, and inspect.table column discovery order.

Security risks

None identified. Seven unsafe raw-pointer reborrow blocks are removed (net safety improvement). No new unsafe, no auth/crypto/permission surface touched. The changes are borrow-shape refactors that Polonius proves sound; each site was spot-checked for behavior preservation.

Level of scrutiny

High. While each individual site is a mechanical de-scaffolding, the aggregate is a workspace-wide toolchain-policy change: after this PR the codebase no longer compiles under the stock NLL borrow checker (linear_fifo.rs and others hard-require the flag). That couples every future rust-toolchain.toml bump to Polonius alpha stability. The PR description acknowledges this ("future nightly bumps may change acceptance at the margin") and the ~2% compile-time cost. This is exactly the kind of infrastructure decision a maintainer should explicitly approve rather than have land via automated review.

Other factors

  • All prior review feedback (CodeRabbit's two test nits, my two stale-comment nits) was addressed and resolved.
  • The dns.rs change is the only one with a visible statement reorder (publish-after-init instead of publish-before-init); I traced it and confirmed the map value type is *mut UvDnsPoll (Copy, no Drop), so swap_remove on the failure path behaves identically either way.
  • patchPackage.rs changes the helper return type from owned Vec<u8> to borrowed &ZStr and moves the .to_vec() to the four call sites — behavior-preserving, one fewer allocation on the borrowed path is irrelevant since callers immediately clone.
  • Test coverage was added for the three user-visible code paths most affected (which PATH iteration, toNamespacedPath branches, inspect.table column discovery), and the PR description reports passing test suites across the touched areas plus cargo miri on bun_collections.
  • The build-config half now emits windows-msvc [target.*] sections for the first time; I verified the docstring and inline comment were updated to match after my earlier nit.

Removing the flag from rust.ts already fails the build (bun_collections
no longer compiles under the stock borrow checker), but nothing guarded
the generated .cargo/config.toml, which plain cargo check, rust:check-all
and rust-analyzer rely on. Covers every target triple, including the
rustflags-only windows-msvc sections.
@robobun

robobun commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Follow-up on the latest review round:

  • Build-flag coverage: added test/internal/rust-polonius-flag.test.ts (cf16871), which pins the flag in both CARGO_ENCODED_RUSTFLAGS and every generated .cargo/config.toml target section.
  • dns.rs failed-init test: not adding one. The change moves the map-slot write from before to after uv_poll_init_socket; the slot type is a Copy raw pointer and the failure path swap_removes the slot either way, so the observable state after the function is identical before and after this PR (no behavior change to regress). Exercising it would also require making libuv's poll init fail on Windows from a test, which there is no hook for.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this PR and the bug-hunting pass found no issues. CodeRabbit's request for regression coverage of both flag paths looks addressed by the new test/internal/rust-polonius-flag.test.ts (cf16871) — that thread can likely be resolved.

Given this is a workspace-wide adoption of the alpha -Zpolonius=next flag plus a 27-file refactor across many subsystems (including removal of seven unsafe reborrow blocks and a write-ordering change in dns.rs), a maintainer sign-off still makes sense here.

What was reviewed: the build-script changes (rust.ts / cargo-config.ts) for flag consistency across ninja and .cargo/config.toml; the unsafe removals in which/lib.rs, open.rs, and Hardlinker.rs for behavior preservation; the dns.rs reorder (map slot now written only after uv_poll_init_socket succeeds — net map state unchanged on both paths); and the isolated_install.rs members borrow-vs-clone change for any intervening scc_stack mutation (none found).

Extended reasoning...

Overview

This PR enables -Zpolonius=next for every rustc invocation (both the ninja cargo edge via CARGO_ENCODED_RUSTFLAGS and every [target.*] section in the generated .cargo/config.toml, including newly-emitted windows-msvc sections) and removes ~27 files' worth of NLL borrow-checker workarounds that the flag makes unnecessary. The workarounds removed span raw-pointer reborrows under unsafe, contains-then-get double lookups, index/len round-trips, and one bool-plus-out-param signature. Four test files gain coverage (which PATH-segment iteration, path.win32.toNamespacedPath branches, console.table column discovery order, and a new hermetic test that pins the flag in both build-config sources).

Security risks

None identified. No auth/crypto/permissions code is touched. The unsafe blocks being removed were raw-pointer reborrows that existed solely to work around NLL problem-case-3; their removal reduces the unsafe surface rather than adding to it. The elf.rs change hoists an immutable strtab slice out of a loop but the write path still returns immediately after — no new aliasing.

Level of scrutiny

High. This is not a mechanical change: it commits the entire workspace to an alpha borrow-checker whose acceptance boundary can shift on future nightly bumps (the PR description acknowledges this). Several of the 27 source edits are pure scaffolding deletion, but others are structural — open.rs changes two function signatures from bool + out-param to Option<…>, patchPackage.rs changes two helpers from returning owned Vec<u8> to borrowed &ZStr (with .to_vec() moved to the four call sites), dns.rs reorders a map write relative to a fallible uv_poll_init_socket call, and isolated_install.rs replaces a defensive .to_vec() copy with a live borrow into scc_stack. Each of these is individually reviewable and I found no correctness issues, but the aggregate scope plus the ~2% compile-time cost and the toolchain-risk tradeoff is a maintainer decision.

Other factors

  • My two prior nits (stale docstring and dead grep hint) were fixed in 850981a.
  • CodeRabbit's 2026-08-10 request for hermetic test coverage of generateCargoConfig() / cargoBuildInvocation() is answered by test/internal/rust-polonius-flag.test.ts (cf16871): it decodes CARGO_ENCODED_RUSTFLAGS on \\x1f, asserts -Zpolonius=next for five build configs, parses the generated TOML per-triple, checks windows-msvc sections carry "-Z", "polonius=next" without link-arg=-fuse-ld=lld, and checks non-windows triples keep the lld link-arg. That thread is unresolved in the UI but substantively addressed.
  • The author explicitly noted they are waiting on a maintainer.

Comment thread test/internal/rust-polonius-flag.test.ts Outdated

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this PR and didn't find any bugs. Because it flips the whole workspace onto an alpha rustc feature (-Zpolonius=next) and reshapes borrow patterns across ~27 source files in many subsystems, a maintainer sign-off on the toolchain decision is still warranted.

What was reviewed:

  • Each removed workaround traced for behavior preservation — e.g. elf.rs strtab hoist (mutating path returns before the borrow is reused), dns.rs poll-entry write reorder (failure path still swap_removes the slot), patchPackage.rs &ZStr return (all callers immediately .to_vec()).
  • Build-config changes: flag pushed in both CARGO_ENCODED_RUSTFLAGS and every generated [target.*] section including new windows-msvc entries; docstring/comment now match.
  • The by_path_for_editor / by_fallback signature change from bool+out-param to Option<&[u8]> — all three call sites in detect_editor updated consistently.
Extended reasoning...

Overview

This PR enables -Zpolonius=next (the alpha Polonius borrow checker) for every rustc invocation — both the ninja CARGO_ENCODED_RUSTFLAGS path and the generated .cargo/config.toml per-target sections — and then deletes the NLL "problem case 3" workarounds that flag makes unnecessary across 27 Rust source files. The workarounds removed fall into a few classes: raw-pointer reborrows around loop-carried &mut (which/lib.rs, open.rs, Hardlinker.rs), contains_key-then-get double lookups (WorkspacePackageJSONCache, snapshot.rs), index/len round-trips instead of returned borrows (fmt.rs, path.rs, types.rs, Listener.rs, node_fs.rs, ConsoleObject.rs), and a bool+out-param signature collapsed to Option<&T> (open.rs). Three test files add coverage for the touched code paths (which PATH-segment iteration, console.table column discovery, path.win32.toNamespacedPath branches).

Security risks

None identified. Seven unsafe blocks are deleted (raw-pointer reborrows in which_win, which_for_spawn, and open.rs), which is a net reduction in unsafe surface. No new unsafe is introduced. The changes are refactors of borrow structure, not of validation, parsing, or trust boundaries.

Level of scrutiny

High. This is not a mechanical change: it makes the entire ~200-crate workspace hard-depend on an alpha nightly rustc feature (per the PR description, "future nightly bumps may change acceptance at the margin"), and it touches control flow in memory-sensitive code across the bundler, installer, ELF writer, DNS resolver, and node:path/fs. Each site is individually small and the bug-hunting pass found nothing, but the aggregate is a toolchain policy decision that a maintainer should explicitly accept — the author's own status update says "Waiting on CI and a maintainer."

Other factors

A maintainer (alii) has already engaged on the PR (requested deletion of the build-flag unit test, done in f4bf3ec), so there is active human review in progress. My two prior nit comments (stale grep hint in rust.ts, stale docstring in cargo-config.ts) were addressed in 850981a. All CodeRabbit threads are resolved. The dns.rs reorder was specifically justified by the author (Copy raw pointer, failure path swap_removes either way) and I agree the observable state is identical. Given the scope and the explicit toolchain dependency being introduced, deferring to the maintainer already in the loop is the right call.

@robobun

robobun commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 8:35 PM PT - Aug 10th, 2026

@robobun, your commit e43da769652d64c5538591870f5f4078b827c589 passed in Build #91877! 🎉


🧪   To try this PR locally:

bunx bun-pr 36951

That installs a local version of the PR into your bun-36951 executable, so you can run:

bun-36951 --bun

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this PR and didn't find any bugs. Because it makes -Zpolonius=next (an alpha borrow checker) a hard compile-time dependency for the whole workspace and reshapes control flow across ~27 Rust files, a maintainer sign-off on the toolchain commitment is still worthwhile.

What was reviewed

  • Each refactor site checked for behavior preservation vs. the deleted workaround (e.g. elf.rs strtab hoist stays valid because read_shdr only reads self.data; dns.rs reordered slot write is observationally identical on the failure path since swap_remove runs either way).
  • The seven deleted unsafe raw-pointer reborrows in which/lib.rs and cli/open.rs — replacements are straight &mut *buf reborrows with the same one-live-borrow-per-iteration invariant.
  • cargo-config.ts / rust.ts: flag reaches every rustc invocation (ninja, plain cargo, rust-analyzer, windows-msvc targets); the two prior doc-comment nits from this bot were addressed in 850981a.
Extended reasoning...

Overview

This PR enables -Zpolonius=next in every Rust compilation path (ninja's CARGO_ENCODED_RUSTFLAGS in scripts/build/rust.ts and every [target.*] section of the generated .cargo/config.toml, including new rustflags-only sections for the windows-msvc triples), then deletes the NLL-problem-case-3 workarounds it makes unnecessary across 27 source files in src/. The workspace no longer compiles under the stock borrow checker after this change. Net diff is roughly +243/-312; three new tests cover console.table column discovery, Bun.which PATH-segment iteration, and path.win32.toNamespacedPath branch coverage.

Security risks

None identified. The change removes seven unsafe raw-pointer reborrow blocks (a net safety improvement) and does not touch auth, crypto, TLS, or input-validation paths. The refactors are borrow-shape changes, not logic changes; each site was checked against its predecessor for identical observable behavior.

Level of scrutiny

High — not because any individual site is risky, but because (a) the change spans many unrelated subsystems (bundler, package manager, node:fs/path, DNS poll, ELF writer, sockets, postgres DataCell, test-runner snapshots), so a subtle behavior drift in one wouldn't be caught by the others' tests, and (b) adopting an alpha nightly borrow checker as a hard workspace dependency is a toolchain-policy decision: future rust-toolchain.toml bumps may change what polonius accepts at the margin, and someone needs to own that risk. The PR description acknowledges this and the ~2% cold-check compile-time cost.

Other factors

  • My two prior inline nits (stale grep hint in rust.ts, contradictory docstring in cargo-config.ts) were fixed in 850981a and verified in the current diff.
  • A maintainer (alii) has already engaged (requested deletion of the build-flag unit test, done in f4bf3ec).
  • The bug-hunting system found nothing this run. Candidate concerns I ruled out: the elf.rs strtab hoist looked like it might alias a mutable borrow inside the loop, but read_shdr takes &self and only reads self.data, so the shared borrow is fine and the section-header write happens after the loop returns; the dns.rs reorder leaves an uninitialized value_ptr slot only until the very next line writes it, and the failure path's swap_remove(&fd) clears the slot regardless of whether it was written, so no dangling entry escapes.
  • CI build #91766 is in flight for the latest merge-from-main; the earlier build's one red lane was a known main break (#36986) unrelated to this PR.

Polonius alpha is the default borrow checker on nightlies from
2026-08-06 on (rust-lang/rust#159343), so the workspace now builds on
the pinned toolchain with or without -Zpolonius=next. The flag stays in
rust.ts and the generated .cargo/config.toml so a future toolchain bump
cannot silently change which borrow checker builds bun if upstream
toggles the nightly default while the alpha bakes.

The new nightly bundles LLVM 23, which trips the
rustc-no-regular-lto-summary workaround's re-check threshold. That
fix-up has been unreachable since every LTO platform moved to ThinLTO
(rustLtoLinkInputs returned early whenever cfg.lto was set, and
crossLangLto implies lto), so take the cleanup path the entry
prescribes: delete rust-lto-fix-cli.ts, the rust_lto_fix rule and
rustLtoLinkInputs, unwrap its call sites, drop the llvm-tools component,
and remove the entry. rust-lld and llvm-objcopy come from the rustc
component and the clang toolchain respectively, so nothing else used
llvm-tools.

The four GitHub workflows that pin RUSTUP_TOOLCHAIN are kept in sync
with rust-toolchain.toml.
@robobun robobun changed the title Enable -Zpolonius=next and remove NLL borrow-checker workarounds Bump Rust to nightly-2026-08-11 (polonius alpha) and remove NLL borrow-checker workarounds Aug 11, 2026
@robobun

robobun commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator Author

Scope change, per discussion with @alii: this PR now also bumps the toolchain (750fa2d).

Polonius alpha is the nightly default since nightly-2026-08-06 (rust-lang/rust#159343), so rather than enabling it on the old pin, the branch moves rust-toolchain.toml and the four RUSTUP_TOOLCHAIN workflow pins to nightly-2026-08-11. -Zpolonius=next stays explicit so a later bump cannot change the borrow checker under us if upstream toggles the nightly default during the bake. The new nightly carries LLVM 23, which tripped the rustc-no-regular-lto-summary workaround's re-check; that fix-up had been unreachable since the ThinLTO switch, so the commit takes the cleanup the entry prescribes instead of bumping its threshold. Details and local verification are in the updated PR description; CI is re-running on the new toolchain.

@robobun robobun changed the title Bump Rust to nightly-2026-08-11 (polonius alpha) and remove NLL borrow-checker workarounds Enable -Zpolonius=next and remove NLL borrow-checker workarounds Aug 11, 2026
@robobun

robobun commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator Author

Reverted the toolchain bump (750fa2d) in 24ac600. It breaks the windows-x64 cross build at link time (build 91851):

rust-lld: error: undefined symbol: WTF::openLatin1ContextAwareUTextProvider(...)
rust-lld: error: undefined symbol: WTF::openUTF16ContextAwareUTextProvider(...)
>>> referenced by cache/webkit-447082ab68972787-windows-lto/.../JavaScriptCore.libUnifiedSource-tools-1.cpp.obj

Cause: the cross-language LTO link on Windows is driven by rust-lld from the Rust toolchain, which the bump moves to LLVM 23, while the prebuilt WebKit LTO bitcode is still produced by the LLVM 21 clang. main at this branch's merge-base (c63dc64, same WebKit) links fine on the same lane with the 2026-07-20 nightly's rust-lld, and the LTO fix-up code the bump removed had an explicit windows early-return, so the skew is the only delta. That is a toolchain-bump problem independent of this PR, so it is better handled in its own PR (cherry-pick 750fa2d to restart from it). The polonius-is-default-now observation from its commit message still holds and is the reason the flag here is low risk; the flag stays for now since the pinned 2026-07-20 nightly still needs it.

Branch is back to the shape that was green on every lane, plus the main merge. PR title restored to match.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this revision and the bug-hunting pass found no issues. Given the scope — a workspace-wide borrow-checker switch plus ~27 rewritten sites across bundler/install/DNS/node-compat and the removal of seven unsafe reborrow blocks — a maintainer sign-off is still warranted.

Checked: elf.rs strtab hoist (shared borrow dead before the &mut self.data write on the .interp path); dns.rs poll-entry write reorder (slot is swap_removed on the failure path either way, so post-state is identical); path.rs to_namespaced_path_windows_t now indexes resolved instead of bufresolve_windows_t returns &buf[0..len] so bytes match; which_win / open.rs reborrow deletions return immediately on hit so only one &mut buf is ever live.

Extended reasoning...

Overview

This PR adds -Zpolonius=next to every rustc invocation (ninja edge in rust.ts and every [target.*] section in the generated .cargo/config.toml, including new rustflags-only sections for windows-msvc triples) and deletes the NLL workarounds that flag makes unnecessary: seven unsafe raw-pointer reborrow blocks (which/lib.rs, cli/open.rs), double-lookup patterns (snapshot.rs, WorkspacePackageJSONCache.rs), index/len round-trips (fmt.rs, path.rs, linear_fifo.rs, elf.rs, node_fs.rs, Listener.rs, types.rs, DataCell.rs), a bool-plus-out-param signature (open.rs), an owning Vec<u8> return that becomes &ZStr (patchPackage.rs), and assorted dead scaffolding. Tests are added for Bun.which PATH-segment iteration, path.win32.toNamespacedPath branch coverage, and console.table column-discovery order. A toolchain bump to nightly-2026-08-11 was attempted (750fa2d) and reverted (24ac600) after a Windows cross-LTO link failure; the branch is back to enabling the flag on the existing pin.

Security risks

None identified. The change removes unsafe blocks rather than adding them; the deleted reborrows were already sound-by-construction (each returned immediately on hit so only one &mut was live), and their safe replacements are strictly narrower. No auth, crypto, network parsing, or untrusted-input paths are touched in a way that changes validation.

Level of scrutiny

High. This flips the borrow checker for the entire workspace to a nightly alpha that upstream explicitly reserves the right to toggle back off (the PR description itself cites two P-high unsoundness reports filed within days of the nightly default flip). It touches 27 source files across many subsystems, changes build-script behavior for every target, and removes unsafe code whose correctness argument was local and now depends on the new checker's acceptance. Each individual site is a small mechanical simplification, but the aggregate is an infrastructure decision a maintainer should own.

Other factors

  • A maintainer (alii) is already engaged (requested and got the rust-polonius-flag.test.ts deletion, discussed the toolchain-bump scope).
  • My two prior inline nits (stale grep hint in rust.ts, stale docstring in cargo-config.ts) were addressed in 850981a.
  • The PR description states the previous revision (same src changes, old nightly + flag) was green across the full CI matrix; the current head (e43da76) is a CI retrigger after the toolchain-bump revert.
  • The dns.rs reorder and the patchPackage.rs return-type change are the only sites where control flow / ownership visibly moved rather than just collapsing an index round-trip; both were traced and are behaviorally equivalent (the dns slot is a Copy raw pointer swap-removed on failure either way; patchPackage callers now .to_vec() at the four return sites instead of inside the helper).

Comment thread src/bundler/Chunk.rs
Comment on lines +312 to 324
for other in chunks.iter() {
if let Content::Javascript(js) = &other.content {
if other.entry_point.is_entry_point()
&& other.entry_point.entry_point_id() == entry_point_id
{
let css_chunk_indices = &js.css_chunks[..];
if !css_chunk_indices.is_empty() {
let idx = css_chunk_indices[0] as usize;
return Some(&mut chunks[idx]);
}
break;
}
}

@panstromek panstromek Aug 12, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code compiles on stable without Polonius. I also tried to test the refactor on the first version of this code in the repo and it also compiles on stable. Do you know what was the original motivation for this workaround? Did the code look differently when it was introduced (maybe that point is not in git history anymore)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants