Repository: facebook/react
File: compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects_exp.ts (TypeScript)

Code before:
    }

    typeOfValue = joinValue(typeOfValue, operandMetadata.typeOfValue);
    for (const id of operandMetadata.sourcesIds) {
      sources.add(id);
    }
  }

  if (typeOfValue === 'ignored') {
    return;
  }

  for (const lvalue of eachInstructionLValue(instr)) {
    context.derivationCache.addDerivationEntry(lvalue, sources, typeOfValue);
  }

  for (const operand of eachInstructionOperand(instr)) {
    switch (operand.effect) {
      case Effect.Capture:
      case Effect.Store:
      case Effect.ConditionallyMutate:
      case Effect.ConditionallyMutateIterator:
      case Effect.Mutate: {
        if (
          isMutable(instr, operand) &&
          context.derivationCache.cache.has(operand.identifier.id)
        ) {
          const operandMetadata = context.derivationCache.cache.get(
            operand.identifier.id,
          );

          if (operandMetadata !== undefined) {
            operandMetadata.typeOfValue = joinValue(
              typeOfValue,
              operandMetadata.typeOfValue,
            );
          }
        }
        break;
      }
      case Effect.Freeze:
      case Effect.Read: {
        // no-op
        break;
      }
      case Effect.Unknown: {
        CompilerError.invariant(false, {
          reason: 'Unexpected unknown effect',
          description: null,
          details: [
            {

Review comment (performance):
If the derivation cache does not already have this entry, we still may want to record a `typeOfValue`. Or is this already handled by your fixpoint iteration logic?

```js
function useHook() {
  const [s, setS] = useState();
  const cb = () => append(arr, s);  // `arr` is mutable here and should get marked as `fromState` 
  const arr = [];
}
```

Code after:
    }

    typeOfValue = joinValue(typeOfValue, operandMetadata.typeOfValue);
    for (const id of operandMetadata.sourcesIds) {
      sources.add(id);
    }
  }

  if (typeOfValue === 'ignored') {
    return;
  }

  for (const lvalue of eachInstructionLValue(instr)) {
    context.derivationCache.addDerivationEntry(lvalue, sources, typeOfValue);
  }

  for (const operand of eachInstructionOperand(instr)) {
    switch (operand.effect) {
      case Effect.Capture:
      case Effect.Store:
      case Effect.ConditionallyMutate:
      case Effect.ConditionallyMutateIterator:
      case Effect.Mutate: {
        if (isMutable(instr, operand)) {
          if (context.derivationCache.cache.has(operand.identifier.id)) {
            const operandMetadata = context.derivationCache.cache.get(
              operand.identifier.id,
            );

            if (operandMetadata !== undefined) {
              operandMetadata.typeOfValue = joinValue(
                typeOfValue,
                operandMetadata.typeOfValue,
              );
            }
          } else {
            context.derivationCache.addDerivationEntry(
              operand,
              sources,
              typeOfValue,
            );
          }
        }
        break;
      }
      case Effect.Freeze:
      case Effect.Read: {
        // no-op
        break;
      }
      case Effect.Unknown: {