diff --git a/compiler/packages/babel-plugin-react-forget/src/Inference/DropManualMemoization.ts b/compiler/packages/babel-plugin-react-forget/src/Inference/DropManualMemoization.ts index cf91cafeda..ccfcc39b51 100644 --- a/compiler/packages/babel-plugin-react-forget/src/Inference/DropManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-forget/src/Inference/DropManualMemoization.ts @@ -130,12 +130,12 @@ export function dropManualMemoization(func: HIRFunction): void { * $1 = LoadGlobal useMemo // load the useMemo global (dead code) * $2 = FunctionExpression ... // memo function * $3 = ArrayExpression [ ... ] // deps array (dead code) - * $5 = Call $2 () // invoke the memo function itself - * $4 = Memoize $5 // preserve memo information + * .. = Memoize ... // memoize dependencies + * $4 = Call $2 () // invoke the memo function itself + * .. = Memoize $4 // preserve memo information * - * Note that we synthesize a new temporary for the call ($5) and use - * the original lvalue for the result of the Memoize instruction, so that - * we don't have to rewrite subsequent instructions. + * Note that Memoize does not produce a result and is called for its side + * effects only. */ nextInstructions = nextInstructions ?? block.instructions.slice(0, i); @@ -194,13 +194,13 @@ export function dropManualMemoization(func: HIRFunction): void { * $1 = LoadGlobal useCallback * $2 = FunctionExpression ... // the callback being memoized * $3 = ArrayExpression ... // deps array - * $3 = Call $1 ( $2, $3 ) // invoke useCallback + * $4 = Call $1 ( $2, $3 ) // invoke useCallback * * after: * $1 = LoadGlobal useCallback // dead code * $2 = FunctionExpression ... // the callback being memoized * $3 = ArrayExpression ... // deps array (dead code) - * $3 = LoadLocal $2 // reference the function + * $4 = LoadLocal $2 // reference the function */ if (fn.kind === "Identifier") { instr.value = { @@ -227,15 +227,18 @@ export function dropManualMemoization(func: HIRFunction): void { * $1 = LoadGlobal useCallback // dead code * $2 = FunctionExpression ... // the callback being memoized * $3 = ArrayExpression ... // deps array (dead code) - * $3 = LoadLocal $2 // reference the function + * $4 = LoadLocal $2 // reference the function * * With flag enabled: * $1 = LoadGlobal useCallback // dead code * $2 = FunctionExpression ... // the callback being memoized * $3 = ArrayExpression ... // deps array (dead code) - * $3 = Memoize $2 // reference the function + * .. = Memoize ... // memoize dependencies + * $n = Memoize $2 // reference the function + * $4 = LoadLocal $2 // reference the function * - * Note the s/LoadLocal/Memoize/ + * Note that Memoize does not produce a result and is called for its side effects + * only. */ const functionExpression = functions.get(fn.identifier.id); if (functionExpression !== undefined) { diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useMemo-mabye-modified-free-variable-dont-preserve-memoization-guarantees.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useMemo-mabye-modified-free-variable-dont-preserve-memoization-guarantees.expect.md index b3918c1910..c113410428 100644 --- a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useMemo-mabye-modified-free-variable-dont-preserve-memoization-guarantees.expect.md +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useMemo-mabye-modified-free-variable-dont-preserve-memoization-guarantees.expect.md @@ -25,6 +25,9 @@ function Component(props) { mutate(x, free, part); return x; }, [props.value]); + + identity(free); + identity(part); return object; } @@ -60,6 +63,9 @@ function Component(props) { mutate(x, free, part); t39 = x; const object = t39; + + identity(free); + identity(part); return object; } diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useMemo-mabye-modified-free-variable-dont-preserve-memoization-guarantees.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useMemo-mabye-modified-free-variable-dont-preserve-memoization-guarantees.js index 27ef445b83..3f556759f7 100644 --- a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useMemo-mabye-modified-free-variable-dont-preserve-memoization-guarantees.js +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useMemo-mabye-modified-free-variable-dont-preserve-memoization-guarantees.js @@ -21,6 +21,9 @@ function Component(props) { mutate(x, free, part); return x; }, [props.value]); + + identity(free); + identity(part); return object; } diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useMemo-mabye-modified-free-variable-preserve-memoization-guarantees.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useMemo-mabye-modified-free-variable-preserve-memoization-guarantees.expect.md index 05fa49c84a..1d351ee2be 100644 --- a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useMemo-mabye-modified-free-variable-preserve-memoization-guarantees.expect.md +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useMemo-mabye-modified-free-variable-preserve-memoization-guarantees.expect.md @@ -12,16 +12,27 @@ import { } from "shared-runtime"; function Component(props) { + // With the feature enabled these variables are inferred as frozen as of + // the useMemo call const free = makeObject_Primitives(); const free2 = makeObject_Primitives(); const part = free2.part; + + // Thus their mutable range ends prior to this hook call, and both the above + // values and the useMemo block value can be memoized useHook(); + const object = useMemo(() => { const x = makeObject_Primitives(); x.value = props.value; mutate(x, free, part); return x; }, [props.value]); + + // These calls should be inferred as non-mutating due to the above freeze inference + identity(free); + identity(part); + return object; } @@ -63,6 +74,7 @@ function Component(props) { } const free2 = t1; const part = free2.part; + useHook(); let t39; let x; @@ -77,6 +89,9 @@ function Component(props) { } t39 = x; const object = t39; + + identity(free); + identity(part); return object; } diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useMemo-mabye-modified-free-variable-preserve-memoization-guarantees.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useMemo-mabye-modified-free-variable-preserve-memoization-guarantees.js index d0431124b2..276fe6aa0c 100644 --- a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useMemo-mabye-modified-free-variable-preserve-memoization-guarantees.js +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useMemo-mabye-modified-free-variable-preserve-memoization-guarantees.js @@ -8,16 +8,27 @@ import { } from "shared-runtime"; function Component(props) { + // With the feature enabled these variables are inferred as frozen as of + // the useMemo call const free = makeObject_Primitives(); const free2 = makeObject_Primitives(); const part = free2.part; + + // Thus their mutable range ends prior to this hook call, and both the above + // values and the useMemo block value can be memoized useHook(); + const object = useMemo(() => { const x = makeObject_Primitives(); x.value = props.value; mutate(x, free, part); return x; }, [props.value]); + + // These calls should be inferred as non-mutating due to the above freeze inference + identity(free); + identity(part); + return object; }