Turbopack: propagate late partial namespace provenance to passthrough targets (#100444)
### What?
Namespace provenance from a late partial-namespace read now reaches the
module's passthrough targets, even when that module was already
processed with `All` usage or with the same names.
### Why?
`compute_binding_usage_info` tracks modules read through a namespace
value (`namespace_object_may_escape`). Export-name mangling uses this to
keep original names. Passthrough edges such as `export * from './y'`
forward that provenance to their target.
Take a module that was reached first through a plain named or `All`
edge, so its passthrough edge has already run. If a partial-namespace
edge for it arrives later and adds no new export names, the module joins
the provenance set but the visitor reports no change. It is never
revisited, so its passthrough target stays out of the set.
### How?
Direct partial-namespace edges now count adding the target to the
provenance set as a change, the same way the passthrough branch already
does. The export-usage merge still always runs. Each module can only be
added to the set once, so this triggers at most one extra revisit per
module and the fixed point still terminates.
New `turbopack-core` graph tests build a small module graph with
explicit edge usages and check the result directly. In the graph, `x`
re-exports `y` through a passthrough edge, and `x` is reached by both a
short path and a longer path. The tests cover:
- the plain usage of `x` being `All` or an already-used name
- the namespace read arriving on the longer path (the failing case) or
on the shorter path (a control)
Without this fix, the two late cases mark `x` but leave `y` out of the
provenance set; all four pass with it.
The new execution test
`turbopack/exports/mangle-late-namespace-passthrough` reproduces the bug
with real module analysis and codegen. A barrel (`export * from
'./source'`) is reached early by named imports from the entry, and later
by a narrowed dynamic import (`webpackExports`) that sits a few modules
deeper and uses no new names. The test disables `followReexports` so the
named imports target the barrel instead of resolving straight to the
source. It also disables `mangleViaMaterializedNamespaceObject` so the
dynamic import reads the barrel itself, not a namespace facade. Without
the fix, the source export is wrongly marked mangleable (`canMangle:
true`). The values still read correctly in this fixture, so the test
checks the mangling decision through `__webpack_exports_info__`.
### Verification
- `cargo test -p turbopack-core --lib`
- `cargo test -p turbopack-tests --test snapshot` (no snapshot changes)
- `cargo test -p turbopack-tests --test execution`, including the new
test, which fails without the fix
- `cargo clippy -p turbopack-core --tests`
<!-- NEXT_JS_LLM -->
<!-- fleet c860b76b-981c-4d9b-a802-f28b0545c8a7 -->
---------
Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com>
Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com>
Co-authored-by: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com>