This deprecates the `noEmit: boolean` flag and adds `outputMode:
'client' | 'client-no-memo' | 'ssr' | 'lint'` as the replacement.
OutputMode defaults to null and takes precedence if specified, otherwise
we use 'client' mode for noEmit=false and 'lint' mode for noEmit=true.
Key points:
* Retrying failed compilation switches from 'client' mode to
'client-no-memo'
* Validations are enabled behind
Environment.proto.shouldEnableValidations, enabled for all modes except
'client-no-memo'. Similar for dropping manual memoization.
* OptimizeSSR is now gated by the outputMode==='ssr', not a feature flag
* Creation of reactive scopes, and related codegen logic, is now gated
by outputMode==='client'
Just a quick poc:
* Inline useState when the initializer is known to not be a function.
The heuristic could be improved but will handle a large number of cases
already.
* Prune effects
* Prune useRef if the ref is unused, by pruning 'ref' props on primitive
components. Then DCE does the rest of the work - with a small change to
allow `useRef()` calls to be dropped since function calls aren't
normally eligible for dropping.
* Prune event handlers, by pruning props whose names start w "on" from
primitive components. Then DCE removes the functions themselves.
Per the fixture, this gets pretty far.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/35102).
* #35112
* __->__ #35102
Summary:
I missed this conditional messing things up for undefined useState()
calls. We should be tracking them.
I also missed a test that expect an error was not throwing.
Test Plan:
Update broken test
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/35174).
* __->__ #35174
* #35173
Summary:
The operands of a function expression are the elements passed as
context. This means that it doesn't make sense to record mutations for
them.
The relevant mutations will happen in the function body, so we need to
prevent FunctionExpression type instruction from running the logic for
effect mutations.
This was also causing some values to depend on themselves in some cases
triggering an infinite loop. Also added n invariant to prevent this
issue
Test Plan:
Added fixture test
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/35173).
* #35174
* __->__ #35173
Conditionally calling setState in an effect is sometimes necessary, but
should generally follow the pattern of using a "previous vaue" ref to
manually compare and ensure that the setState is idempotent. See fixture
for an example.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/35147).
* #35148
* __->__ #35147
Destructing statements that start off as declarations can end up
becoming reassignments if the variable is a scope declaration, so we
have existing logic to handle cases where some parts of a destructure
need to be converted into new locals, with a reassignment to the hoisted
scope variable afterwards. However, there is an edge case where all of
the values are reassigned, in which case we don't need to rewrite and
can just set the instruction kind to reassign.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/35144).
* #35148
* #35147
* #35146
* __->__ #35144
Fix for the repro from the previous PR. A `Capture x -> y` effect should
downgrade to `ImmutableCapture` when the source value is maybe-frozen.
MaybeFrozen represents the union of a frozen value with a non-frozen
value.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/35140).
* __->__ #35140
* #35139
## Summary
Fixes#35040. The React compiler incorrectly flags ref access within
event handlers as ref access at render time. For example, this code
would fail to compile with error "Cannot access refs during render":
```tsx
const onSubmit = async (data) => {
const file = ref.current?.toFile(); // Incorrectly flagged as error
};
<form onSubmit={handleSubmit(onSubmit)}>
```
This is a false positive because any built-in DOM event handler is
guaranteed not to run at render time. This PR only supports built-in
event handlers because there are no guarantees that user-made event
handlers will not run at render time.
## How did you test this change?
I created 4 test fixtures which validate this change:
* allow-ref-access-in-event-handler-wrapper.tsx - Sync handler test
input
* allow-ref-access-in-event-handler-wrapper.expect.md - Sync handler
expected output
* allow-ref-access-in-async-event-handler-wrapper.tsx - Async handler
test input
* allow-ref-access-in-async-event-handler-wrapper.expect.md - Async
handler expected output
All linters and test suites also pass.
Summary:
This only matters when enableTreatSetIdentifiersAsStateSetters=true
This pattern is still bad. But Right now the validation can only
recommend to move stuff to "calculate in render"
A global setState should not be moved to render, not even conditionally
and you can't remove state without crossing Component boundaries, which
makes this a different kind of fix.
So while we are only suggesting "calculate in render" as a fix we should
disallow the lint from throwing in this case IMO
Test Plan:
Added a fixture
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/35135).
* __->__ #35135
* #35134
Summary:
The validation only allows setState declaration as a usage outside of
the effect.
Another edge case is that if you add the setState being validated in the
dependency array you also make the validation opt out since it counts as
a usage outside of the effect.
Added a bit of logic to consider the effect's deps when creating the
cache for setState usages within the effect
Test Plan:
Added a fixture
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/35134).
* #35135
* __->__ #35134
@josephsavona this was briefly discussed in an old thread, lmk your
thoughts on the approach. I have some fixes ready as well but wanted to
get this test case in first... there's some things I don't _love_ about
this approach, but end of the day it's just a tool for the test suite
rather than something for end user folks so even if it does a 70% good
enough job that's fine.
### refresher on the problem
when we generate coverage reports with jest (istanbul), our coverage
ends up completely out of whack due to the AST missing a ton of (let's
call them "important") source locations after the compiler pipeline has
run.
At the moment to get around this, we've been doing something a bit
unorthodox and also running our test suite with istanbul running before
the compiler -- which results in its own set of issues (for eg, things
being memoized differently, or the compiler completely bailing out on
the instrumented code, etc).
before getting in fixes, I wanted to set up a test case to start
chipping away on as you had recommended.
### how it works
The validator basically:
1. Traverses the original AST and collects the source locations for some
"important" node types
- (excludes useMemo/useCallback calls, as those are stripped out by the
compiler)
3. Traverses the generated AST and looks for nodes with matching source
locations.
4. Generates errors for source locations missing nodes in the generated
AST
### caveats/drawbacks
There are some things that don't work super well with this approach. A
more natural test fit I think would be just having some explicit
assertions made against an AST in a test file, as you can just bake all
of the assumptions/nuance in there that are difficult to handle in a
generic manner. However, this is maybe "good enough" for now.
1. Have to be careful what you put into the test fixture. If you put in
some code that the compiler just removes (for eg, a variable assignment
that is unused), you're creating a failure case that's impossible to
fix. I added a skip for useMemo/useCallback.
2. "Important" locations must exactly match for validation to pass.
- Might get tricky making sure things are mapped correctly when a node
type is completely changed, for eg, when a block statement arrow
function body gets turned into an implicit return via the body just
being an expression/identifier.
- This can/could result in scenarios where more changes are needed to
shuttle the locations through due to HIR not having a 1:1 mapping all
the babel nuances, even if some combination of other data might be good
enough even if not 10000% accurate. This might be the _right_ thing
anyways so we don't end up with edge cases having incorrect source
locations.
Summary:
We should only run one version of the validation. I think it makes sense
that if the exp version is enable it takes precedence over the stable
one
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/35099).
* __->__ #35099
* #35100
Summary:
I missed this test case failing and now having @loggerTestOnly after
landing some other PRs good to know they're not land blocking
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/35100).
* #35099
* __->__ #35100
Summary:
When a local state is created sometimes it uses a `prop` or even other
local state for its initial value.
This value is only relevant on first render so we shouldn't consider it
part of our data flow
Test Plan:
Added tests
Summary:
If we are using a clean up function in an effect and that clean up
function depends on a value that is used to set the state we are
validating for we shouldn't throw an error since it is a valid use case
for an effect.
Test Plan:
added test
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/35020).
* #35044
* __->__ #35020
Summary:
This makes the setState usage logic much more robust. We no longer rely
on identifierName.
Now we track when a setState is loaded into a new promoted identifier
variable and track this in a map `setStateLoaded` map.
For other types of instructions we consider the setState to be being
used. In this case we record its usage into the `setStateUsages` map.
Test Plan:
We expect no changes in behavior for the current tests
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34973).
* #35044
* #35020
* __->__ #34973
* #34972
Summary:
Revamped the derivationCache graph.
This fixes a bunch of bugs where sometimes we fail to track from which
props/state we derived values from.
Also, it is more intuitive and allows us to easily implement a Data Flow
Tree.
We can print this tree which gives insight on how the data is derived
and should facilitate error resolution in complicated components
Test Plan:
Added a test case where we were failing to track derivations. Also
updated the test cases with the new error containing the data flow tree
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34995).
* #35044
* #35020
* #34973
* #34972
* __->__ #34995
* #34967
Summary:
With this we are now comparing a snapshot of the derivationCache with
the new changes every time we are done recording the derivations
happening in the HIR.
We have to do this after recording everything since we still do some
mutations on the cache when recording mutations.
Test Plan:
Test the following in playground:
```
// @validateNoDerivedComputationsInEffects_exp
function Component({ value }) {
const [checked, setChecked] = useState('');
useEffect(() => {
setChecked(value === '' ? [] : value.split(','));
}, [value]);
return (
<div>{checked}</div>
)
}
```
This no longer causes an infinite loop.
Added a test case in the next PR in the stack
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34967).
* #35044
* #35020
* #34973
* #34972
* #34995
* __->__ #34967
When a longer function or expression is identified as the source of an
error, we currently print the entire expression in our error message.
This is because we delegate to a Babel helper to print codeframes. Here,
we add some checking and abbreviate the result if it spans too many
lines.
Fixes a few small things:
- Update imports to reference root babel-plugin-react-compiler rather
than from `[...]/src/...`
- Remove unused cosmiconfig options parsing for now
- Update type exports in babel-plugin-react-compiler accordingly
Within a function expression local variables may use StoreContext for
local context variables, so the reassignment check here was firing too
often. We should only report an error for variables that are declared
outside the function, ie part of its `context`.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34904).
* #34903
* __->__ #34904
As part of the new inference model we updated to (correctly) treat
destructuring spread as creating a new mutable object. This had the
unfortunate side-effect of reducing precision on destructuring of props,
though:
```js
function Component({x, ...rest}) {
const z = rest.z;
identity(z);
return <Stringify x={x} z={z} />;
}
```
Memoized as the following, where we don't realize that `z` is actually
frozen:
```js
function Component(t0) {
const $ = _c(6);
let x;
let z;
if ($[0] !== t0) {
const { x: t1, ...rest } = t0;
x = t1;
z = rest.z;
identity(z);
...
```
#34341 was our first thought of how to do this (thanks @poteto for
exploring this idea!). But during review it became clear that it was a
bit more complicated than I had thought. So this PR explores a more
conservative alternative. The idea is:
* Track known sources of frozen values: component props, hook params,
and hook return values.
* Find all object spreads where the rvalue is a known frozen value.
* Look at how such objects are used, and if they are only used to access
properties (PropertyLoad/Destructure), pass to hooks, or pass to jsx
then we can be very confident the object is not mutated. We consider any
such objects to be frozen, even though technically spread creates a new
object.
See new fixtures for more examples.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34900).
* __->__ #34900
* #34887
In my previous PR I fixed some cases but broke others. So, new approach.
Two phase algorithm:
* First pass is forward data flow to determine all usages of macros.
This is necessary because many of Meta's macros have variants that can
be accessed via properties, eg you can do `macro(...)` but also
`macro.variant(...)`.
* Second pass is backwards data flow to find macro invocations (JSX and
calls) and then merge their operands into the same scope as the macro
call.
Note that this required updating PromoteUsedTemporaries to avoid
promoting macro calls that have interposing instructions between their
creation and usage. Macro calls in general are pure so it should be safe
to reorder them.
In addition, we're now more precise about `<fb:plural>`, `<fbt:param>`,
`fbt.plural()` and `fbt.param()`, which don't actually require all their
arguments to be inlined. The whole point is that the plural/param value
is an arbitrary value (along with a string name). So we no longer
transitively inline the arguments, we just make sure that they don't get
inadvertently promoted to named variables.
One caveat: we actually don't do anything to treat macro functions as
non-mutating, so `fbt.plural()` and friends (function form) may still
sometimes group arguments just due to mutability inference. In a
follow-up, i'll work to infer the types of nested macro functions as
non-mutating.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34887).
* #34900
* __->__ #34887
This is a great validation, so let's enable by default. Changes:
* Move the validation logic into ValidateUseMemo alongside the new check
that the useMemo result is used
* Update the lint description
* Make the void memo errors lint-only, they don't require us to skip
compilation (as evidenced by the fact that we've had this validation
off)
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34882).
* #34855
* __->__ #34882
Two additional validations for useMemo:
* Disallow reassigning to values declared outside the useMemo callback
(always on)
* Disallow unused useMemo calls (part of the validateNoVoidUseMemo
feature flag, which in turn is off by default)
We should probably enable this flag though!
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34868).
* #34855
* #34882
* __->__ #34868
## Summary
When upgrading to `babel-plugin-react-compiler@1.0.0` in a project that
uses `zod@3` we are running into TypeScript errors like:
```
node_modules/babel-plugin-react-compiler/dist/index.d.ts:435:10 - error TS2694: Namespace '"/REDACTED/node_modules/zod/v3/external"' has no exported member 'core'.
435 }, z.core.$strip>>>;
~~~~
```
This problem seems to be related to
d6eb735938, which introduced zod v3/v4
compatibility. Since `zod` is bundled into the compiler source this does
not cause runtime issues and only manifests as TypeScript errors. My
proposed solution is this PR is to use zod's [subpath versioning
strategy](https://zod.dev/v4/versioning?id=versioning-in-zod-4) which
allows you to support v3 and v4 APIs on both major versions.
Changes in this PR include:
- Updated `zod` import paths to `zod/v4`
- Bumped min `zod` version to `^3.25.0` for zod which guarantees the
`zod/v4` subpath is available.
- Updated `zod-validation-error` import paths to
`zod-validation-error/v4`
- Bumped min `zod-validation-error ` version to `^3.5.0`
- Updated `externals` tsup configuration where appropriate.
Once the compiler drops zod v3 support we could optionally remove the
`/v4` subpath from the imports.
## How did you test this change?
Not totally sure the best way to test. I ran `NODE_ENV=production yarn
workspace babel-plugin-react-compiler run build --dts` and diffed the
`dist/` folder between my change and `v1.0.0` and it looks correct. We
have a `patch-package` patch to workaround this for now and it works as
expected.
```diff
diff --git a/node_modules/babel-plugin-react-compiler/dist/index.d.ts b/node_modules/babel-plugin-react-compiler/dist/index.d.ts
index 81c3f3d..daafc2c 100644
--- a/node_modules/babel-plugin-react-compiler/dist/index.d.ts
+++ b/node_modules/babel-plugin-react-compiler/dist/index.d.ts
@@ -1,7 +1,7 @@
import * as BabelCore from '@babel/core';
import { NodePath as NodePath$1 } from '@babel/core';
import * as t from '@babel/types';
-import { z } from 'zod';
+import { z } from 'zod/v4';
import { NodePath, Scope } from '@babel/traverse';
interface Result<T, E> {
```
Co-authored-by: Henry Q. Dineen <henryqdineen@gmail.com>
We now do a single pass over the HIR, building up two data structures:
* One tracks values that are known macro tags or macro calls.
* One tracks operands of macro-related instructions so that we can later
group them.
After building up these data structures, we do a pass over the latter
structure. For each macro call instruction, we recursively traverse its
operands to ensure they're in the same scope. Thus, something like
`fbt('hello' + fbt.param(foo(), "..."))` will correctly merge the fbt
call, the `+` binary expression, the `fbt.param()` call, and `foo()`
into a single scope.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34865).
* #34855
* __->__ #34865
In InferTypes when we infer types for properties during destructuring,
we were breaking out of the loop when we encounter a hole in the array.
Instead we should just skip that element and continue inferring later
properties.
Closes#34748
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34847).
* #34855
* __->__ #34847
Renames the `recommended` property on LintRule to `preset`, to allow
exporting rules for different presets. For now the `Recommended` and
`RecommendedLatest` presets are the same, but in the next PR I will
enable more rules for the latest preset.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34782).
* #34783
* __->__ #34782
Partial redo of #34710. The changes there tried to use `z.function(args,
return)` to be compatible across Zod v3 and v4, but Zod 4's function API
has completely changed. Instead, I've updated to just use `z.any()`
where we expect a function, and manually validate that it's a function
before we call the value. We already have validation of the return type
(also using Zod).
Co-authored-by: kolvian <eliot@pontarelli.com>
This enables `@enablePreserveExistingMemoizationGuarantees` by default.
As of the previous PR (#34503), this mode now enables the following
behaviors:
- Treating variables referenced within a `useMemo()` or `useCallback()`
as "frozen" (immutable) as of the start of the call. Ie, the compiler
will assume that the values you reference are not mutated by the body of
the useMemo, not are they mutated later. Directly modifying them (eg
`var.property = true`) will be an error.
- Similarly, the results of the useMemo/useCallback are treated as
frozen (immutable) after the call.
These two rules match the behavior for other hooks: this means that
developers will see similar behavior to swapping out `useMemo()` for a
custom `useMyMemo()` wrapper/alias.
Additionally, as of #34503 the compiler uses information from the manual
dependencies to know which variables are non-nullable. Even if a useMemo
block conditionally accesses a nested property — `if (cond) { log(x.y.z)
}` — where the compiler would not usually know that `x` is non-nullable,
if the user specifies `x.y.z` as a manual dependency then the compiler
knows that `x` and `x.y` are non-nullable and can infer a more precise
dependency.
Finally, this mode also ensures that we always memoize function calls
that return primitives. See #34343 for more details.
For now, I've explicitly opted out of this feature in all test fixtures
where the behavior changed.
The `@enablePreserveExistingMemoizationGuarantees` mode can still fail
to preserve manual memoization due to mismtached dependencies.
Specifically, where the user's dependencies are more precise than the
compiler infers bc the compiler is being conservative about what might
be nullable. In this mode though we're intentionally using information
from the manual memoization and can also rely on the deps as a signal
for what's non-nullable.
The idea of the PR is that we treat manual memo deps just like other
inferred-as-non-nullable objects during PropagateScopeDeps. We're
careful to not treat the full path as non-nullable, only up to the last
property index. So `x.y.z` as a manual dep treats `x` and `x.y` as
non-nullable, allowing us to preserve a conditional dependency on
`x.y.z`.
Optionals within manual dependencies are a bit trickier and aren't
handled yet, but hopefully that's less common and something we can
improve in a follow-up. Not handling them just means that developers may
hit false positives on validating existing memoization if they use
optional chains in manual dependencies.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34503).
* #34689
* __->__ #34503
We previously always generated import statements for any modules that
had to be required, notably the `import {c} from
'react/compiler-runtime'` for the memo cache function. However, this
obviously doesn't work when the source is using commonjs. Now we check
the sourceType of the module and generate require() statements if the
source type is 'script'.
I initially explored using
https://babeljs.io/docs/babel-helper-module-imports, but the API design
was unfortunately not flexible enough for our use-case. Specifically,
our pipeline is as follows:
* Compile individual functions. Generate candidate imports,
pre-allocating the local names for those imports.
* If the file is compiled successfully, actually add the imports to the
program.
Ie we need to pre-allocate identifier names for the imports before we
add them to the program — but that isn't supported by
babel-helper-module-imports. So instead we generate our own require()
calls if the sourceType is script.
@eps1lon flagged this case. Inlined useCallback has an extra LoadLocal
indirection which caused us not to add a name. While I was there I added
some extra checks to make sure we don't generate names for a given node
twice (just in case).
<!--
Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please
provide enough information so that others can review your pull request.
The three fields below are mandatory.
Before submitting a pull request, please make sure the following is
done:
1. Fork [the repository](https://github.com/facebook/react) and create
your branch from `main`.
2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch
TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It
supports the same options as `yarn test`.
6. If you need a debugger, run `yarn test --debug --watch TestName`,
open `chrome://inspect`, and press "Inspect".
7. Format your code with
[prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only
check changed files.
9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
10. If you haven't already, complete the CLA.
Learn more about contributing:
https://reactjs.org/docs/how-to-contribute.html
-->
## Summary
<!--
Explain the **motivation** for making this change. What existing problem
does the pull request solve?
--> The React Compiler rejected a default parameter that contains a
TSInstantiationExpression with the todo message that the expression
cannot be safely reordered. This change teaches the reorder check in
BuildHIR.ts to treat TSInstantiationExpression as reorderable. This is
safe because TypeScript instantiation only affects types and is erased
at runtime, so it has no side effects and does not change semantics.
## How did you test this change?
```
Set-Content testfilter.txt 'ts-instantiation-default-param'
yarn test --filter --update
yarn test --filter
```
<!--
Demonstrate the code is solid. Example: The exact commands you ran and
their output, screenshots / videos if the pull request changes the user
interface.
How exactly did you verify that your PR solves the issue you wanted to
solve?
If you leave this empty, your PR will very likely be closed.
--> I added a fixture:
>
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ts-instantiation-default-param.js
Some components accept a union of a ref callback function or ref object.
In this case we may infer the type as a function due to the presence of
invoking the ref callback function. In that case, we currently report a
"Hint: name `fooRef` as "ref" or with a "-Ref" suffix..." even though
the variable is already named appropriately — the problem is that we
inferred a non-ref type. So here we check the type and don't report this
hint if we inferred another type.
Calling setState functions during render can lead to extraneous renders
or even infinite loops. We also have runtime detection for loops, but
static detection is obviously even better.
This PR adds an option to infer identifers as setState functions if both
the following conditions are met:
- The identifier is named starting with "set"
- The identifier is used as the callee of a call expression
By inferring values as SetState type, this allows our existing
ValidateNoSetStateInRender rule to flag calls during render, disallowing
examples like the following:
```js
function Component({setParentState}) {
setParentState(...);
^^^^^^^^^^^^^^ Error: Cannot call setState in render
}
```
<!--
Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please
provide enough information so that others can review your pull request.
The three fields below are mandatory.
Before submitting a pull request, please make sure the following is
done:
1. Fork [the repository](https://github.com/facebook/react) and create
your branch from `main`.
2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch
TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It
supports the same options as `yarn test`.
6. If you need a debugger, run `yarn test --debug --watch TestName`,
open `chrome://inspect`, and press "Inspect".
7. Format your code with
[prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only
check changed files.
9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
10. If you haven't already, complete the CLA.
Learn more about contributing:
https://reactjs.org/docs/how-to-contribute.html
-->
## Summary
Removed the old `OVERRIDE` pragma to make the source of truth for config
overrides in the left-hand pane. Now, it will automatically update the
output pane each time there is an edit to the config. The old pragma
format is still supported, but it will be overwritten by the config pane
if they are modifying the same flags. Removed the gating on the config
panel so now all users will automatically be able to view it, but it
will be initially collapsed.
<!--
Explain the **motivation** for making this change. What existing problem
does the pull request solve?
-->
## How did you test this change?
https://github.com/user-attachments/assets/9d4512b9-e203-4ce0-ae95-dd96ff03bbc1
<!--
Demonstrate the code is solid. Example: The exact commands you ran and
their output, screenshots / videos if the pull request changes the user
interface.
How exactly did you verify that your PR solves the issue you wanted to
solve?
If you leave this empty, your PR will very likely be closed.
-->
Two small QoL improvements inspired by feedback:
* `if (ref.current === undefined) { ref.current = ... }` is now allowed.
* `if (!ref.current) { ref.current = ... }` is still disallowed, but we
emit an extra hint suggesting the `if (!ref.current == null)` pattern.
I was on the fence about the latter. We got feedback asking to allow `if
(!ref.current)` but if your ref stores a boolean value then this would
allow reading the ref in render. The unary form is also less precise in
general due to sketchy truthiness conversions. I figured a hint is a
good compromise.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34449).
* __->__ #34449
* #34424