…affiliates.
## Summary
There were 8 different places where the copyright comment was wrong.
Rewrote from "Copyright (c) Facebook, Inc. and its affiliates." to
"Copyright (c) Meta Platforms, Inc. and its affiliates."
## How did you test this change?
No code was changed. Comment was still a comment after changes.
Co-authored-by: Dennis Moradkhani <denmo530@student.liu.se>
## Summary
Changed the comment in react/packages/react
/react.shared-subset.js saying
```
Copyright (c) Facebook, Inc. and affiliates ..
```
To
```
Copyright (c) Meta Platforms, Inc. and affiliates ..
```
as raised in the following issues:
https://github.com/facebook/react/issues/26829
Files Changed:
react/packages/react/react.shared-subset.js
## How did you test this change?
Tests Required: No
Adds a new feature flag which tells the compiler to assume that hooks follow the
Rules of React. Specifically, the idea that since any hook could be wrapped in a
giant `useMemo()` call, all arguments to hooks have to be treated as if they're
owned by React — and therefore become immutable — and that the return value of
the hook is immutable.
Our default is to assume that hooks break the rules, but in practice nearly
every component follows them.
Updates the InferReferenceEffects logic for CallExpression to work similarly to
MethodCall, where we take into account the function signature (if present) when
inferring the effects and return kind.
Defines the `Boolean`, `String`, and `Number` global functions. This will be
useful for allowing developers to wrap statements that produce a primitive in a
way that Forget knows about in order to optimize better.
The bindings upstream in Relay has been removed so we don't need these
builds anymore. The idea is to revisit an FB integration of Flight but
it wouldn't use the Relay specific bindings. It's a bit unclear how it
would look but likely more like the OSS version so not worth keeping
these around.
The `dom-relay` name also included the FB specific Fizz implementation
of the streaming config so I renamed that to `dom-fb`. There's no Fizz
implementation for Native yet so I just removed `native-relay`.
We created a configurable fork for how to encode the output of Flight
and the Relay implementation encoded it as JSON objects instead of
strings/streams. The new implementation would likely be more stream-like
and just encode it directly as string/binary chunks. So I removed those
indirections so that this can just be declared inline in
ReactFlightServer/Client.
Handles some edge-cases where we previously flattened away some of the structure
of a labeled block, instead ensuring that we retain the original shape. See the
output.
## Test Plan
Tested on the internal app we're focused on (w useMemo inlining enabled), it
works fine.
I realized a wayyyy simpler approach to inlining a lambda: wrap it in a labeled
block. The transformation is roughly as follows:
```javascript
// Before
const x = useMemo(() => {
if (a) {
return b;
}
return c;
}, [a, b, c]);
return x;
// After
let x;
label: {
if (a) {
x = b;
break label;
}
x = c;
break label;
}
return x;
```
The key to making this work is fixing up some edge cases in labeled blocks,
hence the previous PRs.
This is part of a stack to fix some edge cases in inlining of useMemo closures.
In this first step, I'm disabling `shrink()` in order to retain more information
about the data flow. For example,
```
label: if (cond) {
break label;
}
return foo;
```
Would previously have shrunk away the if body, making the IfTerminal.consequent
point directly to the fallthrough block (w the return). Now we retain a separate
block.
- delete output files when we detect input files are deleted
- enable test fixtures in nested directories
- exit with error code when we detect failures
Note that the test failure on this PR is expected and will be fixed by #1608 (or
happy to abandon that PR and fold the changes)
---
Looks like we delete `.js` files but missed `.expect` files. Jest probably
didn't catch this because the basename of the fixtures had duplicates (in
rule-of-hooks)
---
(`react-forget-runtime` package seems to be synced to -.)
RFC: useRenderCounter hook:
- tracks # renders (increments on render path)
- exposes a global renderCounterRegistry (counting # renders in alive / mounted
components)
Next PR will modify BabelPlugin to add codegen
```js
// Similar to how we're currently importing `isForgetEnabled`
import {isInstrumentForgetEnabled_Secret} from "ReactForgetFeatureFlag";
// ...
function Component_uncompiled(props) {
if (isInstrumentForgetEnabled_Secret) {
useRenderCounter();
}
// ...
}
function Component_forget(props) {
if (isInstrumentForgetEnabled_Secret) {
useRenderCounter();
}
// ...
}
```
Now that the throttling mechanism applies more often, we've decided to
lower this a tad to ensure it's not noticeable. The idea is it should be
just large enough to prevent jank when lots of different parts of the UI
load in rapid succession, but not large enough to make the UI feel
sluggish. There's no perfect number, it's just a heuristic.
The throttling mechanism for fallbacks should apply to both their
appearance _and_ disappearance.
This was mostly addressed by #26611. See that PR for additional context.
However, a flaw in the implementation is that we only update the the
timestamp used for throttling when the fallback initially appears. We
don't update it when the real content pops in. If lots of content in
separate Suspense trees loads around the same time, you can still get
jank.
The issue is fixed by updating the throttling timestamp whenever the
visibility of a fallback changes. Not just when it appears.
I originally created a separate test for the mode with JSX memoization disabled,
but we can merge this into the main compiler-test and enable the feature with a
pragma.
Reverts #1502, but flips test flags (e.g. `inlineUseMemo` by default, unless a
test specifies `@inlineUseMemo false`. I figured this add less thrash for test
fixtures, but happy to just do a clean revert (or remove the pragma altogether
and always pass `inlineUseMemo: true`)
Previously, we'd call and use getSnapshot on the second render resulting
in `Warning: Text content did not match. Server: "Nay!" Client: "Yay!"`
and then `Error: Text content does not match server-rendered HTML.`.
Fixes#26095. Closes#26113. Closes#25650.
---------
Co-authored-by: eps1lon <silbermann.sebastian@gmail.com>
---
In `lower`, we now ensure that all context variables are declared by a
`DeclareContext` instruction. `DeclareContext` always produces a `let`
declaration, and `StoreContext` is always a reassign. There are a few reasons we
need `DeclareContext`:
- DeclareLocal assumes it is storing to a SSA-fied identifier (which always
stores an immutable primitive). This does not fit context variables.
- Without DeclareContext, we need custom logic in some passes to initialize
identifier / context state (e.g. `MutableRange`, ValueKind, etc) for the
`StoreContext` that declares the context.
This PR stack models context variables as concrete identifiers (with references
to context variables modeled by `Place` referencing the context variable
identifier). @josephsavona pointed out that this is abusing the notion of
Identifier/Place, as context variables are essentially interior properties of a
ContextEnvironment. Since we are not modeling `ContextEnvironment` implicitly or
explicitly, all inference for context variables is essentially pointer analysis.
---
This PR adds LoadContext and StoreContext to handle reading and writing to
context variables.
A context variable is any variable that is declared within a Forget-compiled
function and reassigned within a closure. Conceptually, we want to treat these
variables as attributes of a `EnvironmentContext` variable (as most javascript
VMs do).
- context variables currently do not participate in type inference (i.e. we do
not produce type equations for loads from context variables). In the future, we
can try typing this as `Phi(assignment1Type, assignment2Type, ...)`.
- context variables are always treated as `Effect.Mutable`.
- context variables do not participate in SSA, or certain optimizing passes
(e.g. dead code elimination, constant propagation, etc).
There is some still follow ups:
- From my understanding, we should introduce a `DeclareContext` instruction.
- currently, declaring a context variable (without initializing it) is broken.
This is because the declaration lowers to `DeclareLocal`, which assumes it is
storing to a SSA-fied identifier.
```js
let x;
x = 4;
() => { x = {}; };
```
- DeclareContext will also make some initialization logic easier. In this PR, I
added some hack-y code to handle initializing effects / mutable ranges / other
inference state for the first StoreContext.
- Handle or bail on stores to context variables through destructuring assignment
-
~~Next PR:~~
- ~~Change closures to track reassigned identifiers (to extend mutable range of
primitives)~~
## Summary
To support incremental adoption of bridgeless logic we want to default
to using these globals whenever they're available.
## How did you test this change?
https://github.com/facebook/react-native/pull/37410
## Summary
Initially reported in https://github.com/facebook/react/issues/26797.
Was not able to reproduce the exact same problem, but found this case:
1. Open corresponding codepen from the issue in debug mode
2. Open components tab of the extension
3. Refresh the page
Received multiple errors:
- Warning in the Console tab: Invalid renderer id "2".
- Error in the Components tab: Uncaught Error: Cannot add node "3"
because a node with that id is already in the Store.
This problem has occurred after landing a fix in
https://github.com/facebook/react/pull/26779. Looks like Chrome is
keeping the injected scripts (the backend in this case) and we start
backend twice.
Enables hooks validation in playground. Also adds a tab to show the output of
validation (in case it passes) with the inferred post dominator tree. We can use
this to debug the dominator in case of false negatives.
<img width="1724" alt="Screenshot 2023-05-11 at 11 07 08 AM"
src="https://github.com/facebook/react-forget/assets/6425824/8f7ae472-8415-4899-aedf-c8f26094ebfe">
Incorporates the fixtures from eslint-plugin-react-hooks using a script, so that
we can easily update them in the future. For each fixture we run the compiler
with and without hooks validation first so that we know if the fixture is
expected to pass — we have some false positives and false negatives that i can
work through. For example we accidentally think that `userFetch()` is a hook,
oops. Fixtures that should pass but error, or that should error but pass, are
marked as `todo.<name>` or `todo.error.<name>`.
While i was here i added the ability to have fixtures in subdirectories for
grouping purposes.
---
Try to fix bug from #1589:
> If a declaration for an immutable identifier (i.e. one that is not later
re-assigned, since undefined is a primitive) is sandwiched between mutations, we
currently do not record it as an output or hoist it out of the reactive scope.
One simple fix is to add all declared (and later referenced) identifiers as
declarations of a reactive scope. This has some undesired effects (e.g.
additional instructions + memo cache slots), but in practice, this shouldn't be
happening often.
Alternatively, we could 1.) add a pass to hoist declarations, 2.) account for
this in constant propagation, or 3.) add a bailout
---
Record incorrect output.
If a declaration for an immutable identifier (i.e. one that is not later
re-assigned, since `undefined` is a primitive) is sandwiched between mutations,
we currently do not record it as an output or hoist it out of the reactive
scope.
While optimizing per @josephsavona's suggestions in #1592, I noticed that we
were clearing quite a few require cache entries.
As of this PR, `Object.keys(require.cache)` holds
- 1258 entries total
- 67 files compiled from Forget source code (this is what
`ts.createWatchCompilerHost` modifies)
- 1120 babel source files (from node_modules)
When working on watch mode, I'm almost always making changes to Forget source or
test fixture files. It's a bit faster to just clear those entries (assuming that
babel has no global state we need to invalidate).
On my computer, re-running tests in watch mode (triggered by source code
changes) takes:
| | All tests | One test (filter) |
|-- |--------|----------|
| current | 4.7s | 1.8s |
| this PR | 1.8s | 0.1s |
---
Some typed functions need to annotate callees or arguments as `Effect.Store`.
This PR modifies alias analysis (`InferAliasForStores`) to account for this
When I was renaming the next channel to canary, I updated the
`publish_preleases` workflow correctly, but I skipped over
`publish_preleases_nightly`. Oops.