[ruff] Treat f-string interpolation as potential side effect in RUF019 (#24426)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:
- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
requests.)
- Does this pull request include references to any relevant issues?
- Does this PR follow our AI policy
(https://github.com/astral-sh/.github/blob/main/AI_POLICY.md)?
-->
## Summary
Fixes #12953
F-string interpolation can call `__format__`/`__str__`/`__repr__`, which
may have side effects. RUF019 was applying a safe auto-fix that
collapsed two `__str__` calls into one, changing behavior.
Added a tri-state `SideEffect` enum (`No`/`Maybe`/`Yes`) and a
`side_effect()` function that reuses the existing `any_over_expr`
traversal via a new `FnMut` variant (`any_over_expr_mut`), following the
approach suggested by @ntBre in the other closed pr tagged in the issue
In RUF019, `SideEffect::Maybe` (non-literal f-string interpolation) now
produces an unsafe fix instead of a safe one. Literal interpolations
like `f"{1}"` remain safe.
## Test Plan
- Added f-string fixture cases to `RUF019.py` (non-literal → unsafe,
literal → safe, no interpolation → safe).
- `cargo nextest run -p ruff_linter`
- Ecosystem check (stable + preview)