compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateContextVariableLValues.ts TYPESCRIPT 135 lines View on github.com → Search inside
1/**2 * Copyright (c) Meta Platforms, Inc. and affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 */78import {CompilerDiagnostic, CompilerError} from '..';9import {ErrorCategory} from '../CompilerError';10import {Environment} from '../HIR/Environment';11import {HIRFunction, IdentifierId, Place} from '../HIR';12import {printPlace} from '../HIR/PrintHIR';13import {eachInstructionValueLValue, eachPatternOperand} from '../HIR/visitors';1415/**16 * Validates that all store/load references to a given named identifier align with the17 * "kind" of that variable (normal variable or context variable). For example, a context18 * variable may not be loaded/stored with regular StoreLocal/LoadLocal/Destructure instructions.19 */20export function validateContextVariableLValues(fn: HIRFunction): void {21  const identifierKinds: IdentifierKinds = new Map();22  validateContextVariableLValuesImpl(fn, identifierKinds, fn.env);23}2425function validateContextVariableLValuesImpl(26  fn: HIRFunction,27  identifierKinds: IdentifierKinds,28  env: Environment,29): void {30  for (const [, block] of fn.body.blocks) {31    for (const instr of block.instructions) {32      const {value} = instr;33      switch (value.kind) {34        case 'DeclareContext':35        case 'StoreContext': {36          visit(identifierKinds, value.lvalue.place, 'context', env);37          break;38        }39        case 'LoadContext': {40          visit(identifierKinds, value.place, 'context', env);41          break;42        }43        case 'StoreLocal':44        case 'DeclareLocal': {45          visit(identifierKinds, value.lvalue.place, 'local', env);46          break;47        }48        case 'LoadLocal': {49          visit(identifierKinds, value.place, 'local', env);50          break;51        }52        case 'PostfixUpdate':53        case 'PrefixUpdate': {54          visit(identifierKinds, value.lvalue, 'local', env);55          break;56        }57        case 'Destructure': {58          for (const lvalue of eachPatternOperand(value.lvalue.pattern)) {59            visit(identifierKinds, lvalue, 'destructure', env);60          }61          break;62        }63        case 'ObjectMethod':64        case 'FunctionExpression': {65          validateContextVariableLValuesImpl(66            value.loweredFunc.func,67            identifierKinds,68            env,69          );70          break;71        }72        default: {73          for (const _ of eachInstructionValueLValue(value)) {74            fn.env.recordError(75              CompilerDiagnostic.create({76                category: ErrorCategory.Todo,77                reason:78                  'ValidateContextVariableLValues: unhandled instruction variant',79                description: `Handle '${value.kind} lvalues`,80              }).withDetails({81                kind: 'error',82                loc: value.loc,83                message: null,84              }),85            );86          }87        }88      }89    }90  }91}9293type IdentifierKinds = Map<94  IdentifierId,95  {place: Place; kind: 'local' | 'context' | 'destructure'}96>;9798function visit(99  identifiers: IdentifierKinds,100  place: Place,101  kind: 'local' | 'context' | 'destructure',102  env: Environment,103): void {104  const prev = identifiers.get(place.identifier.id);105  if (prev !== undefined) {106    const wasContext = prev.kind === 'context';107    const isContext = kind === 'context';108    if (wasContext !== isContext) {109      if (prev.kind === 'destructure' || kind === 'destructure') {110        env.recordError(111          CompilerDiagnostic.create({112            category: ErrorCategory.Todo,113            reason: `Support destructuring of context variables`,114            description: null,115          }).withDetails({116            kind: 'error',117            loc: kind === 'destructure' ? place.loc : prev.place.loc,118            message: null,119          }),120        );121        return;122      }123124      CompilerError.invariant(false, {125        reason:126          'Expected all references to a variable to be consistently local or context references',127        description: `Identifier ${printPlace(place)} is referenced as a ${kind} variable, but was previously referenced as a ${prev.kind} variable`,128        message: `this is ${prev.kind}`,129        loc: place.loc,130      });131    }132  }133  identifiers.set(place.identifier.id, {place, kind});134}

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.