Skip to content

Conversation

@nathanmarks
Copy link
Owner

@nathanmarks nathanmarks commented Oct 17, 2025

Summary

Remove restriction on complex expressions as computed property keys in object literals. The restriction was added to prevent a mutation tracking bug in the original mutation aliasing model, but the new mutation aliasing model (now the default) correctly handles these cases.

Changes

  • BuildHIR.ts: Removed lines 1571-1584 that blocked CallExpression and other complex expressions as computed property keys
  • The underlying lowerExpressionToTemporary function already handles all expression types correctly (CallExpression, SequenceExpression, etc.)

Converted 4 error.todo- tests to passing tests:

  • object-expression-member-expr-call.js - CallExpression via MemberExpression
  • object-expression-computed-key-modified-during-after-construction.js - Direct CallExpression
  • object-expression-computed-key-mutate-key-while-constructing-object.js - CallExpression during construction
  • object-expression-computed-key-modified-during-after-construction-sequence-expr.js - SequenceExpression

Background

The restriction was added to avoid issues where mutations were not tracked accurately/consistently. Example of the problematic pattern was visible in this bug (recently removed as part of the new mutation aliasing model rollout): https://github.com/facebook/react/blob/d58c07b563a79bd706531278cb4afec6292b84a8/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.expect.md

How the New Model Fixes This

The new mutation aliasing model (documented in MUTABILITY_ALIASING_MODEL.md) builds a data flow graph to track mutations and aliasing. From the documentation:

The mutability and aliasing system is a conceptual subcomponent whose primary role is to determine minimal sets of values that mutate together, and the range of instructions over which those mutations occur.

When processing the computed key (mutate(key), key), the compiler lowers it to a temporary value. The model then infers an Assign effect from the sequence expression result to this temporary.

Two key rules from the mutation model apply. First, "Mutation of Assignment Mutates the Source Value":

Assign a <- b
Mutate a
=>
Mutate b

And second, "Mutation of Source Affects Alias, Assignment, CreateFrom, and Capture":

Alias a <- b OR Assign a <- b OR CreateFrom a <- b OR Capture a <- b
Mutate b
=>
Mutate a

As the documentation explains: "A derived value changes when its source value is mutated."

In our case, the computed key expression creates an assignment relationship between the temporary and key. When key is mutated later, this mutation propagates to the temporary through the assignment edge in the data flow graph. The mutable range of the temporary extends to include all mutations of key, preventing incorrect separate memoization of the object construction.

Follow-up

Note: Many fixture files still contain the @enableNewMutationAliasingModel pragma. This pragma is now obsolete (the new model is the default and the config option has been removed). Cleaning up these pragmas would be a good follow-up task. The presence of this pragma was initially confusing during investigation—it required checking git history to understand that it had been cleaned up and is now the default behavior.

@nathanmarks nathanmarks force-pushed the nathanmarks/fix-todo-callexp-computedkeys branch from d99852d to 2f6c8fe Compare October 17, 2025 18:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants