@samitouri / QOS-React / commits / a9732d65b4

[dx] Improve error messages for unpreserved memoization

ghstack-source-id: ff5bcaa7ab219035f57dc3dc3396c9a324896d4b Pull Request resolved: https://github.com/facebook/react-forget/pull/2869

Joe Savona committed Apr 18, 2024 at 09:49 UTC a9732d65b48b73c1dabb3e3d218eed7d3a1885cc
26 files changed +205 -46
compiler/packages/babel-plugin-react-forget/src/CompilerError.ts
+1 -1
@@ -23,7 +23,7 @@ export enum ErrorSeverity {
23 */
24 InvalidConfig = "InvalidConfig",
25 /**
26 - * Code that can reasonably occur and that doesn't break any rules, but is unsafe to perserve
26 + * Code that can reasonably occur and that doesn't break any rules, but is unsafe to preserve
27 * memoization.
28 */
29 CannotPreserveMemoization = "CannotPreserveMemoization",
compiler/packages/babel-plugin-react-forget/src/Validation/ValidateMemoizedEffectDependencies.ts
+2 -2
@@ -104,9 +104,9 @@ class Visitor extends ReactiveFunctionVisitor<CompilerError> {
104 ) {
105 state.push({
106 reason:
107 - "This effect may trigger an infinite loop: one or more of its dependencies could not be memoized due to a later mutation",
107 + "React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior",
108 description: null,
109 - severity: ErrorSeverity.InvalidReact,
109 + severity: ErrorSeverity.CannotPreserveMemoization,
110 loc: typeof instruction.loc !== "symbol" ? instruction.loc : null,
111 suggestions: null,
112 });
compiler/packages/babel-plugin-react-forget/src/Validation/ValidatePreservedManualMemoization.ts
+26 -15
@@ -20,6 +20,7 @@ import {
20 ReactiveScopeDependency,
21 ReactiveValue,
22 ScopeId,
23 + SourceLocation,
24 } from "../HIR";
25 import { printManualMemoDependency } from "../HIR/PrintHIR";
26 import { eachInstructionValueOperand } from "../HIR/visitors";
@@ -48,7 +49,12 @@ export function validatePreservedManualMemoization(fn: ReactiveFunction): void {
49 }
50 }
51
52 +const DEBUG = false;
53 +
54 type ManualMemoBlockState = {
55 + // The source of the original memoization, used when reporting errors
56 + loc: SourceLocation;
57 +
58 /**
59 * Values produced within manual memoization blocks.
60 * We track these to ensure our inferred dependencies are
@@ -201,7 +207,8 @@ function validateInferredDep(
207 temporaries: Map<IdentifierId, ManualMemoDependency>,
208 declsWithinMemoBlock: Set<IdentifierId>,
209 validDepsInMemoBlock: Array<ManualMemoDependency>,
204 - errorState: CompilerError
210 + errorState: CompilerError,
211 + memoLocation: SourceLocation
212 ): void {
213 let normalizedDep: ManualMemoDependency;
214 const maybeNormalizedRoot = temporaries.get(dep.identifier.id);
@@ -249,19 +256,21 @@ function validateInferredDep(
256 }
257 }
258 errorState.push({
252 - severity: ErrorSeverity.Todo,
259 + severity: ErrorSeverity.CannotPreserveMemoization,
260 reason:
254 - "Could not preserve manual memoization because an inferred dependency does not match the dependency list in source",
255 - description: `The inferred dependency was \`${prettyPrintScopeDependency(
256 - dep
257 - )}\`, but the source dependencies were [${validDepsInMemoBlock
258 - .map((dep) => printManualMemoDependency(dep, true))
259 - .join(", ")}]. Detail: ${
260 - errorDiagnostic
261 - ? getCompareDependencyResultDescription(errorDiagnostic)
262 - : "none"
263 - }`,
264 - loc: GeneratedSource,
261 + "React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected",
262 + description: DEBUG
263 + ? `The inferred dependency was \`${prettyPrintScopeDependency(
264 + dep
265 + )}\`, but the source dependencies were [${validDepsInMemoBlock
266 + .map((dep) => printManualMemoDependency(dep, true))
267 + .join(", ")}]. Detail: ${
268 + errorDiagnostic
269 + ? getCompareDependencyResultDescription(errorDiagnostic)
270 + : "none"
271 + }`
272 + : null,
273 + loc: memoLocation,
274 suggestions: null,
275 });
276 }
@@ -359,7 +368,8 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
368 this.temporaries,
369 state.manualMemoState.decls,
370 state.manualMemoState.depsFromSource,
362 - state.errors
371 + state.errors,
372 + state.manualMemoState.loc
373 );
374 }
375 }
@@ -405,6 +415,7 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
415 });
416
417 state.manualMemoState = {
418 + loc: instruction.loc,
419 decls: new Set(),
420 depsFromSource,
421 manualMemoId: instruction.value.manualMemoId,
@@ -437,7 +448,7 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
448 ) {
449 state.errors.push({
450 reason:
440 - "This value was manually memoized, but cannot be memoized under Forget because it may be mutated after it is memoized",
451 + "React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value may be mutated later, which could cause the value to change unexpectedly",
452 description: null,
453 severity: ErrorSeverity.CannotPreserveMemoization,
454 loc: typeof instruction.loc !== "symbol" ? instruction.loc : null,
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.invalid-useEffect-dep-not-memoized-bc-range-overlaps-hook.expect.md
+1 -1
@@ -30,7 +30,7 @@ function Component(props) {
30 > 10 | console.log(items);
31 | ^^^^^^^^^^^^^^^^^^^^^^^
32 > 11 | }, [items]);
33 - | ^^^^^^^^^^^^^^ InvalidReact: This effect may trigger an infinite loop: one or more of its dependencies could not be memoized due to a later mutation (9:11)
33 + | ^^^^^^^^^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior (9:11)
34 12 |
35 13 | return [items, state];
36 14 | }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.invalid-useEffect-dep-not-memoized.expect.md
+1 -1
@@ -27,7 +27,7 @@ function Component(props) {
27 > 7 | console.log(props.value);
28 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29 > 8 | }, [data]);
30 - | ^^^^^^^^^^^^^ InvalidReact: This effect may trigger an infinite loop: one or more of its dependencies could not be memoized due to a later mutation (6:8)
30 + | ^^^^^^^^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior (6:8)
31 9 | mutate(data);
32 10 | return data;
33 11 | }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.invalid-useInsertionEffect-dep-not-memoized.expect.md
+1 -1
@@ -27,7 +27,7 @@ function Component(props) {
27 > 7 | console.log(props.value);
28 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29 > 8 | }, [data]);
30 - | ^^^^^^^^^^^^^ InvalidReact: This effect may trigger an infinite loop: one or more of its dependencies could not be memoized due to a later mutation (6:8)
30 + | ^^^^^^^^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior (6:8)
31 9 | mutate(data);
32 10 | return data;
33 11 | }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.invalid-useLayoutEffect-dep-not-memoized.expect.md
+1 -1
@@ -27,7 +27,7 @@ function Component(props) {
27 > 7 | console.log(props.value);
28 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29 > 8 | }, [data]);
30 - | ^^^^^^^^^^^^^ InvalidReact: This effect may trigger an infinite loop: one or more of its dependencies could not be memoized due to a later mutation (6:8)
30 + | ^^^^^^^^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior (6:8)
31 9 | mutate(data);
32 10 | return data;
33 11 | }
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-repro-unmemoized-callback-captured-in-context-variable.expect.md
+1 -1
@@ -53,7 +53,7 @@ export const FIXTURE_ENTRYPOINT = {
53 9 | const a = useHook();
54 10 | // Because b is also part of that same mutable range, it can't be memoized either
55 > 11 | const b = useMemo(() => ({}), []);
56 - | ^^^^^^^^^^ CannotPreserveMemoization: This value was manually memoized, but cannot be memoized under Forget because it may be mutated after it is memoized (11:11)
56 + | ^^^^^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value may be mutated later, which could cause the value to change unexpectedly (11:11)
57 12 |
58 13 | // Conditional assignment without a subsequent mutation normally doesn't create a mutable
59 14 | // range, but in this case we're reassigning a context variable
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md
+1 -1
@@ -45,7 +45,7 @@ export const FIXTURE_ENTRYPOINT = {
45 > 10 | ref.current.inner = event.target.value;
46 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
47 > 11 | });
48 - | ^^^^ CannotPreserveMemoization: This value was manually memoized, but cannot be memoized under Forget because it may be mutated after it is memoized (7:11)
48 + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value may be mutated later, which could cause the value to change unexpectedly (7:11)
49 12 |
50 13 | // The ref is modified later, extending its range and preventing memoization of onChange
51 14 | const reset = () => {
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md
+1 -1
@@ -42,7 +42,7 @@ export const FIXTURE_ENTRYPOINT = {
42 > 10 | ref.current.inner = event.target.value;
43 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
44 > 11 | });
45 - | ^^^^ CannotPreserveMemoization: This value was manually memoized, but cannot be memoized under Forget because it may be mutated after it is memoized (7:11)
45 + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value may be mutated later, which could cause the value to change unexpectedly (7:11)
46 12 |
47 13 | // The ref is modified later, extending its range and preventing memoization of onChange
48 14 | ref.current.inner = null;
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/error.validate-memoized-effect-deps-invalidated-dep-value.expect.md
+1 -1
@@ -35,7 +35,7 @@ export const FIXTURE_ENTRYPOINT = {
35 > 12 | console.log(y);
36 | ^^^^^^^^^^^^^^^^^^^
37 > 13 | }, [y]);
38 - | ^^^^^^^^^^ InvalidReact: This effect may trigger an infinite loop: one or more of its dependencies could not be memoized due to a later mutation (11:13)
38 + | ^^^^^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior (11:13)
39 14 | }
40 15 |
41 16 | export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.false-positive-useMemo-infer-mutate-deps.expect.md
+1 -1
@@ -36,7 +36,7 @@ export const FIXTURE_ENTRYPOINT = {
36 > 13 | return identity(val);
37 | ^^^^^^^^^^^^^^^^^^^^^^^^^
38 > 14 | }, [val]);
39 - | ^^^^ CannotPreserveMemoization: This value was manually memoized, but cannot be memoized under Forget because it may be mutated after it is memoized (12:14)
39 + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value may be mutated later, which could cause the value to change unexpectedly (12:14)
40 15 | }
41 16 |
42 17 | export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.invalid-useCallback-captures-reassigned-context.expect.md
+2 -2
@@ -33,9 +33,9 @@ export const FIXTURE_ENTRYPOINT = {
33 10 |
34 11 | // makeArray() is captured, but depsList contains [props]
35 > 12 | const cb = useCallback(() => [x], [x]);
36 - | ^^^^^^^^^ CannotPreserveMemoization: This value was manually memoized, but cannot be memoized under Forget because it may be mutated after it is memoized (12:12)
36 + | ^^^^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value may be mutated later, which could cause the value to change unexpectedly (12:12)
37
38 -CannotPreserveMemoization: This value was manually memoized, but cannot be memoized under Forget because it may be mutated after it is memoized (12:12)
38 +CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value may be mutated later, which could cause the value to change unexpectedly (12:12)
39 13 |
40 14 | x = makeArray();
41 15 |
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-invalid-useCallback-read-maybeRef.expect.md
+10 -1
@@ -17,7 +17,16 @@ function useHook(maybeRef) {
17 ## Error
18
19 ```
20 -Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `maybeRef.current`, but the source dependencies were [maybeRef]. Detail: differences in ref.current access
20 + 3 |
21 + 4 | function useHook(maybeRef) {
22 +> 5 | return useCallback(() => {
23 + | ^^^^^^^
24 +> 6 | return [maybeRef.current];
25 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
26 +> 7 | }, [maybeRef]);
27 + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (5:7)
28 + 8 | }
29 + 9 |
30 ```
31
32
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-invalid-useMemo-read-maybeRef.expect.md
+10 -1
@@ -17,7 +17,16 @@ function useHook(maybeRef, shouldRead) {
17 ## Error
18
19 ```
20 -Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `maybeRef.current`, but the source dependencies were [shouldRead, maybeRef]. Detail: differences in ref.current access
20 + 3 |
21 + 4 | function useHook(maybeRef, shouldRead) {
22 +> 5 | return useMemo(() => {
23 + | ^^^^^^^
24 +> 6 | return () => [maybeRef.current];
25 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
26 +> 7 | }, [shouldRead, maybeRef]);
27 + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (5:7)
28 + 8 | }
29 + 9 |
30 ```
31
32
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.todo-useCallback-captures-invalidating-value.expect.md
+1 -1
@@ -31,7 +31,7 @@ export const FIXTURE_ENTRYPOINT = {
31 11 | x.push(props);
32 12 |
33 > 13 | return useCallback(() => [x], [x]);
34 - | ^^^^^^^^^ CannotPreserveMemoization: This value was manually memoized, but cannot be memoized under Forget because it may be mutated after it is memoized (13:13)
34 + | ^^^^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value may be mutated later, which could cause the value to change unexpectedly (13:13)
35 14 | }
36 15 |
37 16 | export const FIXTURE_ENTRYPOINT = {
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-aliased-var.expect.md
+6 -1
@@ -19,7 +19,12 @@ function useHook(x) {
19 ## Error
20
21 ```
22 -Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `aliasedX`, but the source dependencies were [x, aliasedProp]. Detail: inferred different dependency than source
22 + 7 | const aliasedProp = x.y.z;
23 + 8 |
24 +> 9 | return useCallback(() => [aliasedX, x.y.z], [x, aliasedProp]);
25 + | ^^^^^^^^^^^^^^^^^^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (9:9)
26 + 10 | }
27 + 11 |
28 ```
29
30
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-conditional-access-noAlloc.expect.md
+17 -1
@@ -25,7 +25,23 @@ export const FIXTURE_ENTRYPOINT = {
25 ## Error
26
27 ```
28 -Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propB`, but the source dependencies were [propA, propB.x.y]. Detail: inferred less specific property than source
28 + 3 |
29 + 4 | function Component({ propA, propB }) {
30 +> 5 | return useCallback(() => {
31 + | ^^^^^^^
32 +> 6 | return {
33 + | ^^^^^^^^^^^^
34 +> 7 | value: propB?.x.y,
35 + | ^^^^^^^^^^^^
36 +> 8 | other: propA,
37 + | ^^^^^^^^^^^^
38 +> 9 | };
39 + | ^^^^^^^^^^^^
40 +> 10 | }, [propA, propB.x.y]);
41 + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (5:10)
42 + 11 | }
43 + 12 |
44 + 13 | export const FIXTURE_ENTRYPOINT = {
45 ```
46
47
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-infer-less-specific-conditional-access.expect.md
+22 -1
@@ -24,7 +24,28 @@ function Component({ propA, propB }) {
24 ## Error
25
26 ```
27 -Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.a, propB.x.y]. Detail: inferred less specific property than source
27 + 4 |
28 + 5 | function Component({ propA, propB }) {
29 +> 6 | return useCallback(() => {
30 + | ^^^^^^^
31 +> 7 | const x = {};
32 + | ^^^^^^^^^^^^^^^^^
33 +> 8 | if (propA?.a) {
34 + | ^^^^^^^^^^^^^^^^^
35 +> 9 | mutate(x);
36 + | ^^^^^^^^^^^^^^^^^
37 +> 10 | return {
38 + | ^^^^^^^^^^^^^^^^^
39 +> 11 | value: propB.x.y,
40 + | ^^^^^^^^^^^^^^^^^
41 +> 12 | };
42 + | ^^^^^^^^^^^^^^^^^
43 +> 13 | }
44 + | ^^^^^^^^^^^^^^^^^
45 +> 14 | }, [propA?.a, propB.x.y]);
46 + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (6:14)
47 + 15 | }
48 + 16 |
49 ```
50
51
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-property-call-dep.expect.md
+10 -1
@@ -17,7 +17,16 @@ function Component({ propA }) {
17 ## Error
18
19 ```
20 -Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.x]. Detail: inferred less specific property than source
20 + 3 |
21 + 4 | function Component({ propA }) {
22 +> 5 | return useCallback(() => {
23 + | ^^^^^^^
24 +> 6 | return propA.x();
25 + | ^^^^^^^^^^^^^^^^^^^^^
26 +> 7 | }, [propA.x]);
27 + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (5:7)
28 + 8 | }
29 + 9 |
30 ```
31
32
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-aliased-var.expect.md
+6 -1
@@ -19,7 +19,12 @@ function useHook(x) {
19 ## Error
20
21 ```
22 -Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `x`, but the source dependencies were [aliasedX, aliasedProp]. Detail: inferred different dependency than source
22 + 7 | const aliasedProp = x.y.z;
23 + 8 |
24 +> 9 | return useMemo(() => [x, x.y.z], [aliasedX, aliasedProp]);
25 + | ^^^^^^^^^^^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (9:9)
26 + 10 | }
27 + 11 |
28 ```
29
30
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-infer-less-specific-conditional-access.expect.md
+24 -3
@@ -24,9 +24,30 @@ function Component({ propA, propB }) {
24 ## Error
25
26 ```
27 -Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.a, propB.x.y]. Detail: inferred less specific property than source
28 -
29 -Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propB`, but the source dependencies were [propA.a, propB.x.y]. Detail: inferred less specific property than source
27 + 4 |
28 + 5 | function Component({ propA, propB }) {
29 +> 6 | return useMemo(() => {
30 + | ^^^^^^^
31 +> 7 | const x = {};
32 + | ^^^^^^^^^^^^^^^^^
33 +> 8 | if (propA?.a) {
34 + | ^^^^^^^^^^^^^^^^^
35 +> 9 | mutate(x);
36 + | ^^^^^^^^^^^^^^^^^
37 +> 10 | return {
38 + | ^^^^^^^^^^^^^^^^^
39 +> 11 | value: propB.x.y,
40 + | ^^^^^^^^^^^^^^^^^
41 +> 12 | };
42 + | ^^^^^^^^^^^^^^^^^
43 +> 13 | }
44 + | ^^^^^^^^^^^^^^^^^
45 +> 14 | }, [propA?.a, propB.x.y]);
46 + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (6:14)
47 +
48 +CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (6:14)
49 + 15 | }
50 + 16 |
51 ```
52
53
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-infer-less-specific-conditional-value-block.expect.md
+24 -3
@@ -24,9 +24,30 @@ function Component({ propA, propB }) {
24 ## Error
25
26 ```
27 -Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.a, propB.x.y]. Detail: inferred less specific property than source
28 -
29 -Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propB`, but the source dependencies were [propA.a, propB.x.y]. Detail: inferred less specific property than source
27 + 4 |
28 + 5 | function Component({ propA, propB }) {
29 +> 6 | return useMemo(() => {
30 + | ^^^^^^^
31 +> 7 | const x = {};
32 + | ^^^^^^^^^^^^^^^^^
33 +> 8 | if (identity(null) ?? propA.a) {
34 + | ^^^^^^^^^^^^^^^^^
35 +> 9 | mutate(x);
36 + | ^^^^^^^^^^^^^^^^^
37 +> 10 | return {
38 + | ^^^^^^^^^^^^^^^^^
39 +> 11 | value: propB.x.y,
40 + | ^^^^^^^^^^^^^^^^^
41 +> 12 | };
42 + | ^^^^^^^^^^^^^^^^^
43 +> 13 | }
44 + | ^^^^^^^^^^^^^^^^^
45 +> 14 | }, [propA.a, propB.x.y]);
46 + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (6:14)
47 +
48 +CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (6:14)
49 + 15 | }
50 + 16 |
51 ```
52
53
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-property-call-chained-object.expect.md
+14 -1
@@ -19,7 +19,20 @@ function Component({ propA }) {
19 ## Error
20
21 ```
22 -Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.x]. Detail: inferred less specific property than source
22 + 3 |
23 + 4 | function Component({ propA }) {
24 +> 5 | return useMemo(() => {
25 + | ^^^^^^^
26 +> 6 | return {
27 + | ^^^^^^^^^^^^
28 +> 7 | value: propA.x().y,
29 + | ^^^^^^^^^^^^
30 +> 8 | };
31 + | ^^^^^^^^^^^^
32 +> 9 | }, [propA.x]);
33 + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (5:9)
34 + 10 | }
35 + 11 |
36 ```
37
38
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-property-call-dep.expect.md
+10 -1
@@ -17,7 +17,16 @@ function Component({ propA }) {
17 ## Error
18
19 ```
20 -Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.x]. Detail: inferred less specific property than source
20 + 3 |
21 + 4 | function Component({ propA }) {
22 +> 5 | return useMemo(() => {
23 + | ^^^^^^^
24 +> 6 | return propA.x();
25 + | ^^^^^^^^^^^^^^^^^^^^^
26 +> 7 | }, [propA.x]);
27 + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (5:7)
28 + 8 | }
29 + 9 |
30 ```
31
32
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-unrelated-mutation-in-depslist.expect.md
+11 -1
@@ -30,7 +30,17 @@ function useFoo(input1) {
30 ## Error
31
32 ```
33 -Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `input1`, but the source dependencies were [y]. Detail: inferred different dependency than source
33 + 14 | const x = {};
34 + 15 | const y = [input1];
35 +> 16 | const memoized = useMemo(() => {
36 + | ^^^^^^^
37 +> 17 | return [y];
38 + | ^^^^^^^^^^^^^^^
39 +> 18 | }, [(mutate(x), y)]);
40 + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (16:18)
41 + 19 |
42 + 20 | return [x, memoized];
43 + 21 | }
44 ```
45
46
\ No newline at end of file