1# pruneUnusedScopes23## File4`src/ReactiveScopes/PruneUnusedScopes.ts`56## Purpose7This pass converts reactive scopes that have no meaningful outputs into "pruned scopes". A pruned scope is no longer memoized - its instructions are executed unconditionally on every render. This optimization removes unnecessary memoization overhead for scopes that don't produce values that need to be cached.89## Input Invariants10- The input is a `ReactiveFunction` that has already been transformed into reactive scope form11- Scopes have been created and have `declarations`, `reassignments`, and potentially `earlyReturnValue` populated12- The pass is called after:13 - `pruneUnusedLabels` - cleans up unnecessary labels14 - `pruneNonEscapingScopes` - removes scopes whose outputs don't escape15 - `pruneNonReactiveDependencies` - removes non-reactive dependencies from scopes16- Scopes may already be marked as pruned by earlier passes1718## Output Guarantees19Scopes that meet ALL of the following criteria are converted to `pruned-scope`:20- No return statement within the scope21- No reassignments (`scope.reassignments.size === 0`)22- Either no declarations (`scope.declarations.size === 0`), OR all declarations "bubbled up" from inner scopes2324Pruned scopes:25- Keep their original scope metadata (for debugging/tracking)26- Keep their instructions intact27- Will be executed unconditionally during codegen (no memoization check)2829## Algorithm3031The pass uses the visitor pattern with `ReactiveFunctionTransform`:32331. **State Tracking**: A `State` object tracks whether a return statement was encountered:34 ```typescript35 type State = {36 hasReturnStatement: boolean;37 };38 ```39402. **Terminal Visitor** (`visitTerminal`): Checks if any terminal is a `return` statement41423. **Scope Transform** (`transformScope`): For each scope:43 - Creates a fresh state for this scope44 - Recursively visits the scope's contents45 - Checks pruning criteria:46 - `!scopeState.hasReturnStatement` - no early return47 - `scope.reassignments.size === 0` - no reassignments48 - `scope.declarations.size === 0` OR `!hasOwnDeclaration(scopeBlock)` - no outputs49504. **hasOwnDeclaration Helper**: Determines if a scope has "own" declarations vs declarations propagated from nested scopes5152## Edge Cases5354### Return Statements55Scopes containing return statements are preserved because early returns need memoization to avoid re-executing the return check on every render.5657### Bubbled-Up Declarations58When nested scopes are flattened or merged, their declarations may be propagated to parent scopes. The `hasOwnDeclaration` check ensures that parent scopes with only inherited declarations can still be pruned.5960### Reassignments61Scopes with reassignments are kept because the reassignment represents a side effect that needs to be tracked for memoization.6263### Already-Pruned Scopes64The pass operates on `ReactiveScopeBlock` (kind: 'scope'), not `PrunedReactiveScopeBlock`. Scopes already pruned by earlier passes are not revisited.6566### Interaction with Subsequent Passes67The `MergeReactiveScopesThatInvalidateTogether` pass explicitly handles pruned scopes - it does not merge across them.6869## TODOs70None in the source file.7172## Example7374### Fixture: `prune-scopes-whose-deps-invalidate-array.js`7576**Input:**77```javascript78function Component(props) {79 const x = [];80 useHook();81 x.push(props.value);82 const y = [x];83 return [y];84}85```8687What happens:88- The scope for `x` cannot be memoized because `useHook()` is called inside it89- `FlattenScopesWithHooksOrUseHIR` marks scope @0 as `pruned-scope`90- `PruneUnusedScopes` doesn't change it further since it's already pruned9192**Output (no memoization for x):**93```javascript94function Component(props) {95 const x = [];96 useHook();97 x.push(props.value);98 const y = [x];99 return [y];100}101```102103### Key Insight104105The `pruneUnusedScopes` pass is part of a multi-pass pruning strategy:1061. `FlattenScopesWithHooksOrUseHIR` - Prunes scopes that contain hook/use calls1072. `pruneNonEscapingScopes` - Prunes scopes whose outputs don't escape1083. `pruneNonReactiveDependencies` - Removes non-reactive dependencies1094. **`pruneUnusedScopes`** - Prunes scopes with no remaining outputs110111This pass acts as a cleanup for scopes that became "empty" after previous pruning passes removed their outputs.
Findings
✓ No findings reported for this file.