From db7e7c7fae69e54fee8751b10790827e2dea0ac2 Mon Sep 17 00:00:00 2001 From: Sathya Gunasekaran Date: Fri, 22 Mar 2024 23:42:27 +0000 Subject: [PATCH] Support method call when validating useEffect Treat MethodCall similarly to CallExpression when validation useEffect --- .../src/Inference/InferReferenceEffects.ts | 16 +++++++- .../compiler/useEffect-method-call.expect.md | 37 +++++++++++++++++++ .../compiler/useEffect-method-call.js | 11 ++++++ 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useEffect-method-call.expect.md create mode 100644 compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useEffect-method-call.js diff --git a/compiler/packages/babel-plugin-react-forget/src/Inference/InferReferenceEffects.ts b/compiler/packages/babel-plugin-react-forget/src/Inference/InferReferenceEffects.ts index 97d23ee340..20efae0b61 100644 --- a/compiler/packages/babel-plugin-react-forget/src/Inference/InferReferenceEffects.ts +++ b/compiler/packages/babel-plugin-react-forget/src/Inference/InferReferenceEffects.ts @@ -1190,7 +1190,9 @@ function inferBlock( const effects = signature !== null ? getFunctionEffects(instrValue, signature) : null; let hasCaptureArgument = false; + let isUseEffect = isEffectHook(instrValue.property.identifier); for (let i = 0; i < instrValue.args.length; i++) { + const argumentEffects: Array = []; const arg = instrValue.args[i]; const place = arg.kind === "Identifier" ? arg : arg.place; if (effects !== null) { @@ -1200,18 +1202,28 @@ function inferBlock( */ state.reference( place, - functionEffects, + argumentEffects, effects[i], ValueReason.Other ); } else { state.reference( place, - functionEffects, + argumentEffects, Effect.ConditionallyMutate, ValueReason.Other ); } + /* + * Join the effects of the argument with the effects of the enclosing function, + * unless the we're detecting a global mutation inside a useEffect hook + */ + functionEffects.push( + ...argumentEffects.filter( + (argEffect) => + !isUseEffect || i !== 0 || argEffect.kind !== "GlobalMutation" + ) + ); hasCaptureArgument ||= place.effect === Effect.Capture; } if (signature !== null) { diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useEffect-method-call.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useEffect-method-call.expect.md new file mode 100644 index 0000000000..dbb0a0da8b --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useEffect-method-call.expect.md @@ -0,0 +1,37 @@ + +## Input + +```javascript +let x = {}; +function Component() { + React.useEffect(() => { + x.foo = 1; + }); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], +}; + +``` + +## Code + +```javascript +let x = {}; +function Component() { + React.useEffect(() => { + x.foo = 1; + }); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], +}; + +``` + +### Eval output +(kind: ok) \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useEffect-method-call.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useEffect-method-call.js new file mode 100644 index 0000000000..c536fbe905 --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/useEffect-method-call.js @@ -0,0 +1,11 @@ +let x = {}; +function Component() { + React.useEffect(() => { + x.foo = 1; + }); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], +};