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

Code before:
      }
      case 'ArrayExpression': {
        const contextRefOperands = getContextRefOperand(state, instrValue);
        const valueKind: AbstractValue =
          contextRefOperands.length > 0
            ? {
                kind: ValueKind.Context,
                reason: new Set([ValueReason.Other]),
                context: new Set(contextRefOperands),
              }
            : {
                kind: ValueKind.Mutable,
                reason: new Set([ValueReason.Other]),
                context: new Set(),
              };

        for (const element of instrValue.elements) {
          if (element.kind === 'Spread') {
            state.referenceAndRecordEffects(
              freezeActions,
              element.place,
              Effect.ConditionallyMutate,
              ValueReason.Other,
            );
          } else if (element.kind === 'Identifier') {
            state.referenceAndRecordEffects(
              freezeActions,
              element,
              Effect.Capture,
              ValueReason.Other,
            );
          } else {
            let _: 'Hole' = element.kind;
          }
        }
        state.initialize(instrValue, valueKind);
        state.define(instr.lvalue, instrValue);
        instr.lvalue.effect = Effect.Store;
        continuation = {
          kind: 'funeffects',
        };
        break;
      }
      case 'NewExpression': {
        /**
         * For new expressions, we infer a `read` effect on the Class / Function type
         * to avoid extending mutable ranges of locally created classes, e.g.
         * ```js
         * const MyClass = getClass();
         * const value = new MyClass(val1, val2)
         *                   ^ (read)   ^ (conditionally mutate)

Review comment (suggestion):
I wonder if we could address most of the negative consequences of this change by just special-casing array here. Basically `isBuiltInArrayType(element) ? Effect.Capture : Effect.ConditionallyMutate` as the effect. Because spreading doesn't mutate arrays, it only mutates if you have an iterator.

Code after:
      }
      case 'ArrayExpression': {
        const contextRefOperands = getContextRefOperand(state, instrValue);
        const valueKind: AbstractValue =
          contextRefOperands.length > 0
            ? {
                kind: ValueKind.Context,
                reason: new Set([ValueReason.Other]),
                context: new Set(contextRefOperands),
              }
            : {
                kind: ValueKind.Mutable,
                reason: new Set([ValueReason.Other]),
                context: new Set(),
              };

        for (const element of instrValue.elements) {
          if (element.kind === 'Spread') {
            state.referenceAndRecordEffects(
              freezeActions,
              element.place,
              isArrayType(element.place.identifier)
                ? Effect.Capture
                : Effect.ConditionallyMutate,
              ValueReason.Other,
            );
          } else if (element.kind === 'Identifier') {
            state.referenceAndRecordEffects(
              freezeActions,
              element,
              Effect.Capture,
              ValueReason.Other,
            );
          } else {
            let _: 'Hole' = element.kind;
          }
        }
        state.initialize(instrValue, valueKind);
        state.define(instr.lvalue, instrValue);
        instr.lvalue.effect = Effect.Store;
        continuation = {
          kind: 'funeffects',
        };
        break;
      }
      case 'NewExpression': {
        /**
         * For new expressions, we infer a `read` effect on the Class / Function type
         * to avoid extending mutable ranges of locally created classes, e.g.
         * ```js
         * const MyClass = getClass();