Skip to content

Commit ec9cc00

Browse files
[compiler][poc] Reuse ValidateExhaustiveDeps for effect dep validation (#35285)
Alternative approach to #35282 for validating effect deps in the compiler that builds on the machinery in ValidateExhaustiveDependencies. Key changes to that pass: * Refactor to track the dependencies of array expressions as temporaries so we can look them up later if they appear as effect deps. * Instead of not storing temporaries for LoadLocals of locally created variables, we store the temporary but also propagate the local-ness through. This allows us to record deps at the top level, necessary for effect deps. Previously the pass was only ever concerned with tracking deps within function expressions. * Refactor the bulk of the dependency-checking logic from `onFinishMemoize()` into a standalone helper to use it for the new `onEffect()` helper as well. * Add a new ErrorCategory for effect deps, use it for errors on effects * Put the effect dep validation behind a feature flag * Adjust the error reason for effect errors --------- Co-authored-by: Jack Pope <[email protected]>
1 parent 380778d commit ec9cc00

20 files changed

+924
-303
lines changed

compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,8 @@ function printErrorSummary(category: ErrorCategory, message: string): string {
601601
case ErrorCategory.Syntax:
602602
case ErrorCategory.UseMemo:
603603
case ErrorCategory.VoidUseMemo:
604-
case ErrorCategory.MemoDependencies: {
604+
case ErrorCategory.MemoDependencies:
605+
case ErrorCategory.EffectExhaustiveDependencies: {
605606
heading = 'Error';
606607
break;
607608
}
@@ -683,6 +684,10 @@ export enum ErrorCategory {
683684
* Checks for memoized effect deps
684685
*/
685686
EffectDependencies = 'EffectDependencies',
687+
/**
688+
* Checks for exhaustive and extraneous effect dependencies
689+
*/
690+
EffectExhaustiveDependencies = 'EffectExhaustiveDependencies',
686691
/**
687692
* Checks for no setState in effect bodies
688693
*/
@@ -838,6 +843,16 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
838843
preset: LintRulePreset.Off,
839844
};
840845
}
846+
case ErrorCategory.EffectExhaustiveDependencies: {
847+
return {
848+
category,
849+
severity: ErrorSeverity.Error,
850+
name: 'exhaustive-effect-dependencies',
851+
description:
852+
'Validates that effect dependencies are exhaustive and without extraneous values',
853+
preset: LintRulePreset.Off,
854+
};
855+
}
841856
case ErrorCategory.EffectDerivationsOfState: {
842857
return {
843858
category,

compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,10 @@ function runWithEnvironment(
304304
log({kind: 'hir', name: 'InferReactivePlaces', value: hir});
305305

306306
if (env.enableValidations) {
307-
if (env.config.validateExhaustiveMemoizationDependencies) {
307+
if (
308+
env.config.validateExhaustiveMemoizationDependencies ||
309+
env.config.validateExhaustiveEffectDependencies
310+
) {
308311
// NOTE: this relies on reactivity inference running first
309312
validateExhaustiveDependencies(hir).unwrap();
310313
}

compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,11 @@ export const EnvironmentConfigSchema = z.object({
223223
*/
224224
validateExhaustiveMemoizationDependencies: z.boolean().default(true),
225225

226+
/**
227+
* Validate that dependencies supplied to effect hooks are exhaustive.
228+
*/
229+
validateExhaustiveEffectDependencies: z.boolean().default(false),
230+
226231
/**
227232
* When this is true, rather than pruning existing manual memoization but ensuring or validating
228233
* that the memoized values remain memoized, the compiler will simply not prune existing calls to

0 commit comments

Comments
 (0)