Skip to content

Remove dead code from the bundler, the JS parser, Glob.scan, bun --help, and bun_install - #44687

Draft
robobun wants to merge 1 commit into
mainfrom
robobun/fd900f23/dead-code-sweep
Draft

robobun wants to merge 1 commit into
mainfrom
robobun/fd900f23/dead-code-sweep

Conversation

@robobun

@robobun robobun commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator

Behaviour change: none

Problem

  • Seven groups of code in 17 files cannot run, or compute a value that nothing reads.
  • No lint reports them. Each has a textual use that rustc accepts: a comparison with a variant that nothing constructs, a flag with one value, a parameter with one argument value.

Fix

  • Delete the seven groups: 213 lines removed, 41 added. The Notes give each group with its proof.
  • Each proof is local: a variant with no constructor, a field with one value, a parameter with one call site, a value that is created and dropped without a use.
  • Verified: bun bd, bun run rust:check-all (12 targets), cargo check with --all-targets, the debug cfgs and --release, cargo clippy, and the tests in Notes.

Background

  • The workspace denies dead_code. But rustc counts e == Error::EmptyAST as a use of the variant, and a store as a use of a field.
  • esbuild warns about a return that a line break separates from its expression. Bun's parser carries the option that turns such warnings off, and no caller turns them on.
  • The first list had about 140 candidates. A comparison with the open pull requests took out each one that another pull request already deletes or rewrites (Notes).

Downsides

  • None found. Checked each removed name with rg over src/, packages/ and build/debug/codegen/, and each removed branch for a second path that reaches it.
Notes

Removed, one group each

  1. parse_task::ResultValue::Empty and bun_bundler::Error::EmptyAST (30 lines). EmptyAST has no constructor: the only expression that names it is if e == crate::Error::EmptyAST in ParseTask.rs, and no From impl or name table produces it. That if held the one constructor of ResultValue::Empty. So the variant, its three match arms (source_index, drop_result_owned_fields, on_parse_task_complete) and the error variant go.
  2. esbuild's "weird code" warnings in the JS parser (45 lines). Options.suppress_warnings_about_weird_code is true in Options::default(), Options::init, the literal in src/bundler/transpiler.rs, and the three assignments in function_identities.rs, sema/mod.rs and pm_diff_normalize.rs. clone_for_lazy_export copies it. Its two readers are the ASI warning after a bare return (parse/mod.rs) and an empty !a instanceof b block whose body is a TODO comment (parse_suffix.rs). With them go P::latest_return_had_semicolon (its one reader was the ASI block), the local return_without_semicolon_start, and the option.
  3. help_command::Reason::InvalidCommand (31 lines, src/runtime/cli/mod.rs). Nothing constructs it. exec() and the two other callers pass Reason::Explicit. The enum, the reason parameter, the Uh-oh not sure what to do with that command arm and the exit(1) branch go. print_cli_helptext! loses its printer parameter, because pretty! is its one printer now.
  4. The arena of Glob.scan and Glob.scanSync (27 lines, src/runtime/api/glob.rs). Each call created a bun_alloc::Arena, passed it down to ScanOpts::parse_cwd, where the parameter is _arena, and dropped it. A comment called it vestigial.
  5. impl Default for linker_graph::File (14 lines). Nothing calls it. LinkerGraph::load creates the rows zeroed, and MultiArrayList<File> has no File: Default bound.
  6. HostProvider::from_shortcut(.., with_colon) (12 lines, src/install/hosted_git_info.rs). One call site, and it passes false. The function now has the shape of from_domain next to it.
  7. keep_catalog_reference in PackageJSONEditor::edit (11 lines). The flag can be true only when manager.subcommand == Subcommand::Update. Its one reader is the last operand of a condition that has manager.subcommand != Subcommand::Update before it.

Open pull requests

Verified and left out, because an open pull request deletes the same lines

