fix(renamer): prevent renaming symbols when there no conflicts#7936
fix(renamer): prevent renaming symbols when there no conflicts#7936hyf0 merged 18 commits intorolldown:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes issue #6586 to prevent renaming symbols when there are no conflicts. The main improvement is in the renamer logic to avoid unnecessary symbol renaming, using a more targeted reference-based approach for handling shadowing conflicts instead of preemptively renaming all top-level symbols.
Changes:
- Refactored renamer logic to allow entry module symbols to use original names freely, with reference-based renaming for nested bindings
- Added
reference_idtracking toMemberExprRefandMemberExprRefResolutionfor better conflict detection - Updated oxc dependency to a git branch for new semantic analysis features
Reviewed changes
Copilot reviewed 30 out of 31 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
crates/rolldown/src/utils/renamer.rs |
Simplified renaming logic to avoid unnecessary renames, changed entry module symbol handling |
crates/rolldown/src/utils/chunk/deconflict_chunk_symbols.rs |
Added reference-based shadowing detection for member expressions and named imports |
crates/rolldown_common/src/types/member_expr_ref*.rs |
Added reference_id field to track oxc reference IDs |
crates/rolldown/src/ast_scanner/ |
Updated to capture and pass reference IDs |
crates/rolldown/src/stages/link_stage/bind_imports_and_exports.rs |
Updated to pass reference IDs through resolution |
Cargo.toml and Cargo.lock |
Updated oxc dependencies to unreleased git branch |
| Test snapshots | Updated to reflect improved renaming (fewer unnecessary renames) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
22eea64 to
436e1a2
Compare
|
No dependency changes detected. Learn more about Socket for GitHub. 👍 No dependency changes detected in pull request |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 30 out of 31 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 29 out of 30 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
rolldown/rolldown#7936 relies on this. You can see how Rolldown uses this at description of that PR. Additionally, it can also simplify the use case when you want to get the scope ID where the `Reference` occurs. See follow-up PR #18059
12d6576 to
b0d70e3
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
You said
In pr #7867, but the test case seems regressed |
Yes, due to the prioritized internal binding being renamed (previously, it was the top-level binding that was renamed first), this has reverted to the state before that PR. I also checked how Additionally, avoiding ugly |
✅ Deploy Preview for rolldown-rs canceled.
|
## [1.0.0-rc.1] - 2026-01-22 ### 🚀 Features - debug_info: add facade chunk elimination reason (#7980) by @IWANABETHATGUY - support lazy barrel optimization (#7933) by @shulaoda - add `experimental.lazyBarrel` option (#7908) by @shulaoda - skip unused external modules from IIFE parameter list (#7978) by @sapphi-red - add custom panic hook for better crash reporting (#7752) by @shulaoda - treeshake: add `invalidImportSideEffects` option (#7958) by @shulaoda - merge allow-extension emitted chunks (#7940) by @IWANABETHATGUY - nativeMagicString generateMap (#7944) by @IWANABETHATGUY - Include meta.magicString in RenderChunkMeta (#7943) by @IWANABETHATGUY - debug_info: add debug info for eliminated facade chunks (#7946) by @IWANABETHATGUY - stablize `strictExecutionOrder` and move to `output.strictExecutionOrder` from `experimental.strictExecutionOrder` (#7901) by @sapphi-red - add documentation link to require() error message (#7898) by @Copilot - add `codeSplitting: boolean` and deprecate `inlineDynamicImports` (#7870) by @hyf0 - dev: change lazy module URL to `/@vite/lazy` from `/lazy` (#7884) by @sapphi-red ### 🐛 Bug Fixes - transform JS files containing `</script>` to escape template literals (#7987) by @IWANABETHATGUY - apply avoid-breaking-exported-api = false to clippy.toml and fix clippy errors (#7982) by @Boshen - pass `kind` from `this.resolve` (#7981) by @sapphi-red - rolldown_plugin_vite_resolve: ignore yarn resolution errors and fallback to other resolvers (#7968) by @sapphi-red - renamer: prevent renaming symbols when there no conflicts (#7936) by @Dunqing - correct minifyInterExports when emitted chunk got merged (#7941) by @IWANABETHATGUY - deduplicate entry points when module is both emitted and dynamically imported (#7885) by @IWANABETHATGUY - dev: add `@vite-ignore` to lazy compilation proxy module import (#7883) by @sapphi-red ### 🚜 Refactor - rust: enable clippy nursery lint group (#8002) by @Boshen - rust: fix inconsistent_struct_constructor clippy lint (#7999) by @Boshen - rust: fix needless_pass_by_ref_mut clippy lint (#7994) by @Boshen - rust: fix unnecessary_wraps clippy lint (#7993) by @Boshen - rust: fix enum_variant_names clippy lint (#7992) by @Boshen - fix single_match clippy lint (#7997) by @Boshen - rust: fix redundant_clone clippy lint (#7996) by @Boshen - rust: rename CJS to Cjs to follow upper_case_acronyms lint (#7991) by @Boshen - rust: remove unnecessary Box wrapper around Vec in MemberExprRef (#7990) by @Boshen - import_record: make resolved_module optional (#7907) by @shulaoda - remove unnecessary `.parse` (#7966) by @sapphi-red - remove unused `ImportRecordMeta::IsPlainImport` (#7948) by @shulaoda - proper set chunk meta (#7939) by @IWANABETHATGUY - module_loader: remove `try_spawn_with_cache` (#7920) by @shulaoda - link_stage: simplify `ImportStatus::NoMatch` to unit variant (#7909) by @shulaoda - improve global scope symbol reservation in chunk deconfliction (#7906) by @IWANABETHATGUY - simplify ast unwrapping in generate stage (#7900) by @IWANABETHATGUY - generate_stage: optimize cross-chunk imports computation (#7889) by @shulaoda - link_stage: move runtime require logic into match branch (#7892) by @shulaoda - link_stage: simplify runtime require reference conditions (#7891) by @shulaoda - link_stage: inline and simplify external dynamic import check (#7890) by @shulaoda - generate_stage: simplify external module import collection logic (#7887) by @shulaoda - avoid redundant module lookup in TLA computation (#7886) by @shulaoda - dev: `devEngine.compileEntry` does not return null (#7882) by @sapphi-red - dev: fix type errors for test HMR runtime (#7881) by @sapphi-red - dev: move `clientId` property to `DevRuntime` base class (#7880) by @sapphi-red - dev: generate client id in browser (#7878) by @hyf0 ### 📚 Documentation - apis: organize hook filters documentation and add composable filters section (#8003) by @sapphi-red - update `vitepress-plugin-group-icons` (#7947) by @yuyinws - add in-depth documentation for lazy barrel optimization (#7969) by @shulaoda - bump theme & update activeMatch for reference (#7963) by @mdong1909 - mark `build()` API as experimental (#7954) by @sapphi-red - enhance search functionality with improved scoring and filtering logic (#7935) by @hyf0 - add minor comments to multiple types (#7930) by @sapphi-red - refactor advanedChunks related content to adapt manual code splitting concept (#7925) by @hyf0 - apis: add content to Bundler API page (#7926) by @sapphi-red - apis: restructure plugin API related docs (#7924) by @sapphi-red - add plugin API docs (#7923) by @sapphi-red - apis: add docs to important APIs (#7913) by @sapphi-red - move the important APIs to the top of the sidebar (#7912) by @sapphi-red - apis: add more content to CLI documentation (#7911) by @sapphi-red - apis: generate CLI docs from --help output (#7910) by @sapphi-red - add fathom analytics (#7896) by @mdong1909 ### ⚡ Performance - use u32 for string indices in string_wizard and rolldown to reduce memory usage (#7989) by @IWANABETHATGUY - rust: remove all usages of `with_scope_tree_child_ids(true)` for `SemanticBuilder` (#7995) by @Dunqing - renamer: skip unnecessary nested scope symbol processing (#7899) by @Dunqing - module_loader: use ArcStr for importer_id to avoid string copy (#7922) by @shulaoda - module_loader: defer `ModuleTaskOwner` construction until needed (#7921) by @shulaoda - renamer: optimize symbol renaming by eliminating `rename_non_root_symbol` pass (#7867) by @Dunqing ### 🧪 Testing - add lazy barrel optimization test cases (#7967) by @shulaoda ### ⚙️ Miscellaneous Tasks - remove lazy barrel option (#8010) by @shulaoda - mark watch API as experimental (#8004) by @sapphi-red - deps: update dependency lodash-es to v4.17.23 [security] (#8001) by @renovate[bot] - git ignore zed local config (#7988) by @IWANABETHATGUY - setup publint for published packages (#7972) by @Copilot - enable `tagged_template_transform ` uncondionally (#7975) by @IWANABETHATGUY - deps: update oxc to v0.110.0 (#7964) by @renovate[bot] - deps: update oxc apps (#7962) by @renovate[bot] - ai: add upgrade-oxc Claude skill (#7957) by @Boshen - deps: update rollup submodule for tests to v4.55.2 (#7959) by @sapphi-red - deps: update test262 submodule for tests (#7960) by @sapphi-red - deps: update crate-ci/typos action to v1.42.1 (#7961) by @renovate[bot] - deps: update rust crates (#7951) by @renovate[bot] - deps: update npm packages (#7953) by @renovate[bot] - deps: update github-actions (#7952) by @renovate[bot] - deps: update npm packages (#7950) by @renovate[bot] - format magic-string test before write to disk (#7945) by @IWANABETHATGUY - deps: update dependency rolldown-plugin-dts to ^0.21.0 (#7915) by @renovate[bot] - deps: update dependency oxlint-tsgolint to v0.11.1 (#7914) by @renovate[bot] - deps: update dependency diff to v8.0.3 [security] (#7904) by @renovate[bot] - remove outdated TODO comment in `collect_depended_symbols` (#7888) by @shulaoda - deps: update oxc resolver to v11.16.3 (#7876) by @renovate[bot]
Note: waiting for oxc-project/oxc#18053 to merge to unblock this (Edit: merged, and already released)
Summary
Fixes: #6586
This PR refines the symbol renaming (deconflict) logic to correctly handle both top-level symbol conflicts and nested scope shadowing. The key insight is that these are two distinct problems requiring different solutions.
Related fixes:
rename_non_root_symbolpass #7867This PR essentially reverts all the logic implemented in the previous fixes while preserving the performance improvements introduced in #7867 (4%).
1. Top-Level Symbol Renaming
When bundling multiple modules into a single chunk, symbols with the same name need unique identifiers.
Example:
Output:
Rules:
$1,$2, etc.Object,Promise) are always avoided2. Nested Scope Symbol Renaming
This handles cases where a nested binding (function parameter, catch clause, block-scoped variable) interacts with top-level symbols.
Case A: NO renaming needed - Intentional shadowing
When a nested binding shadows an import that kept its original name, no renaming is needed because JavaScript's scoping rules handle it correctly.
Example (
preserve_shadowing_param_name):Output:
Case B: Star import member references - Renaming needed
When a namespace import member (like
ns.foo) is referenced inside a function, and a nested binding would capture that reference, the nested binding must be renamed.Example (
argument-treeshaking-parameter-conflict):Output:
Why renaming is needed:
dep.mutateresolves to the top-levelmutatefunctiontest, the parametermutatewould shadow the top-levelmutatedep.mutate('hello')becomes justmutate("hello")after bundlingmutate$1so the reference correctly resolves to the top-levelmutateCase C: Named imports - Renaming needed
When a named import is renamed due to a top-level conflict, and a nested binding has the same name as the renamed import, that nested binding must be renamed to avoid capturing references.
Example (
basic_scoped):Output:
Why renaming is needed:
afroma.jsis renamed toa$1(conflicts with localain entry module)aJsresolves to the renameda$1foo, the parametera$1would capture the reference toaJsa$1$1soaJscorrectly resolves to the top-levela$1Case D: CJS wrapper parameters - Renaming needed
For CommonJS wrapped modules, nested scopes must avoid shadowing the synthetic
exportsandmoduleparameters injected by the CJS wrapper.Example:
Output:
Implementation Details
The renaming happens in two phases:
add_symbol_in_root_scope- Assigns canonical names to top-level symbols, checking:NestedScopeRenamer- Renames nested bindings that would capture references:rename_bindings_shadowing_star_imports(Case B): Star import member references (ns.foo)rename_bindings_shadowing_named_imports(Case C): Named imports that were renamedrename_bindings_shadowing_cjs_params(Case D): CJS wrapper parameter shadowing (exports,module)Test Cases
preserve_shadowing_param_nameargument-treeshaking-parameter-conflictbasic_scopedcjspreserves-catch-argumentclass-name-conflict-2