Skip to content

[compiler] Repro for missed case of global mutation#102

Draft
everettbu wants to merge 3 commits into
mainfrom
pr33643
Draft

[compiler] Repro for missed case of global mutation#102
everettbu wants to merge 3 commits into
mainfrom
pr33643

Conversation

@everettbu

@everettbu everettbu commented Dec 12, 2025

Copy link
Copy Markdown

Mirror of facebook/react#33643
Original author: josephsavona


I realized a pattern of global mutations that we don't currently detect (both in the old and new inference models). If you hide the mutation inside a function returned from another function, we lose track of it:

const f = () => () => {
  global.property = true;
};
f()();

Roughly speaking, we need to track that if the return value of f is mutated, that it should count as triggering some effects. Right now we encode the idea that a function specifically can have side effects if it is mutated, but other values don't have a way to represent this. I'm thinking that we change the shape of the Create effect a bit, and allow room for an optional "mutation effects" array. Then, InferMutationAliasingRanges can visit these effects like it does when trying to find transitive function effects.


Stack created with Sapling. Best reviewed with ReviewStack.

  • -> #33643
  • #33642
  • #33650

In InferReferenceEffects we used `InstructionValue` as the key to represent values, since each time we process an instruction this object will be the same. However this was always a bit of a hack, and in the new model and InferMutationAliasingEffects we can instead use the (creation) effect as the stable value. This avoids an extra layer of memoization since the effects are already interned anyway.
… functions

If you have a local helper function that itself returns a function (`() => () => { ... }`), we currently infer the return effect of the outer function as `Create mutable`. We correctly track the aliasing, but we lose some precision because we don't understand that a function specifically is being returned.

Here, we do some extra analysis of which values are returned in InferMutationAliasingRanges, and if the sole return value is a function we infer a `CreateFunction` effect. We also infer an `Assign` (instead of a Create) if the sole return value was one of the context variables or parameters.
I realized a pattern of global mutations that we don't currently detect (both in the old and new inference models). If you hide the mutation inside a function returned from another function, we lose track of it:

```js
const f = () => () => {
  global.property = true;
};
f()();
```

Roughly speaking, we need to track that if the return value of `f` is mutated, that it should count as triggering some effects. Right now we encode the idea that a function specifically can have side effects if it is mutated, but other values don't have a way to represent this. I'm thinking that we change the shape of the `Create` effect a bit, and allow room for an optional "mutation effects" array. Then, InferMutationAliasingRanges can visit these effects like it does when trying to find transitive function effects.
@everettbu everettbu added CLA Signed React Core Team Opened by a member of the React Core Team labels Dec 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed React Core Team Opened by a member of the React Core Team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants