turbo-tasks: Drop output_dependent on immutable task completion (#92683)
### What?
Extend the `cleanup_after_execution` macro codegen to support
`drop_on_completion_if_immutable` on **inline** collection fields
(previously only lazy fields were supported), and apply it to
`output_dependent` in the task storage schema.
### Why?
`output_dependent` tracks which tasks depend on a given task's output,
used for invalidation and leaf distance propagation. For immutable
tasks:
- **No invalidation needed** — the output never changes, so dependents
never need to be dirtied via this edge.
- **No new readers added** — `try_read_task_output` already guards with
`!task.immutable()` at `mod.rs:742`, so the set is frozen after
completion.
- **Leaf distance propagation** — immutable tasks can be treated as
non-participants in the leaf distance graph; propagation simply stops at
immutable nodes.
This matches the existing treatment of `cell_dependents`, which already
has `drop_on_completion_if_immutable` for the same reasons (immutable
tasks' cells don't change).
### How?
**Macro change**
(`turbo-tasks-macros/src/derive/task_storage_macro.rs`):
The `generate_cleanup_after_execution` function previously only handled
`shrink_on_completion` for inline fields. Now it also handles
`drop_on_completion_if_immutable`: when the task is immutable, it emits
`typed.field_name = Default::default()` which replaces the `AutoSet`
with an empty one, releasing any heap allocation (`Box<HashMap>` or
spilled `SmallVec` buffer). When mutable, it falls back to
`shrink_to_fit()`.
Note: unlike lazy fields which are physically removed from
`Vec<LazyField>`, inline fields always occupy their struct slot — but
`Default::default()` ensures zero heap overhead (the `SmallVec<[_; 1]>`
reverts to inline storage).
**Schema change** (`turbo-tasks-backend/src/backend/storage_schema.rs`):
Added `drop_on_completion_if_immutable` to the `#[field(...)]` attribute
on `output_dependent`.
<!-- NEXT_JS_LLM_PR -->
---------
Co-authored-by: Claude <noreply@anthropic.com>