Cleans up the public exports for the package itself:
* `parseFunctions()` was only used in playground, so this moves the definition
there. I had to update playground's dependencies to ensure the babel version
matched.
* Flattens away the `HIR` const in the export, and exports just 4 functions all
at the top-level: `run()`, `compile()`, `printHIR()`, and
`printReactiveFunction()`.
This will make it very easy to split the core compiler into a separate package
from the babel plugin, though i'm not sure it's worth doing that (yet).
Other than BuildReactiveFunction (HIR -> ReactiveFunction), Codegen.ts was the
only other remaining place that we use HIRTreeVisitor. However, we've already
switched the compiler to use the new form of codegen,
CodegenReactiveFunction.ts. This PR extracts the shared code from Codegen.ts
into the latter, and deletes the unused bits of Codegen.ts which relied on the
visitor API.
This now frees us up to merge BuildReactiveFunction and HIRTreeVisitor, removing
all the complexity of the visitor trait and type params.
Note that the `ReactiveFunction` data type can represent non-reactive functions.
So we can still compile non-React code after this change, the pipeline is `AST`
-> (BuildHIR) -> `HIR` -> (BuildReactiveFunction) -> `ReactiveFunction` ->
(CodegenReactiveFunction) -> `AST`. Which is the exact sequence I mapped out at
the start of this project ;-) (happy that worked out!)
See the background in #982. This PR reimplements part of InferReactiveScopes,
merging overlapping reactive scopes, but against ReactiveFunction instead of the
HIR.
See the background in #982. This PR reimplements part of InferReactiveScopes,
aligning reactive scopes to block boundaries, but against ReactiveFunction
instead of the HIR.
The primary goal of this stack is to change HIRTreeVisitor to make it easier to
handle value blocks. That's complicated by the fact that the visitor is a
general-purpose visitor, used in several analysis passes including
BuildReactiveFunction (which translates HIR->ReactiveFunction while also
grouping instructions into scopes) and InferReactiveScopes (which is actually
two passes, one to align scopes to block boundaries, one to merge overlapping
scopes). The long-term goal then is as follows:
1. Make BuildReactiveFunction transform HIR->ReactiveFunction but _without_
reactive scopes.
2. Align scopes to block boundaries, but rewritten to operate on
ReactiveFunction
3. Merge overlapping scopes, again rewritten to operate on ReactiveFunction
4. Group statements within ReactiveFunction into ReactiveScopeBlocks (today this
occurs when constructing the ReactiveFunction).
This PR implements 1 and 4. Because the implementation is incomplete this would
break the whole compiler, so for now both versions are still around. By default
compilation uses the old pipeline, but if a feature flag is enabled we use the
new version. The plan is to incrementally fix up the new version of the passes
in this stack, and then cutover: removing the flag and the old version of the
passes.
These values are never imported into `ReactFeatureFlags.www.js`, so
they're unused:
- `allowConcurrentByDefault`
- `consoleManagedByDevToolsDuringStrictMode`
These values are never set in the WWW module
(https://fburl.com/code/dsb2ohv8), so they're always `undefined` on www:
- `createRootStrictEffectsByDefault`
- `enableClientRenderFallbackOnTextMismatch`
It's not enough to only update the mutable range of the canonical id created
instead of the phi but we need to update the mutable range of each of the
operands of the phi as well to account for the fact that the phi could've been
mutated later.
The operands are updated only if the phi is mutated later. Otherwise these
operands can be cached in their blocks.
Fixes https://github.com/facebook/react-forget/issues/978
Changes playground to use the modified `run()` function of the compiler, polling
the generator and building up a Map of tabs automatically based on the passes
that the compiler runs. This means tabs are always derived from the current
state of the compiler and we can never forget to add a pass.
<img width="1497" alt="Screen Shot 2023-01-10 at 11 06 03 AM"
src="https://user-images.githubusercontent.com/6425824/211639442-da421f73-e19e-4b63-9f33-0ce5a68cceb7.png">
Note the inclusion of some recently added passes that weren't added to the
playground — which was my fault but only bc i intended to ship this PR soon :-)
Turns CompilerPipeline into two functions:
* `run()` is a generator and yields values that are a disjoint union of either
AST/HIR/ReactiveFunction along with a name for that step. The idea is to use
this in the playground so that it always matches the exact steps for
compilation. I'll update playground in a follow-up.
* `compile()` is ast in, ast out, and uses `run()` under the hood.
This mock exists in 2 directories (with identical implementation) and
Jest just picks one at random. This removes one which makes it at least
deterministic and fixes a Jest warning on startup.
It existed in these 2 places:
-
`packages/react-server-dom-relay/src/__mocks__/JSResourceReferenceImpl.js`
-
`packages/react-server-native-relay/src/__mocks__/JSResourceReferenceImpl.js`
(removed)
These suppressions are no longer required.
Generated using:
```sh
flow/tool update-suppressions .
```
followed by adding back 1 or 2 suppressions that were only triggered in
some configurations.
## Summary
I was reading the source code of `ReactFiberLane.js` and I found the
third parameter of the function markRootPinged was not used. So I think
we can remove it.
## How did you test this change?
There is no logic changed, so I think there is no need to add unit
tests. So I run `yarn test` and `yarn test --prod` locally and all tests
are passed.
Co-authored-by: Jan Kassens <jkassens@meta.com>
Implements constant propagation/constant folding for a conservative subset of
the language. The approach is described in detail in the comments in the file
itself, a key note here is that this pass currently emits what looks like
garbage:
```
// input
const x = 1;
const y = x + 1;
// output
const x = 1;
2; // <---- you'll see a bunch of lines like this
const y = 2;
```
These useless lines occur where previously there was a temporary getting
calculated that was used later (so we saved it until it was used), but now it
isn't used later so we just emit it in-place. Dead code elimination (DCE) can
eliminate these and other useless statements later.
Note that a key motivation for implementing this pass is to reduce memoization
blocks to what is strictly required for dynamic computations. Why memoize at
runtime when we compute at build time?
After the previous changes these upgrade are easy.
- removes config options that were removed
- object index access now requires an indexer key in the type, this
cause a handful of errors that were fixed
- undefined keys error in all places, this needed a few extra
suppressions for repeated undefined identifiers.
Flow's
[CHANGELOG.md](https://github.com/facebook/flow/blob/main/Changelog.md).
This enables the "exact_empty_objects" setting for Flow which makes
empty objects exact instead of building up the type as properties are
added in code below. This is in preparation to Flow 191 which makes this
the default and removes the config.
More about the change in the Flow blog
[here](https://medium.com/flow-type/improved-handling-of-the-empty-object-in-flow-ead91887e40c).
This setting is an incremental path to the next Flow version enforcing
type annotations on most functions (except some inline callbacks).
Used
```
node_modules/.bin/flow codemod annotate-functions-and-classes --write .
```
to add a majority of the types with some hand cleanup when for large
inferred objects that should just be `Fiber` or weird constructs
including `any`.
Suppressed the remaining issues.
Builds on #25918
When we convert a LabeledStatement to HIR we can end up emitting "consecutive"
blocks, ie where there are two blocks such that control flow will always go from
from one block to the other, with no other way to reach the second block but
through the first. Example:
```javascript
label: {
foo();
break label;
}
bar();
```
Converts to
```
bb0:
foo()
goto bb1:
bb1:
bar();
...
```
Ideally in this case we would merge these into a single block:
* When debugging, the extra goto makes it look like there is conditional control
flow when there isn't. If the code is consecutive it's easier to understand that
if it's a single block.
* Conversion from HIR -> AST relies on consecutive code all being in a single
block, so this breaks codegen (we never visit the goto target since all gotos
are assumed to be safe to convert to a break or continue).
This PR adds a failing test case, the next PR fixes it.
Phi operands and Block predecessors currently use a `BasicBlock` reference
rather than the BlockId. This diverges from other places (like terminals) where
we use an id and not a direct object reference. Especially since blocks may get
rewritten or pruned, it's a bit cleaner to use the block id in these places.