react/compiler
Mike Vitousek 633a0fe536 [compiler] Factor out function effects from reference effects
Summary:
This PR performs a major refactor of InferReferenceEffects to separate out the work on marking places with Effects from inferring FunctionEffects. The behavior should be identical after this change (see [internal sync](https://www.internalfb.com/intern/everpaste/?handle=GN74VxscnUaztTYDAL8q0CRWBIxibsIXAAAB)) but the FunctionEffect logic should be easier to work with.

These analyses are unfortunately still deeply linked--the FunctionEffect analysis needs to reason about the "current" value kind for each point in the program, while the InferReferenceEffects algorithm performs global updates on the state of the program (e.g. freezing). In the future, it might be possible to make these entirely separate passes if we store the ValueKind directly on places.

For the most part, the logic of reference effects and function effects can be cleanly separated: for each instruction and terminal, we visit its places and infer their effects, and then we visit its places and infer any function effects that they cause. The biggest wrinkle here is that when a transitive function freeze operation occurs, it has to happen *after* inferring the function effects on the place, because otherwise we may convert a value from Context to Frozen, which will cause the ContextualMutation function effect to be converted to a ReactMutation effect too early. This can be observed in a case like this:

```
export default component C() {
  foo(() => {
    const p = {};
    return () => {
      p['a'] = 1
    };
  });
}
```
Here when the outer function returns the inner function, it freezes the inner function which transitively freezes `p`. But before that freeze happens, we need to replay the ContextualMutation on the inner function to determine that the value is mutable in the outer context. If we froze `p` first, we would instead convert the ContextualMutation to a ReactMutation and error.

To handle this, InferReferenceEffects now delays the exection of the freezeValue action until after it's called the helper functions that generate function effects. So the order of operations on a given place is now

set effect --> generate function effects --> transitively freeze dependencies, if applicable

ghstack-source-id: 21cb50c14054e7e7a307acb595ef30b54c2f2a52
Pull Request resolved: https://github.com/facebook/react/pull/30920
2024-09-13 12:38:17 -07:00
..
apps/playground [compiler][playground] Fix displayed naming of outlined functions 2024-09-07 17:50:19 -07:00
crates Fix rust lints 2024-08-06 14:48:32 -04:00
docs Punctuation & correcting spelling mistakes (#30592) 2024-08-09 14:53:53 -07:00
packages [compiler] Factor out function effects from reference effects 2024-09-13 12:38:17 -07:00
scripts [compiler] Publish to latest tag 2024-08-12 14:41:11 -04:00
.eslintrc.js [compiler:codegen] Wrap non-ascii characters in JsxExpressionContainer 2024-06-21 10:08:15 -04:00
.gitignore [.gitignore] Add bundle script 2024-04-16 14:41:13 +01:00
Cargo.lock Bump rustix from 0.37.22 to 0.37.27 in /compiler (#29173) 2024-05-20 12:02:35 +01:00
Cargo.toml Update references to Forget to React Compiler 2024-05-02 14:28:06 -07:00
package.json [compiler] Refactor release script 2024-08-06 14:48:33 -04:00
README.md Update readme and other docs 2024-05-06 14:53:47 -07:00
rust-toolchain.toml
rustfmt.toml
yarn.lock [compiler] Refactor release script 2024-08-06 14:48:33 -04:00

React Compiler

React Compiler is a compiler that optimizes React applications, ensuring that only the minimal parts of components and hooks will re-render when state changes. The compiler also validates that components and hooks follow the Rules of React.

More information about the design and architecture of the compiler are covered in the Design Goals.

More information about developing the compiler itself is covered in the Development Guide.