Add back transitive freeze functions option

Adds back a mode to transitively freeze function expressions, independently from 
the mode to preserve existing manual memoization. This lets us experiment with a 
few variants: 

* Preserve existing memoization 

* Validate existing memoization with: 

* `enableAssumeHooksFollowRulesOfReact` && 
`enableTransitivelyFreezeFunctionExpressions` 

* `enableAssumeHooksFollowRulesOfReact` only 

* neither of those flags 

Note that `enableTransitivelyFreezeFunctionExpressions` alone probably doesn't 
make sense, it's more aggressive than 

`enableAssumeHooksFollowRulesOfReact` so we might as well try them together.
This commit is contained in:
Joe Savona
2023-12-18 15:33:02 -08:00
parent c77acb3ac6
commit f504eaa16e
4 changed files with 15 additions and 4 deletions
@@ -210,6 +210,14 @@ const EnvironmentConfigSchema = z.object({
*/
enableAssumeHooksFollowRulesOfReact: z.boolean().default(false),
/**
* When enabled, the compiler assumes that any values are not subsequently
* modified after they are captured by a function passed to React. For example,
* if a value `x` is referenced inside a function expression passed to `useEffect`,
* then this flag will assume that `x` is not subusequently modified.
*/
enableTransitivelyFreezeFunctionExpressions: z.boolean().default(false),
/*
* When enabled, removes *all* memoization from the function: this includes
* removing manually added useMemo/useCallback as well as not adding Forget's
@@ -354,7 +354,10 @@ class InferenceState {
reason: reasonSet,
});
if (this.#env.config.enablePreserveExistingMemoizationGuarantees) {
if (
this.#env.config.enablePreserveExistingMemoizationGuarantees ||
this.#env.config.enableTransitivelyFreezeFunctionExpressions
) {
if (value.kind === "FunctionExpression") {
for (const operand of eachInstructionValueOperand(value)) {
this.reference(operand, Effect.Freeze, ValueReason.Other);
@@ -2,7 +2,7 @@
## Input
```javascript
// @enablePreserveExistingMemoizationGuarantees
// @enableTransitivelyFreezeFunctionExpressions
function Component(props) {
const { data, loadNext, isLoadingNext } =
usePaginationFragment(props.key).items ?? [];
@@ -31,7 +31,7 @@ function Component(props) {
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react"; // @enablePreserveExistingMemoizationGuarantees
import { unstable_useMemoCache as useMemoCache } from "react"; // @enableTransitivelyFreezeFunctionExpressions
function Component(props) {
const $ = useMemoCache(10);
const { data, loadNext, isLoadingNext } =
@@ -1,4 +1,4 @@
// @enablePreserveExistingMemoizationGuarantees
// @enableTransitivelyFreezeFunctionExpressions
function Component(props) {
const { data, loadNext, isLoadingNext } =
usePaginationFragment(props.key).items ?? [];