Remove dead code: 49 trait impls nothing uses, across 12 crates - #43664
Conversation
rustc's dead_code lint exempts trait impls, so the workspace lints never report an impl that no caller and no bound needs. A relink of the debug build with --gc-sections shows which impl methods the linker drops from every codegen unit. Each impl here has no live code in that link, and the workspace still compiles without it on all 12 targets, in the release profile, and with --tests. Also removes hash_array_list in src/css/generics.rs. Its only caller was the removed CssHash impl for ArrayList.
|
Status: ready for review. How to check a removal:
Self-reviewed: the review asked for a smaller shape. I put back 8 impls that open PRs use (#39497, #38692, #36605, #40708, #40372), 19 std ergonomics impls on shared containers that need a maintainer decision, and 21 impls that docs describe. The PR body lists each group. This PR is perishable. Main has no merge queue, so a PR that starts to use one of these impls after 2026-09-21 06:00 UTC would break main when it merges after this one. |
|
Understand this PR’s impact Explore downstream dependencies and potential security impact with Blast Radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: oven-sh/bun/.coderabbit.yaml Review profile: ASSERTIVE Plan: Essentials Run ID: 📒 Files selected for processing (25)
💤 Files with no reviewable changes (25)
Included review availability: Your plan provides up to 10 included reviews per hour; 5 remain after this review. WalkthroughThis PR removes unsupported or redundant trait implementations and conversion paths across core utilities, bundler and collection types, CSS types, JavaScript bindings, installation code, and runtime code. ChangesTrait implementation removals
Priority: ➖ Normal 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Comment |
|
Updated 12:10 AM PT - Sep 21st, 2026
✅ @robobun, your commit 85c4883521d5839e3403b1eb310f5a219c193a31 passed in 🧪 To try this PR locally: bunx bun-pr 43664That installs a local version of the PR into your bun-43664 --bun |
…hs (#43840) ### Problem - `src/codegen/generate-classes.ts` still has the DOMJIT emitter (C++ signatures, `WithoutTypeChecks` wrappers, result-type asserts, Rust thunks). None of it can run: `define()` in `class-definitions.ts` has set `DOMJIT = undefined` on each field since #14005 (2024-09), and all 31 `*.classes.ts` files go through `define()`. - Nothing is left for it to bind: #35002 deleted each Rust `*_without_type_checks` fast path, and #36756 and #36903 removed the C++ leftovers. - A `DOMJIT:` option in a `.classes.ts` file does nothing. Five exist. ### Fix - Delete the emitter, the option type, the strip in `define()`, the five ignored blocks, and the stale notes next to them: 6 files, 273 lines removed. - The generated output is the same except for 94 empty `#if BUN_DEBUG`/`#endif` pairs in `ZigGeneratedClasses.h` and three DOMJIT-only `#include`s in `ZigGeneratedClasses.cpp`. `generated_classes.rs` is byte-identical. - Verified: the generator run before and after, `bun bd`, `tsc -p src`, and the tests in the Notes. - Self-reviewed: 13 concerns raised, 13 addressed (Notes). ### Background - DOMJIT is the JavaScriptCore fast path that lets the JIT call a host function with unboxed, type-checked arguments. The generator could emit a C++ signature and a Rust thunk for each method. - The hand-written DOMJIT users (`Buffer.alloc`, `performance.now`, `bun:ffi`) do not use this generator. They stay. - Earlier sweeps (#39249, #41169) called this removal a design call. This PR asks for that call alone. ### Downsides - To turn generated DOMJIT on again, a person must restore these paths from git history and write the Rust fast paths again. - No runtime cost found. Checked: the generated `.cpp`, `.h` and `.rs` differ only as Fix says. <details><summary>Notes</summary> **Removed** - `generate-classes.ts`: `DOMJITName`, `argTypeName`, `DOMJITType`, `DOMJITFunctionDeclaration`, `DOMJITFunctionDefinition`, `domJITTypeCheckFields`, `RustDOMJITArgType`. Also the `DOMJIT` branches in `zigExportName`, `propRow`, `renderDecls`, the `expectedResultType` asserts in the host-function wrapper, both Rust thunk loops, and the `DOMJITAbstractHeap.h`, `FrameTracers.h`, `DFGAbstractHeap.h` includes of the generated prologue. The destructures that named `DOMJIT` also lose the unused `cache` and `value` bindings. - `class-definitions.ts`: the `DOMJIT?:` option type and the two `.map()` calls in `define()` that erased it. - Ignored live blocks: `Crypto.randomUUID`, `Crypto.timingSafeEqual` (`crypto.classes.ts`), `ServerWebSocket.publishText`, `publishBinary` (`server.classes.ts`), `TextDecoder.decode` (`encoding.classes.ts`). - Stale notes: the commented-out `// DOMJIT: {` blocks with their crash notes on `sendText`, `sendBinary` (2023) and `getRandomValues` (#13470, 2024-08), and three orphan "DOMJIT fast path" comments in `src/runtime/webcore/Crypto.rs` whose functions #35002 deleted. **Self-review, and what changed because of it** - The first draft mixed this design call with 22 log scopes and seven fields. It now ships alone, with its history in the body. - The leftover DOMJIT notes (`Crypto.rs`, the commented-out blocks) are folded in. - Three deletions that open PRs carry were dropped (#40232, #41385). - Five items that open PRs use were taken out of the held branch (#43283, #31855, #42819, #39222, #37518). Two `builtins.d.ts` lines were dropped too: `src/codegen/replacements.ts` defines `$ImportKindLabelToId`, so that declaration is live. **History** - #13470 (2024-08) turned DOMJIT off for `getRandomValues`. #14005 (2024-09) added the strip in `define()` as the repair for the #14001 segfault. #35224 found the cause (the wrappers returned `{ result }` with a null exception slot) and tried to repair the generated wrappers. A stale-PR cleanup closed it with no maintainer comment. #35002 deleted the Rust fast paths, so the option cannot come back without new native code. **Kept on purpose** - The hand-written `DomCall` path for `bun:ffi` (`src/jsc/host_fn.rs`, `src/runtime/ffi`), the C++ DOMJIT signatures in `JSBuffer.cpp`, `JSPerformance.cpp`, `NodeVM.cpp`, `JSSQLStatement.cpp`, and `test/js/bun/jsc/domjit.test.ts`. **Tests (debug build)** - `test/js/web/encoding/text-decoder.test.js` 127 pass, `test/js/web/web-globals.test.js` 23 pass, `test/js/bun/util/randomUUIDv5.test.ts` 40 pass, `test/js/bun/websocket/websocket-server.test.ts -t sendBinary` 5 pass. - `websocket-server.test.ts -t "publish|send"`: 44 pass, 4 time out near 19 s under debug+ASAN. A debug binary built from main fails the same 4. - `test/js/bun/jsc/domjit.test.ts`: 40 pass, 10 time out at the 100k-iteration sizes. A debug binary built from main gives the same 40/10. **The rest of this sweep** - Relink of the debug build with `-Wl,--gc-sections`, then the DWARF line table of the result: 2,290 of 31,118 Rust `fn`s have no live line. After `cargo check` on six targets only three `pub fn`s had no caller anywhere. The 96 trait impls with no caller are the ones #43664 kept on purpose. - clang `-fsyntax-only -Wunused-function -Wunused-template -Wunused-member-function -Wunused-macros` over bun's 177 C/C++ translation units (the build passes `-Wno-unused-function`): ten hits. Open PRs delete them, or an `#if` uses them. - oxlint `no-unused-vars` over `src/js`, `src/codegen`, `scripts`, `packages`. cargo's `unused_dependencies` lint over four targets. A scan for commented-out blocks (62 lines in the repo). Nothing new that is certain. - Each deletion was compared with the diffs of the 36 open dead-code PRs. Left out because an open PR has it: `Bun__napi_get_version` (#40232), two unused generator locals (#41385). **Verified and held for the next run** (branch `robobun/9a0817f5/dead-code-scopes-fields`, 25 files, 81 lines removed) - 20 `declare_scope!` scopes that nothing logs to: `JSC`, `STR`, `Bundle` and `scan_counter` (outer pair), `Store`, `hot_reloader`, `CLI`, `LibUVBackend`, `ResolveInfoRequest`, `GetHostByAddrInfoRequest`, `CAresNameInfo`, `GetNameInfoRequest`, `CAresReverse`, `CAresLookup`, `quic_session`, `PathWatcherManager`, `S3Client`, `S3Stat`, `AWS`, `uws` (`uws_sys/socket.rs`). rustc does not lint an item that another crate's macro expands. - Fields: `Runtime::Features.jsx_optimization_inline` with the local `can_be_inlined`, `DebugOptions.output_file`, `ArchiveIterator.filter`, `PackageManager.total_scripts`, `CommandLineArguments.lockfile`, `ArgumentsSlice::_vm`. Also `struct_Channeldata` and two empty modules in `napi_body.rs`. - It passed `rust:check-all` (12 targets), release and `--cfg bun_debug --cfg bun_asan` checks on linux, windows and darwin, and `cargo check --tests` before the trim below. The trimmed commit passes `cargo check` on linux. - Taken out because an open PR uses the item: `BundleOptions.code_coverage` (#43283 reads it), scope `ModuleLoader` (#31855), scope `PROCESS` (#42819, #39222), `impl Clone for JsPoster` and its vtable slot (#37518 rewrites the vtable). **Follow-up candidates, not verified dead** - `Parser Options.preserve_unused_imports_ts` is never `true`. tsconfig `importsNotUsedAsValues` is parsed into `preserve_imports_not_used_as_values` but never reaches the parser, in the released binary too. This looks like a missing feature. - `completions/bun-cli.json` (4,513 lines) and `misctools/generate-cli-completions.ts` (728 lines): nothing in the repo reads the JSON, but feature PRs still edit it by hand. - `bench/snippets/runner-entrypoint.js` (244 lines): no reference, first line says "this isn't done yet", last real change 2023-05. - Ten `impl_timer_owner!` accessors have no caller because `dispatch.rs` recovers the owner with its own `owner!` macro. Which mechanism stays is a design call. - `mordant-baseline.toml` still counts about 170 `unused_pub` findings (`sys/lib.rs` 56, `libuv_sys/libuv.rs` 41, `errno/windows_errno.rs` 31). `bun run rust:mordant` names them. </details>
Problem
dead_codelint exempts trait impls, so the workspace's deny lints never report them.Fix
hash_array_list(src/css/generics.rs), whose only caller was a removed impl. 25 files, 436 lines removed.--gc-sections, an impl block with no kept function address is a candidate. The compiler decides next: an impl that a bound, a supertrait, another target, or a unit test needs does not compile away, so it stays. That kept 128 of 233 candidates.bun run rust:check-all(12 targets),cargo check --release(3 targets),cargo check --tests,cargo clippy,bun bd, 11 test files, and a scan of all open PRs for users.Background
--gc-sectionsdrops every function with no caller. Callers in generic instantiations and macro-expanded code count.cargo checkcovers the other targets.Notes
Removed impls, by file
src/ast/e.rsimpl From<f64> for Numbersrc/bun_alloc/baby_vec.rsimpl<'a, 'b, T: Copy> Extend<&'b T> for BabyVec<'a, T>impl<'a, 'b, T> IntoIterator for &'b BabyVec<'a, T>impl<'a, 'b, T> IntoIterator for &'b mut BabyVec<'a, T>impl<'a, T> core::borrow::Borrow<[T]> for BabyVec<'a, T>impl<'a, T> AsRef<[T]> for BabyVec<'a, T>src/bun_alloc/lib.rsimpl<const N: usize> BSSAppendable for [&[u8]; N]src/bun_core/atomic_cell.rsunsafe impl<U> Atom for *const Usrc/bun_core/fmt.rsimpl From<InvalidCharacter> for crate::CrateErrorsrc/bun_core/output.rsimpl<T: fmt::Display> FmtTuple for &[T]src/bundler/Chunk.rsimpl core::ops::Index<usize> for CompileResultSlotssrc/bundler/bundle_v2.rsimpl Ord for StableRefimpl PartialOrd for StableRefsrc/collections/array_hash_map.rsimpl<K, V, C, A: MapAllocator> ArrayHashMapExt for ArrayHashMap<K, V, C, A>src/css/generics.rsimpl<'bump, T: DeepClone<'bump>> DeepClone<'bump> for &'bump Timpl<T: CssEql, const N: usize> CssEql for [T; N]impl CssHash for ()impl<T: CssHash, const N: usize> CssHash for [T; N]impl<'bump, T: CssHash> CssHash for ArrayList<'bump, T>impl CssHash for bun_ast::Locimpl<T: IsCompatible, const N: usize> IsCompatible for [T; N]impl<'bump, T: ToCss> ToCss for ArrayList<'bump, T>impl ToCss for CustomIdentimpl ToCss for DashedIdentimpl ToCss for Identsrc/css/media_query.rsimpl crate::generic::ToCss for MediaListsrc/css/properties/mod.rsimpl crate::generics::ParseWithOptions for css_values::length::Lengthimpl<S, const P: u8> crate::generics::Parse for GenericBorder<S, P>src/css/rules/supports.rsimpl crate::generics::CssEql for SupportsConditionimpl css::generic::ToCss for SupportsConditionsrc/css/selectors/parser.rsimpl<Impl: SelectorImpl> Default for GenericSelector<Impl>impl<Impl: BunSelectorImpl> CssEql for GenericSelectorList<Impl>impl<Impl: BunSelectorImpl> CssHash for GenericSelectorList<Impl>impl<Impl: BunSelectorImpl> CssEql for GenericComponent<Impl>impl<Impl: BunSelectorImpl> CssHash for GenericComponent<Impl>src/css/values/alpha.rsimpl crate::generics::CssHash for AlphaValuesrc/install/lockfile/lockfile_json_stringify_for_debugging.rsimpl<const N: usize> JsonScalar for &[u8; N]src/install/resolution.rsimpl Default for Tagsrc/install_types/resolver_hooks.rsimpl<I: VersionInt> Default for ResolutionValue<I>impl Default for Resolutionsrc/jsc/JSPropertyIterator.rsimpl IntoIterObject for *const JSObjectsrc/jsc/JSValue.rsimpl FromAny for ()impl FromAny for &strimpl<T: FromAny> FromAny for Option<T>src/jsc/host_fn.rsimpl<T> IntoHostConstructReturn for *mut Tsrc/react_compiler/hir/mod.rsimpl From<FloatValue> for f64src/runtime/bake/DevServer.rsimpl From<OpaqueFileId> for OpaqueFileIdOrOptionalsrc/runtime/error.rsimpl From<Error> for bun_jsc::CrateErrorsrc/tcc_sys/tcc.rsimpl<ErrCtx> Default for Config<ErrCtx>Candidates that stayed (184 of 233)
SmallListimpls (Deref,DerefMut,IntoIteratorx2,FromIterator,Extend) for markdown: emit balanced tags when an emphasis run matches more than 6 times #39497, css: do not add transition entries the declaration already lists #38692 and jsc: cache resolved source-preview lines for error code frames #36605.Default for Wyhashfor One working directory: bun_core::cwd, read once, followed by chdir #40372.AsRef<[u8]> for Utf8Bytesfor crash_handler: report Rust panics through crash_handler() so --watch restarts and other threads wait #40708. This branch merged with markdown: emit balanced tags when an emphasis run matches more than 6 times #39497, css: do not add transition entries the declaration already lists #38692 and crash_handler: report Rust panics through crash_handler() so --watch restarts and other threads wait #40708 passescargo check --workspace. jsc: cache resolved source-preview lines for error code frames #36605 and One working directory: bun_core::cwd, read once, followed by chdir #40372 conflict with main on their own.Interned(Deref,AsRef<[u8]>,Borrow<[u8]>),ZStr(AsRef<ZStr>,PartialEq<[u8]>,PartialEq<&[u8; N]>),StoreStr(PartialEq<[u8]>),StoreSlice(AsRef<[T]>,From<&[T]>,From<ArenaVec>),IntoIterator for &HashMapand&mut HashMap,BoundedArrayAligned(Deref,DerefMut,fmt::Write),AsRef<[T]> for RawSlice,Deref for ArenaString(also the only caller ofArenaString::as_str),Display for GenericIndex,Display for CowSliceZ.ArrayHashContext<Box<[u8], A>> for BoxedSliceContext<C>(its doc comment records it as the fix for lookups reached throughDeref),Default for Ordinal(the default isINVALID, not 0),IntoLogWrite for &mut W,ThrowFmtArgs for fmt::Arguments,PoolStorage for UnwiredStorage,StringBuilder for semver_string::Builder,fmt::Write for FmtAdapter,AsFd for &File, and the css blanket impls that thecss_derivemodule docs and theParsesection ofsrc/css/generics.rsname (Option<T>,SmallList,bool,str,[u8],[T],Size2D,Rect).Method details
build.ninjaplus-Wl,--gc-sections.-rdynamic,--dynamic-listand the version script stay, so the exported NAPI/V8/uv surface is still a root.llvm-nmlists the 669,524 kept function symbols andllvm-symbolizermaps each address tofile:line. An impl block is a candidate when no kept address falls inside it and a rust-analyzer SCIP index shows that linux compiles every method in it.macro_rules!type list generates are not candidates, so unused arms of such lists are not in this PR.cargo check --workspace --keep-going --message-format=json, put back each impl that an error names, repeat until clean. Targets in the loop: linux-gnu, windows-msvc, darwin, freebsd, android, musl, then--tests.cargo check --workspace --testsreports one error,src/bundler/options.rs:2328(expected ContentHash, found integer). Clean main has the same error. This PR does not touch it.ffi.test.js"FTL-compiled call site" (5 s timeout under ASAN), and twoserve.test.tstests that depend on the container (root can bind low ports, loopback check).Other scans in this run
.rsfiles outside every mod tree, unused Cargo dependencies, extern declarations without a Rust caller, commented-out code in C++/TS, unusedsrc/jsmodules and internal exports, linker-dropped C++ functions insrc/jsc/bindings.Follow-up candidates, not in this diff
Debugimpls that nothing formats. They are a debugging aid, so this PR keeps them.Clone for JsPosterhas no caller, and it is the only reader of theJsPosterVTable::cloneslot. Removing both is a small refactor insrc/event_loopandsrc/jsc/VmHandle.rs.Display for ErrorLocation(src/css/error.rs) has no caller, and it is the only reader ofErrorLocation::filename.Bun__napi_get_versioninsrc/jsc/bindings/napi.cpphas no caller.<Type>Class__callshims for classes that setcall: trueandnoConstructor: true(the sevenExpect*matchers injest.classes.ts). Nothing references those shims.