[forgive] Emit AutoDepsDecoration event when inferring effect deps (#32997)
Emits a new event for decorating inferred effect dependencies. Co-authored-by: Jordan Brown <jmbrown@meta.com> --- [//]: # (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 <jmbrown@meta.com>
lauren committed
Apr 23, 2025 at 20:51 UTC
cd7d236682ff3ba4996a5e1568f148bd6ac91862
2 files changed
+47
-1
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts
+7
-1
@@ -182,7 +182,8 @@ export type LoggerEvent =
182
| CompileDiagnosticEvent
183
| CompileSkipEvent
184
| PipelineErrorEvent
185
- | TimingEvent;
185
+ | TimingEvent
186
+ | AutoDepsDecorations;
187
188
export type CompileErrorEvent = {
189
kind: 'CompileError';
@@ -219,6 +220,11 @@ export type TimingEvent = {
220
kind: 'Timing';
221
measurement: PerformanceMeasure;
222
};
223
+export type AutoDepsDecorations = {
224
+ kind: 'AutoDepsDecorations';
225
+ useEffectCallExpr: t.SourceLocation | null;
226
+ decorations: Array<t.SourceLocation | null>;
227
+};
228
229
export type Logger = {
230
logEvent: (filename: string | null, event: LoggerEvent) => void;
compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts
+40
@@ -188,6 +188,7 @@ export function inferEffectDependencies(fn: HIRFunction): void {
188
* the `infer-effect-deps/pruned-nonreactive-obj` fixture for an
189
* explanation.
190
*/
191
+ const usedDeps = [];
192
for (const dep of scopeInfo.deps) {
193
if (
194
((isUseRefType(dep.identifier) ||
@@ -207,8 +208,19 @@ export function inferEffectDependencies(fn: HIRFunction): void {
208
);
209
newInstructions.push(...instructions);
210
effectDeps.push(place);
211
+ usedDeps.push(dep);
212
}
213
214
+ // For LSP autodeps feature.
215
+ fn.env.logger?.logEvent(fn.env.filename, {
216
+ kind: 'AutoDepsDecorations',
217
+ useEffectCallExpr:
218
+ typeof value.loc !== 'symbol' ? value.loc : null,
219
+ decorations: collectDepUsages(usedDeps, fnExpr.value).map(loc =>
220
+ typeof loc !== 'symbol' ? loc : null,
221
+ ),
222
+ });
223
+
224
newInstructions.push({
225
id: makeInstructionId(0),
226
loc: GeneratedSource,
@@ -340,3 +352,31 @@ function inferReactiveIdentifiers(fn: HIRFunction): Set<IdentifierId> {
352
}
353
return reactiveIds;
354
}
355
+
356
+function collectDepUsages(
357
+ deps: Array<ReactiveScopeDependency>,
358
+ fnExpr: FunctionExpression,
359
+): Array<SourceLocation> {
360
+ const identifiers: Map<IdentifierId, ReactiveScopeDependency> = new Map();
361
+ const loadedDeps: Set<IdentifierId> = new Set();
362
+ const sourceLocations = [];
363
+ for (const dep of deps) {
364
+ identifiers.set(dep.identifier.id, dep);
365
+ }
366
+
367
+ for (const [, block] of fnExpr.loweredFunc.func.body.blocks) {
368
+ for (const instr of block.instructions) {
369
+ if (instr.value.kind === 'LoadLocal') {
370
+ loadedDeps.add(instr.lvalue.identifier.id);
371
+ }
372
+ for (const place of eachInstructionOperand(instr)) {
373
+ if (loadedDeps.has(place.identifier.id)) {
374
+ // TODO(@jbrown215): handle member exprs!!
375
+ sourceLocations.push(place.identifier.loc);
376
+ }
377
+ }
378
+ }
379
+ }
380
+
381
+ return sourceLocations;
382
+}