@samitouri / QOS-React-2 / commits / 4daa4eceb7

[validation] More detailed error diagnostics for validatePreserveExistingMemo

--- This should make it easier to grep through error diagnostics to understand state of the codebase: - no matching dependences -> likely that source is ignoring eslint failures - differences in ref.current access -> non-backwards compatible refs - subpath -> should be fixable in the compiler (unless source is ignore eslint failures)

Mofei Zhang committed Mar 20, 2024 at 16:05 UTC 4daa4eceb7577918fb07eea8b03dcd70cfa84e81
13 files changed +70 -20
compiler/packages/babel-plugin-react-forget/src/Validation/ValidatePreservedManualMemoization.ts
+56 -6
@@ -102,10 +102,41 @@ function prettyPrintScopeDependency(val: ReactiveScopeDependency): string {
102 return `${rootStr}${val.path.length > 0 ? "." : ""}${val.path.join(".")}`;
103 }
104
105 +enum CompareDependencyResult {
106 + Ok = 0,
107 + RootDifference = 1,
108 + PathDifference = 2,
109 + Subpath = 3,
110 + RefAccessDifference = 4,
111 +}
112 +
113 +function merge(
114 + a: CompareDependencyResult,
115 + b: CompareDependencyResult
116 +): CompareDependencyResult {
117 + return Math.max(a, b);
118 +}
119 +
120 +function getCompareDependencyResultDescription(
121 + result: CompareDependencyResult
122 +): string {
123 + switch (result) {
124 + case CompareDependencyResult.Ok:
125 + return "dependencies equal";
126 + case CompareDependencyResult.RootDifference:
127 + case CompareDependencyResult.PathDifference:
128 + return "inferred different dependency than source";
129 + case CompareDependencyResult.RefAccessDifference:
130 + return "differences in ref.current access";
131 + case CompareDependencyResult.Subpath:
132 + return "inferred less specific property than source";
133 + }
134 +}
135 +
136 function compareDeps(
137 inferred: ManualMemoDependency,
138 source: ManualMemoDependency
108 -): boolean {
139 +): CompareDependencyResult {
140 const rootsEqual =
141 (inferred.root.kind === "Global" &&
142 source.root.kind === "Global" &&
@@ -114,7 +145,7 @@ function compareDeps(
145 source.root.kind === "NamedLocal" &&
146 inferred.root.value.identifier.id === source.root.value.identifier.id);
147 if (!rootsEqual) {
117 - return false;
148 + return CompareDependencyResult.RootDifference;
149 }
150
151 let isSubpath = true;
@@ -131,9 +162,20 @@ function compareDeps(
162 (inferred.path.length >= source.path.length &&
163 !inferred.path.includes("current")))
164 ) {
134 - return true;
165 + return CompareDependencyResult.Ok;
166 } else {
136 - return false;
167 + if (isSubpath) {
168 + if (
169 + source.path.includes("current") ||
170 + inferred.path.includes("current")
171 + ) {
172 + return CompareDependencyResult.RefAccessDifference;
173 + } else {
174 + return CompareDependencyResult.Subpath;
175 + }
176 + } else {
177 + return CompareDependencyResult.PathDifference;
178 + }
179 }
180 }
181
@@ -197,9 +239,13 @@ function validateInferredDep(
239 return;
240 }
241 }
242 + let errorDiagnostic: CompareDependencyResult | null = null;
243 for (const originalDep of validDepsInMemoBlock) {
201 - if (compareDeps(normalizedDep, originalDep)) {
244 + const compareResult = compareDeps(normalizedDep, originalDep);
245 + if (compareResult === CompareDependencyResult.Ok) {
246 return;
247 + } else {
248 + errorDiagnostic = merge(errorDiagnostic ?? compareResult, compareResult);
249 }
250 }
251 errorState.push({
@@ -210,7 +256,11 @@ function validateInferredDep(
256 dep
257 )}\`, but the source dependencies were [${validDepsInMemoBlock
258 .map((dep) => printManualMemoDependency(dep, true))
213 - .join(", ")}]`,
259 + .join(", ")}]. Detail: ${
260 + errorDiagnostic
261 + ? getCompareDependencyResultDescription(errorDiagnostic)
262 + : "none"
263 + }`,
264 loc: GeneratedSource,
265 suggestions: null,
266 });
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-invalid-useCallback-read-maybeRef.expect.md
+1 -1
@@ -17,7 +17,7 @@ function useHook(maybeRef) {
17 ## Error
18
19 ```
20 -[ReactForget] 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]
20 +[ReactForget] 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
21 ```
22
23
\ 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
+1 -1
@@ -17,7 +17,7 @@ function useHook(maybeRef, shouldRead) {
17 ## Error
18
19 ```
20 -[ReactForget] 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]
20 +[ReactForget] 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
21 ```
22
23
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-aliased-var.expect.md
+1 -1
@@ -19,7 +19,7 @@ function useHook(x) {
19 ## Error
20
21 ```
22 -[ReactForget] 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]
22 +[ReactForget] 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
23 ```
24
25
\ 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
+1 -1
@@ -25,7 +25,7 @@ export const FIXTURE_ENTRYPOINT = {
25 ## Error
26
27 ```
28 -[ReactForget] 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]
28 +[ReactForget] 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
29 ```
30
31
\ 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
+1 -1
@@ -24,7 +24,7 @@ function Component({ propA, propB }) {
24 ## Error
25
26 ```
27 -[ReactForget] 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]
27 +[ReactForget] 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
30
\ 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
+1 -1
@@ -17,7 +17,7 @@ function Component({ propA }) {
17 ## Error
18
19 ```
20 -[ReactForget] 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]
20 +[ReactForget] 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
21 ```
22
23
\ 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
+1 -1
@@ -19,7 +19,7 @@ function useHook(x) {
19 ## Error
20
21 ```
22 -[ReactForget] 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]
22 +[ReactForget] 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
23 ```
24
25
\ 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
+2 -2
@@ -24,9 +24,9 @@ function Component({ propA, propB }) {
24 ## Error
25
26 ```
27 -[ReactForget] 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]
27 +[ReactForget] 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 -[ReactForget] 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]
29 +[ReactForget] 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
30 ```
31
32
\ 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
+2 -2
@@ -24,9 +24,9 @@ function Component({ propA, propB }) {
24 ## Error
25
26 ```
27 -[ReactForget] 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]
27 +[ReactForget] 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 -[ReactForget] 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]
29 +[ReactForget] 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
30 ```
31
32
\ 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
+1 -1
@@ -19,7 +19,7 @@ function Component({ propA }) {
19 ## Error
20
21 ```
22 -[ReactForget] 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]
22 +[ReactForget] 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
23 ```
24
25
\ 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
+1 -1
@@ -17,7 +17,7 @@ function Component({ propA }) {
17 ## Error
18
19 ```
20 -[ReactForget] 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]
20 +[ReactForget] 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
21 ```
22
23
\ 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
+1 -1
@@ -30,7 +30,7 @@ function useFoo(input1) {
30 ## Error
31
32 ```
33 -[ReactForget] 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]
33 +[ReactForget] 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
34 ```
35
36
\ No newline at end of file