diff --git a/compiler/packages/babel-plugin-react-forget/src/Entrypoint/Program.ts b/compiler/packages/babel-plugin-react-forget/src/Entrypoint/Program.ts index f2572dd77c..7071754a9c 100644 --- a/compiler/packages/babel-plugin-react-forget/src/Entrypoint/Program.ts +++ b/compiler/packages/babel-plugin-react-forget/src/Entrypoint/Program.ts @@ -36,20 +36,27 @@ export type CompilerPass = { comments: (t.CommentBlock | t.CommentLine)[]; }; -function findUseForgetDirective(directives: t.Directive[]): t.Directive | null { +function findDirectiveEnablingMemoization( + directives: t.Directive[] +): t.Directive | null { for (const directive of directives) { - if (directive.value.value === "use forget") { + const directiveValue = directive.value.value; + if (directiveValue === "use forget" || directiveValue === "use memo") { return directive; } } return null; } -function findUseNoForgetDirective( +function findDirectiveDisablingMemoization( directives: t.Directive[] ): t.Directive | null { for (const directive of directives) { - if (directive.value.value === "use no forget") { + const directiveValue = directive.value.value; + if ( + directiveValue === "use no forget" || + directiveValue === "use no memo" + ) { return directive; } } @@ -189,7 +196,7 @@ export function compileProgram( pass: CompilerPass ): void { // Top level "use no forget", skip this file entirely - if (findUseNoForgetDirective(program.node.directives) != null) { + if (findDirectiveDisablingMemoization(program.node.directives) != null) { return; } @@ -372,7 +379,9 @@ export function shouldVisitNode(fn: BabelFn, pass: CompilerPass): boolean { } if (fn.node.body.type === "BlockStatement") { // Opt-outs disable compilation regardless of mode - const useNoForget = findUseNoForgetDirective(fn.node.body.directives); + const useNoForget = findDirectiveDisablingMemoization( + fn.node.body.directives + ); if (useNoForget != null) { pass.opts.logger?.logEvent(pass.filename, { kind: "CompileError", @@ -387,7 +396,7 @@ export function shouldVisitNode(fn: BabelFn, pass: CompilerPass): boolean { return false; } // Otherwise opt-ins enable compilation regardless of mode - if (findUseForgetDirective(fn.node.body.directives) != null) { + if (findDirectiveEnablingMemoization(fn.node.body.directives) != null) { return true; } } diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-memo-simple.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-memo-simple.expect.md new file mode 100644 index 0000000000..d21466648d --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-memo-simple.expect.md @@ -0,0 +1,54 @@ + +## Input + +```javascript +function Component(props) { + "use memo"; + let x = [props.foo]; + return
"foo"
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ foo: 1 }], + isComponent: true, +}; + +``` + +## Code + +```javascript +import { unstable_useMemoCache as useMemoCache } from "react"; +function Component(props) { + const $ = useMemoCache(4); + let t0; + if ($[0] !== props.foo) { + t0 = [props.foo]; + $[0] = props.foo; + $[1] = t0; + } else { + t0 = $[1]; + } + const x = t0; + let t1; + if ($[2] !== x) { + t1 =
"foo"
; + $[2] = x; + $[3] = t1; + } else { + t1 = $[3]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ foo: 1 }], + isComponent: true, +}; + +``` + +### Eval output +(kind: ok)
"foo"
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-memo-simple.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-memo-simple.js new file mode 100644 index 0000000000..3166f45d95 --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-memo-simple.js @@ -0,0 +1,11 @@ +function Component(props) { + "use memo"; + let x = [props.foo]; + return
"foo"
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ foo: 1 }], + isComponent: true, +}; diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-no-memo-module-level.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-no-memo-module-level.expect.md new file mode 100644 index 0000000000..ef306c8291 --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-no-memo-module-level.expect.md @@ -0,0 +1,29 @@ + +## Input + +```javascript +"use no memo"; + +export default function foo(x, y) { + if (x) { + return foo(false, y); + } + return [y * 10]; +} + +``` + +## Code + +```javascript +"use no memo"; + +export default function foo(x, y) { + if (x) { + return foo(false, y); + } + return [y * 10]; +} + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-no-memo-module-level.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-no-memo-module-level.js new file mode 100644 index 0000000000..a7a740e8b9 --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-no-memo-module-level.js @@ -0,0 +1,8 @@ +"use no memo"; + +export default function foo(x, y) { + if (x) { + return foo(false, y); + } + return [y * 10]; +} diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-no-memo-simple.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-no-memo-simple.expect.md new file mode 100644 index 0000000000..f8ddf9af96 --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-no-memo-simple.expect.md @@ -0,0 +1,37 @@ + +## Input + +```javascript +function Component(props) { + "use no memo"; + let x = [props.foo]; + return
"foo"
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ foo: 1 }], + isComponent: true, +}; + +``` + +## Code + +```javascript +function Component(props) { + "use no memo"; + let x = [props.foo]; + return
"foo"
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ foo: 1 }], + isComponent: true, +}; + +``` + +### Eval output +(kind: ok)
"foo"
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-no-memo-simple.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-no-memo-simple.js new file mode 100644 index 0000000000..2a525e275b --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/use-no-memo-simple.js @@ -0,0 +1,11 @@ +function Component(props) { + "use no memo"; + let x = [props.foo]; + return
"foo"
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ foo: 1 }], + isComponent: true, +}; diff --git a/compiler/packages/sprout/src/SproutTodoFilter.ts b/compiler/packages/sprout/src/SproutTodoFilter.ts index d7ce84f7dc..33ab9597ae 100644 --- a/compiler/packages/sprout/src/SproutTodoFilter.ts +++ b/compiler/packages/sprout/src/SproutTodoFilter.ts @@ -385,6 +385,7 @@ const skipFilter = new Set([ "useMemo-return-empty", "useMemo-simple", "use-no-forget-module-level", + "use-no-memo-module-level", // defines multiple functions "alias-while", "babel-existing-react-import",