Commit Graph
19463 Commits
Author SHA1 Message Date
Jan Kassens cb9899955b Fix ReactFreshIntegration-test not running all tests as assumed (#28033)
Fix ReactFreshIntegration-test not running all tests as assumed

`testCommon` was executed twice without setting `compileDestructuring`
ever to true.
This fixes this and removes one layer of abstraction in this test by
using `describe.each`.
2024-01-23 09:59:14 -05:00
Sebastian Silbermann bf32989264 Convert ReactMountDestruction (partially) to createRoot (#28004) 2024-01-23 10:30:19 +01:00
Joe Savona 4d84bee172 Propagate reactive scope dependencies transitively
During PruneNonReactiveDependencies, we sometimes need to promote a value from 
non-reactive to reactive if it ended up being grouped in the same reactive scope 
as some other reactive value. This generally happens due to interleaving 
mutations. 

In this case all downstream usage of the promoted value need to also be 
considered reactive. Fully propagating the reactivity requires re-running 
InferReactivePlaces, to account for things like control reactivity. We can't yet 
reuse that pass here though, because we haven't unified the pipeline on HIR yet. 

For now, we propagate the reactivity through local variables and downstream 
reactive scopes. See test fixtures for some examples that now correctly 
propagate reactivity and some that need the full reactivity inference to run 
correctly. The latter cases are handled in the next PR.
2024-01-22 15:35:56 -08:00
Joe Savona 57163f0a52 InferReactivePlaces account for immutable aliases of mutably aliased values
I found this by adding logic to reject inputs where reactivity gets newly 
propagated in PruneNonReactiveDependencies. It's possible to create a readonly 
alias to a mutable value such that we don't know the value is reactive yet when 
the alias is created. Thus we need to do a fixpoint iteration even if there are 
no loops in order to be able to revisit such aliases and reflow the reactivity 
forward. Example: 

```javascript 

const x = []; 

const y = x; 

const z = [y]; // y isn't reactive yet when we first visit this, so z is 
initially non-reactive 

y.push(props.value); // then we realize y is reactive. we need a fixpoint to 
propagate this back to z 

const a = [z]; // need an indirection to get past the partial propagation in 
PruneNonReactiveDependencies 

let b = 0; 

if (a[0][0]) { 

b = 1; 

} 

return [b]; 

``` 

Existing fixtures don't change because the basic reactivity propagation in 
PruneNonReactiveDependencies is enough to make common cases work. I confirmed 
that the new fixture does not work on previous PR in the stack.
2024-01-22 15:35:55 -08:00
Jack Pope 2f803b47c7 Use createRoot for ReactTreeTraversal-test (#28051) 2024-01-22 17:13:10 -05:00
Ricky ec19db4266 Convert ReactElementJSX to createRoot (#28012) 2024-01-22 15:50:20 -05:00
Sebastian Silbermann e1d20fc0c0 Convert describeComponentFrame to createRoot (#28001) 2024-01-22 15:08:39 +01:00
Sebastian Silbermann 206934f027 Convert ReactDOMOption to createRoot (#28002) 2024-01-22 09:21:40 +01:00
Joe Savona 0894e35d94 More fixtures for reactivity and mutable aliasing (property load case) 2024-01-19 19:12:58 -08:00
Joe Savona 8be56418d3 InferReactivePlaces accounts for mutable aliasing
Fixes T175227223. When inferring reactivity, mutation of a value with a reactive 
input marks the mutable value as reactive. However, we also need to account for 
aliases: 

```javascript 

const x = []; 

const y = x; 

y.push(props.value); 

``` 

Previously we would have only considered `y` reactive here, but `x` also becomes 
reactive. 

The implementation extracts out a helper from InferReactiveScopeVariables that 
builds a `DisjointSet<Identifier>` of disjoint sets of mutably aliased values. 
InferReactivePlaces then treats all instances of each mutable alias group as 
equivalent for reactivity purposes.
2024-01-19 16:03:58 -08:00
Ricky 29fbf6f626 Convert ReactError-test to createRoot (#27995) 2024-01-19 14:35:56 -05:00
Joe Savona a272cf9b0c Reactive control fixtures use multipass evaluation
Updates all of the reactive control dependency fixtures to use multipass 
evaluation in sprout.
2024-01-19 11:04:18 -08:00
Jan Kassens 4c63dc7bdd Convert getEventKey-test to createRoot (#28006)
Convert getEventKey-test to createRoot
2024-01-19 13:51:20 -05:00
Jan Kassens 64d0c94724 Convert ReactUpdaters-test.internal to createRoot (#28005)
Convert ReactUpdaters-test.internal to createRoot
2024-01-19 13:37:10 -05:00
Jan Kassens 624b51388b Convert SyntheticKeyboardEvent-test to createRoot (#28007)
Convert SyntheticKeyboardEvent-test to createRoot
2024-01-19 13:36:05 -05:00
Jan Kassens a2eaa21ac7 Convert dangerouslySetInnerHTML-test to createRoot (#28008)
Convert dangerouslySetInnerHTML-test to createRoot
2024-01-19 13:35:43 -05:00
Jan Kassens 24d1c6f0fa Convert ReactDOM-test to createRoot (#28009)
Convert ReactDOM-test to createRoot
2024-01-19 13:35:15 -05:00
Joe Savona c8323f3b42 Mutation within a reactively controlled block propagates reactivity
In InferReactivePlaces, we already account for reactively controlled values: 
where a value is never assigned a non-reactive value, but _which_ value is 
assigned is based on a reactive condition (the test conditions of an if, switch, 
loop, etc). 

This PR extends that reactively-controlled inference to mutation that is 
conditioned upon a reactive value. From the test case: 

```javascript 

let x = []; 

if (props.cond) { 

// This mutation has no reactive inputs. 

// *But* the mutation conditionally occurs based on props.cond which is reactive 

x.push(1); 

} 

let y = false; 

if (x[0]) { // therefore the value observed here is reactive 

y = true; 

} 

// so the value of y here is reactive via the reactive control dependency x[0] 

return [y]; 

```
2024-01-19 10:03:51 -08:00
Mofei Zhang 34c89458f2 [entrypoint] Allow ref params to component functions 2024-01-19 14:59:52 -05:00
Sebastian Silbermann 4c58fc2ad8 Convert ReactFreshMultipleRenderer to createRoot (#28000) 2024-01-19 18:21:15 +01:00
Sebastian Silbermann 601dba8217 Convert ReactErrorLoggingRecovery to createRoot (#28003) 2024-01-19 18:07:08 +01:00
Ricky feed8f3f95 Convert ReactFunctionComponent to createRoot (#27997) 2024-01-18 22:32:04 -05:00
Mofei Zhang 4aa60d32b9 [patch][dce] Patch dce to have separate mark and sweep phases
--- 

Previously, our logic was something like: 

```js 

fixed-point-loop { 

foreach instruction { 

mark referenced identifiers 

// assume that usages are always visited before declarations 

if (instruction is decl) { 

prune(instruction); 

} 

} 

foreach instruction { 

if not referenced { 

delete(instruction); 

} 

} 

``` 

This contained a bug, as not all usages of a variable are guaranteed to be 
visited before its declaration. 

```js 

// input 

let x = 0; 

while(x < 10) { 

x += 2; 

} 

return x; 

// hir 

entry: 

x$0 = 0 

goto loop-test 

loop-test: 

x$1 = phi(x$0, x$2) 

if ... goto loop-body else goto fallthrough 

loop-body: 

x$2 = x$1 ... 

goto loop-test 

fallthrough: 

return x$1 

``` 

In this example,`x$2` is defined by `loop-body` and used by `loop-test`. 
Similarly, `x$1` is defined by `loop-test` and used by `loop-body`. 

--- 

TODO: trying to come up with more test fixtures
2024-01-18 18:29:19 -05:00
Mofei Zhang a0e90065c6 [patch][babel] check babel identifier before lowering to HoistedConst
Same babel identifier issue as #2510 but for HoistedConst 

Not sure how we should best test this -- one possibility is using constant prop. 
Currently, we have false positives for HoistedConst that prevent constant 
propagation. I don't want to over-rotate on babel apis tests in our fixtures 
(instead of semantically interesting ones) 

```js 

// input 

function Component() { 

{ x: 4 }; 

const x = 2; 

return x; 

} 

// output 

function Component() { 

const $ = useMemoCache(1); 

let x; 

if ($[0] === Symbol.for("react.memo_cache_sentinel")) { 

x = 2; 

$[0] = x; 

} else { 

x = $[0]; 

} 

return x; 

} 

```
2024-01-18 18:29:19 -05:00
Mofei Zhang f88e7fe412 [repro] add fixture repro for destructuring bug 2024-01-18 18:29:18 -05:00
Mofei Zhang 241a615732 [babel][contextvar] Patch context identifier babel logic; only use referenced
identifiers 

--- 

A few fixes for finding context identifiers: 

Previously, we counted every babel identifier as a reference. This is 
problematic because babel counts every string symbol as an identifier. 

```js 

print(x);  // x is an identifier as expected 

obj.x      // x is.. also an identifier here 

{x: 2}     // x is also an identifier here 

``` 

This PR adds a check for `isReferencedIdentifier`. Note that only non-lval 
references pass this check 

```js 

print(x);  // isReferencedIdentifier(x) -> true 

obj.x      // isReferencedIdentifier(x) -> false 

{x: 2}     // isReferencedIdentifier(x) -> false 

x = 2      // isReferencedIdentifier(x) -> false 

``` 

Which brings us to change #2. 

Previously, we counted assignments as references due to the identifier visiting 
+ checking logic. The logic was roughly the following (from #1691) 

```js 

contextVars = intersection(reassigned, referencedByInnerFn); 

``` 

Now that assignments (lvals) and references (rvals) are tracked separately, the 
equivalent logic is this. Note that assignment to a context variable does not 
need to be modeled as a read (`console.log(x = 5)` always will evaluates and 
prints 5, regardless of the previous value of x). 

``` 

contextVars = union(reassignedByInnerFn, intersection(reassigned, 
referencedByInnerFn)) 

``` 

--- 

Note that variables that are never read do not need to be modeled as context 
variables, but this is unlikely to be a common pattern. 

```js 

function fn() { 

let x = 2; 

const inner = () => { 

x = 3; 

} 

} 

```
2024-01-18 18:29:18 -05:00
Mofei Zhang 8f18b8233f [patch][contextvars] Patch for variables reassigned after objectmethod
definitions
2024-01-18 18:29:18 -05:00
Mofei Zhang f0ef0b7d0b Edit .git-blame-ignore-revs 2024-01-18 18:29:17 -05:00
RickyandJan Kassens b300304710 Update error decoder URL (#27240)
Updates the error decoder to the URL for the new docs site.

- Switches the domain from reactjs.org to react.dev
- Switches to put the error code in the URL for SSG
- All params are still in the query

Example without args:

- Before: `https://reactjs.org/docs/error-decoder.html?invariant=200`
- After: ` https://react.dev/errors/200`

Example with args:
- Before:
`https://reactjs.org/docs/error-decoder.html?invariant=124?args[]=foo&args[]=bar
`
- After: ` https://react.dev/errors/124?args[]=foo&args[]=bar`


Requires: https://github.com/reactjs/react.dev/pull/6214

---------

Co-authored-by: Jan Kassens <jkassens@meta.com>
2024-01-17 21:41:07 -05:00
Andrew Clark 5c607369ce Remove client caching from cache() API (#27977)
We haven't yet decided how we want `cache` to work on the client. The
lifetime of the cache is more complex than on the server, where it only
has to live as long as a single request.

Since it's more important to ship this on the server, we're removing the
existing behavior from the client for now. On the client (i.e. not a
Server Components environment) `cache` will have not have any caching
behavior. `cache(fn)` will return the function as-is.

We intend to implement client caching in a future major release. In the
meantime, it's only exposed as an API so that Shared Components can use
per-request caching on the server without breaking on the client.
2024-01-16 20:27:15 -05:00
Andrew Clark f16344ea6d Refactor React Server entrypoint to not depend on the client one (#27940)
This refactors the Server Components entrypoint for the `react` package
(ReactServer.js) so that it doesn't depend on the client entrypoint
(React.js). I also renamed React.js to ReactClient.js to make the
separation clearer.

This structure will make it easier to add client-only and server-only
features.
2024-01-16 20:19:01 -05:00
Andrew Clark 5d1b15a4f0 Rename "shared subset" to "server" (#27939)
The internal file ReactSharedSubset is what the `react` module resolves
to when imported from a Server Component environment. We gave it this
name because, originally, the idea was that Server Components can access
a subset of the APIs available on the client.

However, since then, we've also added APIs that can _only_ by accessed
on the server and not the client. In other words, it's no longer a
subset, it's a slightly different overlapping set.

So this commit renames ReactSharedSubet to ReactServer and updates all
the references. This does not affect the public API, only our internal
implementation.
2024-01-16 19:58:11 -05:00
Jan Kassens da7c466f07 Rename eslint-plugin-react-forget to eslint-plugin-react-compiler
Rename eslint-plugin-react-forget to eslint-plugin-react-compiler
2024-01-16 17:36:37 -05:00
Jan Kassens 9b6605d313 Remove [ReactForget] prefix from eslint messages
Remove [ReactForget] prefix from eslint messages 

No other lint warnings have a prefix, removing this is cleaner.
2024-01-16 13:47:20 -05:00
Jan Kassens fb0cf4f833 Make collapsed playground tabs more compact
Make collapsed playground tabs more compact 

We have a lot of steps creating a lot of tabs by now. This makes them visually a 
lot more compact without a full redesign. 

Makes it a bit harder to read and less modern looking, but I think usability was 
a bit bad with the wide tabs. 

**Before:** 


![image](https://github.com/facebook/react-forget/assets/11849/a87c8f7e-d60c-43c1-aaea-1a1f77e082d0) 

**After:** 


![image](https://github.com/facebook/react-forget/assets/11849/227ebf1e-055f-439a-bfc9-e69bae091f6a)
2024-01-16 13:10:32 -05:00
Sathya Gunasekaran 38d3423970 Treat function expression deps as conditional 2024-01-15 12:44:22 +00:00
Sathya Gunasekaran 121e72a342 Add flag for treating function deps as conditional 2024-01-15 12:44:22 +00:00
Sathya Gunasekaran 6d133111a9 Add test for function deps not treated as conditional
In the test, unconditionally reading props.bar.length will throw when props.bar 
is null.
2024-01-15 12:44:22 +00:00
Sathya Gunasekaran 25ec9fcea4 Add .git-blame-ignore-revs
Ignore commits that just change formatting and file structures
2024-01-15 12:44:22 +00:00
Andrew Clark 60a927d04a Fix: useOptimistic should return passthrough value when there are no updates pending (#27936)
This fixes a bug that happened when the canonical value passed to
useOptimistic without an accompanying call to setOptimistic. In this
scenario, useOptimistic should pass through the new canonical value.

I had written tests for the more complicated scenario, where a new value
is passed while there are still pending optimistic updates, but not this
simpler one.
2024-01-13 21:37:35 -05:00
Jan Kassens 33068c9db9 Upgrade ReactDOMShorthandCSSPropertyCollision-test to createRoot (#27924)
Upgrade ReactDOMShorthandCSSPropertyCollision-test to createRoot

Using the codemod from #27921 as a starting point, this migrates the
test to `createRoot`.
2024-01-12 15:51:31 -05:00
Joe Savona 90348cc873 [housekeeping] Remove disabled test262 setup
I sincerely appreciate the effort to get test262 up and running. This was my 
idea, it seemed like a really good way to test our correctness on edge cases of 
JS. Unfortunately test262 relies heavily on a few specific features that we 
don't support, like classes and `var`, which has meant that we never actually 
use this as a test suite. 

In the meantime we've created a pretty extensive test suite and have tools like 
Sprout to test actual memoization behavior at runtime, which is the right place 
to invest our energy. Let's remove?
2024-01-12 12:26:30 -08:00
Joe Savona bcbbbec1f5 [housekeeping] Remove unused test fixtures
We don't use these fixtures, let's just clean them up.
2024-01-12 12:22:23 -08:00
Joe Savona 33118be835 [housekeeping] Remove fixtures/
Do we still use these? I'm happy to close this PR if we still want this but it 
feels like these may have served their purpose and no longer be necessary.
2024-01-12 12:22:19 -08:00
Joe Savona 653373141a Extra fixture for validating preserved memoization of non-escaping callbacks 2024-01-12 14:32:35 -08:00
Joe Savona 0c866672b0 Fix false positive on preserving memo of non-escaping values
Fixes the false positive in the previous PR. When we prune a scope because it's 
values are non-escaping, we now also remove any `Memoize` instructions for that 
scope. The intuition being that we're actively removing unnecessary memoization, 
so we don't need to check that the memoization occurred anymore.
2024-01-11 17:13:41 -08:00
Joe Savona 8e4d2fb69d Repro for false positive in validatePreserveMemoization on non-escaping value
This demonstrates a false positive in validatePreserveExistingManualMemoization. 
We prune memoization of non-escaping values, but the validation pass just sees 
that the value "should" have a scope and that scope doesn't exist, and thinks we 
failed to preserve memoization.
2024-01-11 16:52:57 -08:00
Joe Savona c3a947643f Update hoisting error message to allow error aggregation
Interpolating values into the `reason` field of an error breaks our error 
aggregation. This PR moves the offending function name into the `description` 
field which isn't used for aggregation.
2024-01-11 15:54:55 -08:00
Jan Kassens f6f042d747 Switch test262 submodule to https url
I had trouble checking out the repo using Sapling because the submodule couldn't 
clone properly. I got 

> Error: Permission denied (publickey) 

In my branch I tested that the https URL format seems to work okay with Sapling.
2024-01-12 15:07:24 -05:00
Jan Kassens 8a634bc1c0 Add frozen reason for props and hook arguments
Add frozen reason for props and hook arguments 

Improves the error message when mutating props or hook arguments. 

Previously, this would print a generic error about mutating global variables.
2024-01-12 14:51:59 -05:00