From cd7d236682ff3ba4996a5e1568f148bd6ac91862 Mon Sep 17 00:00:00 2001 From: lauren Date: Wed, 23 Apr 2025 20:51:38 -0400 Subject: [PATCH] [forgive] Emit AutoDepsDecoration event when inferring effect deps (#32997) Emits a new event for decorating inferred effect dependencies. Co-authored-by: Jordan Brown --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32997). * #33002 * #33001 * #33000 * #32999 * #32998 * __->__ #32997 * #32996 --------- Co-authored-by: Jordan Brown --- .../src/Entrypoint/Options.ts | 8 +++- .../src/Inference/InferEffectDependencies.ts | 40 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts index e0c670c564..db55673fa1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts @@ -182,7 +182,8 @@ export type LoggerEvent = | CompileDiagnosticEvent | CompileSkipEvent | PipelineErrorEvent - | TimingEvent; + | TimingEvent + | AutoDepsDecorations; export type CompileErrorEvent = { kind: 'CompileError'; @@ -219,6 +220,11 @@ export type TimingEvent = { kind: 'Timing'; measurement: PerformanceMeasure; }; +export type AutoDepsDecorations = { + kind: 'AutoDepsDecorations'; + useEffectCallExpr: t.SourceLocation | null; + decorations: Array; +}; export type Logger = { logEvent: (filename: string | null, event: LoggerEvent) => void; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts index 0d27ac7ca0..e14b1af115 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts @@ -188,6 +188,7 @@ export function inferEffectDependencies(fn: HIRFunction): void { * the `infer-effect-deps/pruned-nonreactive-obj` fixture for an * explanation. */ + const usedDeps = []; for (const dep of scopeInfo.deps) { if ( ((isUseRefType(dep.identifier) || @@ -207,8 +208,19 @@ export function inferEffectDependencies(fn: HIRFunction): void { ); newInstructions.push(...instructions); effectDeps.push(place); + usedDeps.push(dep); } + // For LSP autodeps feature. + fn.env.logger?.logEvent(fn.env.filename, { + kind: 'AutoDepsDecorations', + useEffectCallExpr: + typeof value.loc !== 'symbol' ? value.loc : null, + decorations: collectDepUsages(usedDeps, fnExpr.value).map(loc => + typeof loc !== 'symbol' ? loc : null, + ), + }); + newInstructions.push({ id: makeInstructionId(0), loc: GeneratedSource, @@ -340,3 +352,31 @@ function inferReactiveIdentifiers(fn: HIRFunction): Set { } return reactiveIds; } + +function collectDepUsages( + deps: Array, + fnExpr: FunctionExpression, +): Array { + const identifiers: Map = new Map(); + const loadedDeps: Set = new Set(); + const sourceLocations = []; + for (const dep of deps) { + identifiers.set(dep.identifier.id, dep); + } + + for (const [, block] of fnExpr.loweredFunc.func.body.blocks) { + for (const instr of block.instructions) { + if (instr.value.kind === 'LoadLocal') { + loadedDeps.add(instr.lvalue.identifier.id); + } + for (const place of eachInstructionOperand(instr)) { + if (loadedDeps.has(place.identifier.id)) { + // TODO(@jbrown215): handle member exprs!! + sourceLocations.push(place.identifier.loc); + } + } + } + } + + return sourceLocations; +}