Fix: The `child_is_reachable` calculation in `log_effect_tree` fails to incorporate the parent's `is_reachable` state, causing descendant effects to be incorrectly marked as reachable when an ancestor is unreachable.

This commit fixes the issue reported at packages/svelte/src/internal/client/dev/debug.js:130

**Bug Explanation:**

The `log_effect_tree` function recursively traverses an effect tree to log effects and mark "unreachable-but-dirty" effects with a warning. The function receives an `is_reachable` parameter indicating whether the current effect is reachable based on its ancestors.

At line 130, the original code was:
```javascript
var child_is_reachable = (flags & BRANCH_EFFECT) === 0 || (flags & CLEAN) === 0;
```

This calculation determines reachability for children based only on whether the *current* effect would block propagation (being a clean BRANCH_EFFECT). However, it completely ignores the incoming `is_reachable` parameter.

**Example scenario where the bug manifests:**
- Root (reachable) → `is_reachable = true`
  - Branch A: clean BRANCH_EFFECT → passes `child_is_reachable = false` to children
    - Branch B: dirty BRANCH_EFFECT → receives `is_reachable = false`, but calculates `child_is_reachable = false || true = true`
      - Effect C: dirty → receives `is_reachable = true` (WRONG!)

Effect C should be marked as unreachable with a warning (⚠️) because its ancestor Branch A is a clean branch that doesn't propagate updates. Instead, it would appear as reachable because Branch B is dirty, and the original code doesn't carry forward the unreachability.

**The Fix:**

Changed the calculation to combine the inherited reachability with the current effect's contribution:
```javascript
var child_is_reachable = is_reachable && ((flags & BRANCH_EFFECT) === 0 || (flags & CLEAN) === 0);
```

Now:
- If `is_reachable` is already `false` (from an ancestor), children remain unreachable regardless of the current effect's state
- If `is_reachable` is `true`, the original logic applies to determine if THIS effect makes children unreachable

This ensures unreachability properly propagates down the entire subtree once an ancestor clean branch is encountered.

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: Rich-Harris <hello@rich-harris.dev>
pull/17833/head
Vercel 2 days ago
parent c7c80edca2
commit 7c7797f62c

@ -127,7 +127,7 @@ export function log_effect_tree(effect, depth = 0, is_reachable = true) {
}
}
var child_is_reachable = (flags & BRANCH_EFFECT) === 0 || (flags & CLEAN) === 0;
var child_is_reachable = is_reachable && ((flags & BRANCH_EFFECT) === 0 || (flags & CLEAN) === 0);
let child = effect.first;
while (child !== null) {

Loading…
Cancel
Save