turbopack: gate ValueDebugFormat and ValueDebug behind debug_assertions (#92628)
### What?
Gate `ValueDebugFormat` and `ValueDebug` behind
`#[cfg(debug_assertions)]` across the turbopack crates, eliminating all
debug formatting machinery from release binaries entirely.
### Why?
`ValueDebugFormat` and `ValueDebug` contribute to release binary bloat.
The field-level formatting logic (iterating struct fields, resolving
`Vc`s, formatting collections recursively) and the per-type `ValueDebug`
trait registrations are purely debugging aids with no value in
production binaries.
**Measured impact: -7.3 MiB (-5.5%) reduction in release
`libnext_napi_bindings.so` binary size** (from 126.26 MiB to 119.31
MiB).
### How?
**`ValueDebug` trait** (`debug/mod.rs`):
- In debug builds: full `#[turbo_tasks::value_trait(no_debug)]` with
`dbg()` / `dbg_depth()` methods, `ValueDebugFormatString`, all blanket
impls for collections/tuples/etc.
- In release builds: empty marker trait with blanket `impl<T: ?Sized>
ValueDebug for T {}`. This satisfies the supertrait bound on all value
traits at zero cost — no per-type impl code is generated.
**`ValueDebugFormat` trait** (`debug/mod.rs`):
- The `value_debug_format` method only exists under
`#[cfg(debug_assertions)]`. In release builds, the trait is still
present (for derive macros to reference) but has no methods.
- All blanket impls (`String`, `RcStr`, `Option`, `Vec`, `SmallVec`,
`AutoSet`, `AutoMap`, `HashMap`, `FxIndexSet`, `FxIndexMap`, tuples) are
gated behind `debug_assertions`.
- Supporting infrastructure (`ValueDebugFormatString`,
`PassthroughDebug`, `vdbg`, `internal` submodule,
`value_debug_format_field`) is compiled away.
**Proc-macros**:
- `#[derive(ValueDebugFormat)]`: emits a full impl with
`value_debug_format` method in debug builds, empty impl in release
builds.
- `#[derive(ValueDebug)]` and `value_impl` blocks: emit full debug impl
in debug builds only — **no release impl at all** (the blanket marker
trait impl covers it).
- `#[turbo_tasks::value]`: transparent types get
`#[cfg(debug_assertions)]` on the manual `ValueDebug` impl.
Non-transparent types use `#[cfg_attr(debug_assertions,
derive(turbo_tasks::debug::internal::ValueDebug))]` so the `internal`
module is never referenced in release.
- `#[turbo_tasks::value_trait]`: the `Dynamic/Upcast/UpcastStrict` impls
for `Box<dyn ValueDebug>` are gated behind `#[cfg(debug_assertions)]`.
**Callers** (`vc/mod.rs`, `vc/resolved.rs`, `read_ref.rs`,
`mapped_read_ref.rs`, `macro_helpers.rs`, `alias_map.rs`):
- All `impl ValueDebugFormat` blocks and their imports are gated behind
`#[cfg(debug_assertions)]`.
### Verification
- `cargo check --release` — clean (no errors, no warnings)
- `cargo clippy --all-targets` — clean
- CI passing
<!-- NEXT_JS_LLM_PR -->
---------
Co-authored-by: Tobias Koppers <sokra@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>