We need to check reactivity of both the operand and its resolved source (if
operand is produced by a LoadLocal / PropertyLoad / ComputedLoad).
Both the operand and its source can have reactivity.
e.g.
```js
const o = makeObject(); // source has no reactivity
const x = o[props.x]; // x is reactive
```
Rather than having a special FunctionCall type that deduces the return type,
change the FunctionType to include the return type.
This return type is inferred as part of unification.
---
Every `OptionalMemberExpression` rvalue has the form
`<requiredPath>?.<optionalPath>`.
```
// required = [a], optional: [b, c]
props.a?.b.c;
props.a?.b?.c;
```
When calculating reactive dependencies, recall that it is always correct to add
a subpath of a dependency (e.g. we can always take `props.a` instead of
`props.a.b` as a dependency). See comments in `DeriveMinimalDependencies` for a
longer explanation.
There are two ways we can deal with `OptionalMemberExpression`:
- We can always truncate a OptionalMemberExpression dependency to its
`requiredPath`, taking only the required path as a dependency.
- this is the simpler approach, but it potentially loses granularity.
e.g.
```
// here, since props.a is already unconditionally accessed,
// we can safely add props.a.b as a dependency and preserve both
// nullthrows and the correct dependency set.
scope @0 {
let x = [];
x.push(props.a?.b);
x.push(props.a.b);
}
```
(See added test case `reduce-reactive-cond-memberexpr-join` + its comment block
for a more detailed explanation`
- (the approach taken by this PR)
We can add the `requiredPath` as a potentially unconditional access (dependent
on other control flow) and `requiredPath + optionalPath` as a conditional
dependency.
Added an explicit type to all $FlowFixMe suppressions to reduce
over-suppressions of new errors that might be caused on the same lines.
Also removes suppressions that aren't used (e.g. in a `@noflow` file as
they're purely misleading)
Test Plan:
yarn flow-ci
Prerendering a tree (i.e. with Offscreen) should not suspend the commit
phase, because the content is not yet visible. However, when revealing a
prerendered tree, we should suspend the commit phase if resources in the
prerendered tree haven't finished loading yet.
To do this properly, we need to visit all the visible nodes in the tree
that might possibly suspend. This includes nodes in the current tree,
because even though they were already "mounted", the resources might not
have loaded yet, because we didn't suspend when it was prerendered.
We will need to add this capability to the Offscreen component's
"manual" mode, too. Something like a `ready()` method that returns a
promise that resolves when the tree has fully loaded.
Also includes some fixes to #26450. See PR for details.
## Summary
Just copied the types over from the internal types. Type error was
hidden by overly broad FlowFixMe. With `$FlowFixMe[not-a-function]` we
would've seen the actual issue:
```
Cannot return `dispatcher.useEffectEvent(...)` because `T` [1] is incompatible with undefined [2].Flow(incompatible-return)
```
## How did you test this change?
- [x] yarn flow dom-node
- [x] CI
Before a commit is finished if any new stylesheet resources are going to
mount and we are capable of delaying the commit we will do the following
1. Wait for all preloads for newly created stylesheet resources to load
2. Once all preloads are finished we insert the stylesheet instances for
these resources and wait for them all to load
3. Once all stylesheets have loaded we complete the commit
In this PR I also removed the synchronous loadingstate tracking in the
fizz runtime. It was not necessary to support the implementation on not
used by the fizz runtime itself. It makes the inline script slightly
smaller
In this PR I also integrated ReactDOMFloatClient with
ReactDOMHostConfig. It leads to better code factoring, something I
already did on the server a while back. To make the diff a little easier
to follow i make these changes in a single commit so you can look at the
change after that commit if helpful
There is a 500ms timeout which will finish the commit even if all
suspended host instances have not finished loading yet
At the moment error and load events are treated the same and we're
really tracking whether the host instance is finished attempting to
load.
Follow-up to https://github.com/facebook/react/pull/26442.
It looks like we missed a few cases where we default import a CommonJS
module, which leads to Rollup adding `.default` access, e.g.
`require('webpack/lib/Template').default` in the output.
To fix, add the remaining cases to the list of exceptions. Verified by
going through all `externals` in the bundle list, and manually checking
the webpack plugin.
---
Previously, both `path=null` and `path=[]` could represent a dependency with no
property path (i.e. the result of a LoadLocal with no PropertyLoad).
Make path non-nullable so we don't have to add null checks everywhere.
---
We don't need to store whether a `PropertyLoad` happens within a conditional
(within its reactive scope). In fact, the PropertyLoad producing a rval often is
in a different ReactiveScope from where the rval is used.
We only need to add `#inConditionalWithinScope` when we actually visit a
reactive dependency.
Earlier PRs bailed out when the callee of an OptionalCallExpression was a
MemberExpression or OptionalMemberExpression (ie for optional method calls).
This PRs expands support for optional method calls, including when the receiver,
method, or both are optional. Even better, we don't need to add any additional
terminals or instruction variants for this case - the one new OptionalCall
terminal from earlier in the stack works for all these cases.
Tests, focusing on two key behaviors:
* Dependencies of the args are treated as conditional, since the call may not
happen
* Args cannot be memoized independently, even when that would be valid for a
non-optional call.
Implements HIR->ReactiveFunction conversion and Codegen for optional calls. We
add a new OptionalCall variant of ReactiveValue, which is a SequenceExpression
that describes the evaluation of the args and the call itself. This is then
straightforward to codgen.
Implements lowering for a subset of optional calls - specifically, we don't
(yet) support when the callee is a member expression or an optional member
expression. So `foo?.()` works but we bailout on `object?.foo()` and
`object.foo?.()`.
For `<calleee>?.(<args>)` we lower as roughly:
```
bb0:
t0 = <callee>
OptionalCall test=bb1 fallthrough=
bb1 (value):
Branch t0 consequent=bb2 alternate=bb3
bb2 (value):
...lower <args> here...
t1 = Call t0, args
StoreLocal res, t1
Goto bb4
bb3 (value):
t2 = undefined
StoreLocal res, t2
Goto bb4
bb4:
// result in `res` here
```
Adds a new `optional-call` terminal and sets up the appropriate handling in the
visitors, with lowering/reactivefunction/codegen as todos for now and
implemented in follow-ups.
<!--
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
This PR:
- Updates Rollup from 2.x to latest 3.x, and updates associated plugins
- Updates deprecated / altered config settings in the Rollup plugin
pipeline
- Fixes some file extension and import issues related to use of ESM in
`react-dom-webpack-server`
- Removes a now-obsolete `strip-unused-imports` Rollup plugin
- <s>Fixes an _existing_ bug with the Rollup 2.x plugin pipeline on
`main` that was causing parts of `DOMProperty.js` to get left out of the
`react-dom-webpack-server` JS bundles, by adding a new plugin to tell
Rollup to treat that file as if it as side effects</s>
This PR should be functionally identical to the other existing "Rollup 3
upgrade" PR at #26078 . I'm filing this as a near-duplicate because I'm
ready to push this change through ASAP so that I can follow it up with a
PR that adds sourcemap support, that PR's artifact diffing seems like
it's possibly stuck and I want to compare the build results, and I've
got this set up against latest `main`.
<!--
Explain the **motivation** for making this change. What existing problem
does the pull request solve?
-->
This gets React's build setup updated to the latest Rollup version,
which is generally a good practice, but also ensures that any further
Rollup config tweaks can be done using the current Rollup docs as a
reference.
## How did you test this change?
<!--
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.
-->
- Made builds from the latest `main`
- Updated Rollup package versions and cross-compared the changes I
needed to make locally to get successful builds vs #26078
- Diffed the output folders between `main` and this PR, and confirmed
that the bundle contents are identical (with the exception of version
strings and the `react-dom-webpack-server` bundle fix re-adding missing
`DOMProperty.js` content)
---
Expand Hindley Milner type inference to infer dependent types.
Say `t` is a typevar and `t'` is some type (a built-in type, phi node, or
another typevar).
Our type equations are as follows (please edit/correct notation 😅)
- type substitution: `t = t'`,
- ~~dependent~~ polymorphic property load: `t = t'.prop`
- polymorphic function call `t = fnCall{returnType}`
- ~~dependent property call: `t = t'.prop` (only if t'.prop is a function
type)~~
- ~~dependent return type: `t = t'.[[returntype]]`~~
---
+10 −1,698 lines [[insert impacc macro]]
The ObjectShape stacks (#1350, #1358) used these tests to record changes in
inferred types (and associated ObjectShapes), reference effects, and mutable
ranges.
Now that those PRs have landed, we can delete these tests. They are somewhat
fragile (changing anytime HIR / printHIR is changed) and easily cause
rebase/merge conflicts.
---
This PR does not add inference for normal `CallExpression`s, since built-in
functions for `Array` and `Object` are usually only valid if called with a
correctly-typed `this`. If we want codegen to preserve source code semantics,
Forget should only add inferred types it is confident about.
This PR also adds `returnEffect` to FunctionSignature. `returnEffect = Store` if
this function is known to always return a captured value from `receiver` or
`args`.
---
Expand Hindley Milner type inference to infer dependent types.
Say `t` is a typevar and `t'` is some type (a built-in type, phi node, or
another typevar).
Our type equations are as follows (please edit/correct notation 😅)
- type substitution: `t = t'`,
- ~~dependent~~ polymorphic property load: `t = t'.prop`
- polymorphic function call `t = fnCall{returnType}`
- ~~dependent property call: `t = t'.prop` (only if t'.prop is a function
type)~~
- ~~dependent return type: `t = t'.[[returntype]]`~~
We limit the types of expressions allowed as switch case test values because we
our HIR doesn't yet preserve order-of-evaluation for switch test values (we
model them as being evaluated prior to entering the switch, as opposed to
lazily, when the case is reached). One common pattern internally is test case
values that are properties of a global, eg you have some bag of enum values and
are comparing against that:
```javascript
// at module scope, or imported from another module:
const OPTIONS = {FOO: 'foo'};
// in a component
switch (value) {
case OPTIONS.FOO: { ... }
}
```
This PR allows this specific case, ie member expressions where the innermost
object is a global identifier.
Now that we model the method resolution via a PropertyLoad or ComputedLoad, we
don't need to distinguish between PropertyCall and ComputedCall. These two call
variants are now combined into a single MethodCall variant.
This is the version of @mofeiZ's change for PropertyLoad, but made to work on
ComputedCall. We force the method to be evaluated in the same scope as the call
in InferReactiveScopeVariables.
---
(I'm not sure if these are already known issues. I found them while playing
around with lambda captures. They are also reproducible on main / stable)
I have some limited understanding of lambda captures after reading Sathya's
posts -- please correct if/where this is incorrect
```
function Component() {
// instr1
// instr2
const func3 = function(...) {
// func3instr1
}
}
```
We currently determine effects of captured references in `AnalyzeFunctions`,
before InferReferenceEffects.
- i.e. for some function
1. dependencies of all functions (func3.deps)
2. prefix traversal of all instructions (e.g. instr1, instr2, func3.deps,
func3instr1, ...)
- is this just an implementation decision? i.e. what is stopping us from postfix
traversal in InferReferenceEffects (e.g. instr1, instr2, func3instr1,
func3.deps)
As such, for each captured reference, `AnalyzeFunctions` needs to assign a
reference effect. We currently check `MutableRange`, which seems to miss a few
cases
- We do not model assignments to primitives correctly, since primitives do not
have a mutable range.
- We're not able to model captured (but not mutated) values correctly.
Would it be possible to consolidate `AnalyzeFunctions` into
InferReferenceEffects, using some post-order traversal (iterating over a
function's instructions to collect its dependencies + associated capture
effects)? I definitely don't understand lambdas completely, so please tell me
what I'm missing
---
This PR does not add inference for normal `CallExpression`s, since built-in
functions for `Array` and `Object` are usually only valid if called with a
correctly-typed `this`. If we want codegen to preserve source code semantics,
Forget should only add inferred types it is confident about.
This PR also adds `returnEffect` to FunctionSignature. `returnEffect = Store` if
this function is known to always return a captured value from `receiver` or
`args`.
---
I didn't properly understand Capture and Store effects previously, just
correcting those mistakes!
These functions are all synchronously mutative, so they should use Read /
Mutate, not Capture + Store
---
Expand Hindley Milner type inference to infer dependent types.
Say `t` is a typevar and `t'` is some type (a built-in type, phi node, or
another typevar).
Our type equations are as follows (please edit/correct notation 😅)
- type substitution: `t = t'`,
- ~~dependent~~ polymorphic property load: `t = t'.prop`
- polymorphic function call `t = fnCall{returnType}`
- ~~dependent property call: `t = t'.prop` (only if t'.prop is a function
type)~~
- ~~dependent return type: `t = t'.[[returntype]]`~~
## Summary
Now that React Native owns the definition for public instances in Fabric
and ReactNativePrivateInterface provides the methods to create instances
and access private fields (see
https://github.com/facebook/react-native/pull/36570), we can remove the
definitions from React.
After this PR, React Native public instances will be opaque types for
React and it will only handle their creation but not their definition.
This will make RN similar to DOM in how public instances are handled.
This is a new version of #26418 which was closed without merging.
## How did you test this change?
* Existing tests.
* Manually synced the changes in this PR to React Native and tested it
end to end in Meta's infra.
## Overview
This PR unfortunately removes the warning emitted when using layout
effects on the server:
> useLayoutEffect does nothing on the server, because its effect cannot
be encoded into the server renderer's output format. This will lead to a
mismatch between the initial, non-hydrated UI and the intended UI. To
avoid this, useLayoutEffect should only be used in components that
render exclusively on the client. See
https://reactjs.org/link/uselayouteffect-ssr for common fixes.
## Why this warning exists
The new docs explain this really well. Adding a screenshot because as
part of this change, we'll be removing these docs.
<img width="1562" alt="Screenshot 2023-03-15 at 10 56 17 AM"
src="https://user-images.githubusercontent.com/2440089/225349148-f0e57c3f-95f5-4f2e-9178-d9b9b221c28d.png">
## Why are we changing it
In practice, users are not just ignoring this warning, but creating
hooks to bypass this warning by switching the useLayoutEffect hook on
the server instead of fixing it. This battle seems to be lost, so let's
remove the warning so at least users don't need to use the indirection
hook any more. In practice, if it's an issue, you should see the
problems like flashing the wrong content on first load in development.
Fixes a bug in SuspenseList that @kassens found when deploying React to
Meta. In some scenarios, SuspenseList would force the fallback of a
deeply nested Suspense boundary into fallback mode, which should never
happen under any circumstances — SuspenseList should only affect the
nearest descendent Suspense boundaries, without going deeper.
The cause was that the internal ForceSuspenseFallback context flag was
not being properly reset when it reached the nearest Suspense boundary.
It should only be propagated shallowly.
We didn't discover this earlier because the scenario where it happens is
not that common. To trigger the bug, you need to insert a new Suspense
boundary into an already-mounted row of the list. But often when a new
Suspense boundary is rendered, it suspends and shows a fallback, anyway,
because its content hasn't loaded yet.
Another reason we didn't discover this earlier is because there was
another bug that was accidentally masking it, which was fixed by #25922.
When that fix landed, it revealed this bug.
The SuspenseList implementation is complicated but I'm not too concerned
with the current messiness. It's an experimental API, and we intend to
release it soon, but there are some known flaws and missing features
that we need to address first regardless. We'll likely end up rewriting
most of it.
Co-authored-by: Jan Kassens <jkassens@meta.com>
With this flag off, we don't throw and therefore don't patch up the tree
when suppression is off.
Haven't tested.
---------
Co-authored-by: Rick Hanlon <rickhanlonii@fb.com>
## Summary
This type was defined as `mixed` to avoid bringing the whole definition
from React to React Native, but its definition is visible to RN. This
type should be opaque to RN, so this makes it explicit.
## How did you test this change?
Applied the same changes in the React Native repository and could use
the type without issues.
How Forget currently lowers PropertyCall:
```js
// source: [[ calleeExpr ]].propertyName( [[ argExpr0 ]])
$0 = [[ calleeExpr ]]
$1 = [[ argExpr0 ]]
$2 = PropertyCall callee=$0 property="propertyName" args=[$1]
```
This PR changes the lowering:
```js
// source: [[ calleeExpr ]].propertyName( [[ argExpr0 ]])
$0 = [[ calleeExpr ]]
$1 = PropertyLoad $0 "propertyName"
$2 = [[ argExpr0 ]]
$3 = PropertyCall callee=$0 fn=$1 args=[$2]
```
From my understanding, `PropertyCall` needs the receiver to properly model JS
semantics which is something like `resolvedFn.apply(resolvedCallee, arg0, arg1,
...)`. This is additionally useful for:
- Fine-grained mutability / alias analysis. The property call is technically a
read of the resolved function, and a mutate of the callee.
- Dependency tracking. While we could special case PropertyCall, this
representation would correctly add both callee and callee.propertyName as
dependencies for PropertyCall.
e.g.
```js
let x = [];
mutate(x);
useFreeze(x);
let y = {};
y.a = x.bar();
return y;
```
Reverts #1199, which was added before we properly supported destructuring
assignment.
Next PR (changes to PropertyCall in #1384) will lower two references to the same
named identifier (the property call receiver)