Leads, not proved to the end

  • LinkerOptions.mode is always LinkerOptionsMode::Bundle, so should_strip_exports in convertStmtsForChunk.rs is always true. The removal dedents about 100 lines in a file that 18 open pull requests touch.
  • ServerComponentParseTask::Data::ClientEntryWrapper is constructed only as the placeholder of impl Default. The removal needs a constructor in place of that impl.
  • NetworkTask.apply_patch_task is written and never read. PatchTask::new_apply_patch_hash, which builds the value, calls compute_cache_dir_and_subpath, so its side effects need a review first.
  • The "merge adjacent @layer rules" block of findImportedFilesInCSSOrder.rs never runs, because wip_order is always empty there. esbuild's version of the block appends each entry to wip_order. This is a missing step of the port, not dead code.

How the candidates were found

  • Readers went through 24 chunks of Rust (about 180,000 lines in src/install, src/runtime/cli, src/runtime/api, src/bundler and part of src/runtime/node) and listed about 140 places where a value has one possible state.
  • A rustc driver recorded each field read and write, each variant construction and the constant arguments of each call in the workspace. It found the write-only fields and the variants without a constructor. Its output did not survive a reset of the work container, so each group above was proved again by hand on current main.
  • Not covered in this run: src/runtime/webcore, src/runtime/server, the rest of src/js_parser, src/http, src/runtime/shell, src/sql, src/css, the C++ bindings and src/js.

Verification

The base is main at bbdc5a5.

  • bun bd passes (debug build with ASAN). bun run rust:check-all passes for 12 of 12 targets. cargo check --workspace passes with --all-targets, with --cfg bun_asan --cfg bun_debug --cfg socket_fault_injection, and with --release. cargo clippy --workspace and cargo fmt --all --check are clean.
  • Tests with the debug build, no failed assertion: test/bundler/bundler_edgecase.test.ts (182 pass), test/bundler/transpiler/transpiler.test.js (237 pass), test/cli/bun.test.ts (39 pass), test/cli/install/bun-update.test.ts (159 pass), test/cli/install/hosted-git-info/ (673 pass), test/cli/install/catalogs.test.ts (88 pass), test/js/bun/glob/scan.test.ts (199 pass), match.test.ts (28 pass), path-length.test.ts (6 pass), proto.test.ts (1 pass).
  • Eight tests hit their time limit with the debug build and nothing else failed:
    • Six tests of scan.test.ts compare Glob.scan with fast-glob over the checkout and have a 30 s limit. Under the debug JavaScriptCore, fast-glob alone needs 156 s and 168 s for the two patterns. Glob.scan needs 3.4 s and 9.4 s and returns the same number of entries (11,552 and 12,698). With the release binary the same comparison takes 3 s.
    • Glob.match > braces (match.test.ts) takes 5.9 s against the 5 s default. It passes with --timeout. This PR does not touch Glob.match.
    • One test of catalogs.test.ts took 5.01 s in the full run. Alone it passes in 2.5 s.
  • Probes: Glob.scan and Glob.scanSync give identical results with the debug build and with the release binary for four patterns, each with a cwd string, a cwd option, dot and absolute, without an argument, and with an invalid cwd. bun --help, bun help and bun --help --all print the help and exit 0.

@robobun

robobun commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator Author

Status: draft while a self-review of the diff runs.

How each removal was checked: every removed name was searched in src/, packages/ and build/debug/codegen/, and each removed branch was traced to its only writers and callers (the proofs are in the Notes of the description). The branch builds with bun bd, passes bun run rust:check-all on 12 targets, and the test files listed in the description pass with the debug build.

@robobun

robobun commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 3:18 AM PT - Oct 7th, 2026

✅ @robobun, your commit 5b23e7a5dc4861d757fe0b0c62033184f8f09983 passed in Build #123735! 🎉


🧪   To try this PR locally:

bunx bun-pr 44687

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

bun-44687 --bun

This branch has not been deployed

No deployments
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.

2 participants