Commit Graph
932 Commits
Author SHA1 Message Date
Lauren Tan a558b1536a [babel-plugin] buildFunctionDeclaration errors are todos
The existing errors thrown were marked as InvalidInput, which is now considered 
critical. This was causing an error in the sync since we had 2 occurrences of 
the errors being thrown. These are really todos and not invalid code.
2023-06-16 12:18:45 -04:00
Lauren Tan 501cf92f1e Unify UnsafeInput and InvalidInput 2023-06-15 15:13:37 -04:00
Lauren Tan 0d01d5f69c [eslint-plugin] Enable validation passes 2023-06-15 14:57:10 -04:00
Lauren Tan 0fdb1e5ac7 [eslint-plugin] Add test for invariants
Turning off this flag makes only critical errors throw, so TODO errors will no 
longer be surfaced by the plugin. The previously failing test for unsupported 
syntax is now valid.
2023-06-15 14:57:07 -04:00
Lauren Tan 87a39e1995 Mark InvalidInput errors as critical 2023-06-15 14:34:49 -04:00
Lauren Tan b68c409a6b [eslint-plugin] Throw non CompilerErrors 2023-06-15 14:34:46 -04:00
Lauren Tan fe91cd8ac1 [eslint-plugin] Parse flow 2023-06-15 14:34:43 -04:00
Lauren Tan c402d8de76 [eslint-plugin] Fall back to context.getSourceCode()
Older versions of eslint use the deprecated method, so add a fallback in the 
event a modern version of eslint isn't available
2023-06-15 12:52:57 -04:00
Lauren Tan c416fb16ca [make-read-only] Make tsconfig more consistent with other pkgs 2023-06-15 12:52:56 -04:00
Lauren Tan 6810ddbf56 [react-forget-runtime] Compile with typescript 2023-06-15 12:52:55 -04:00
Lauren Tan b6c1ca9718 [build] yarn bundle:meta builds and uploads all packages
Some changes to our build infra to create a Meta bundle containing all packages. 
Needs corresponding changes in the internal upgrade commands
2023-06-15 12:52:55 -04:00
Joe Savona aae9b01f91 Test cases for inferring mutability of function expressions (as values)
This PR contains just the test cases from #1717, showing some tricky cases 
around function expression mutability inference.
2023-06-15 09:32:30 -07:00
Joe Savona 8fcceb715c Rename feature flag for function expr optimization
This got lost in a rebase, just renaming for clarity.
2023-06-12 15:56:48 -07:00
Joe Savona a21660de00 Fix calculation of nested function dependencies
We were incorrectly calculating the dependencies of nested lambdas, because the 
"component" scope was incorrectly set to the next closest parent rather than 
outermost React function (component/hook) being compiled.
2023-06-14 14:04:26 -07:00
Joe Savona a8fff7cc5c Feature to optimize function expressions
This PR adds a new feature which enables additional validation/optimization of 
function expressions, gated by the `enableOptimizeFunctionExpressions` feature 
flag. When disabled, we actually revert the changes earlier in this stack, and 
do all our lowering of function expressions in AnalyzeFunctions. 

When the feature is enabled, we incrementally process function expressions in 
the various compilation stages, eg InferTypes infers into function expressions, 
ConstantPropagation propagates constants into function expressions, etc. Because 
this stage optimizes function expressions, in this mode codegen uses the HIR as 
the source rather than the original babel node. 

The feature is disabled by default so it has no impact on generated code. For 
now i've enabled the feature on just one test to demonstrate constant 
propagation into a function expression.
2023-06-08 18:05:41 -04:00
Joe Savona 4d7d2cf4dc Type inference across function expressions boundaries
Updates InferTypes to perform type inference across function boundaries. 
Specifically InferTypes is now responsible for driving type inference of 
function expressions (rather than deferring to AnalyzeFunctions to infer 
functions), and type inference now traverses into function expressions and 
infers types of free variables taking into account information from the outer 
context. This relies on the fact that identifier ids are consistent across 
function expression boundaries and that all free variables in functions are 
guaranteed to be effectively `const`, since we promote non-const variables used 
in function expressions to context variables.
2023-06-08 14:02:04 -04:00
Joe Savona 5775102b85 InferTypes traverses function expressions 2023-06-08 14:02:04 -04:00
Joe Savona 11d4ff430f ConstantPropagation traverses function expressions 2023-06-08 14:02:03 -04:00
Joe Savona e39855d251 EliminateRedundantPhi traverses function expressions 2023-06-08 14:02:03 -04:00
Joe Savona 638e45c928 EnterSSA traverses function expressions 2023-06-08 14:02:02 -04:00
Joe Savona c2c221a452 MergeConsecutiveBlocks traverses function expressions
Currently the process of lowering function expression bodies is deferred until 
AnalyzeFunctions. However, per the motivation of the previous PR, we'd like to 
be able to perform inference across function expression boundaries. To do that 
we need to use consistent identifier ids across function expression boundaries. 
This requires SSA conversion of function expressions at the same time as we 
enter SSA. 

To start, this PR moves MergeConsecutiveBlocks for function expressions into 
that phase.
2023-06-08 14:02:02 -04:00
Lauren Tan 3673272ca4 [eslint-plugin] Add basic test for unsupported syntax
Kinda works?
2023-06-07 15:41:22 -04:00
Mofei Zhang 246936ca57 [prettier] add expected prettierrc file 2023-06-08 14:32:22 -04:00
Mofei Zhang 166f47a41e [snap] Fix snap ignored paths 2023-06-08 14:32:22 -04:00
Joe Savona 8192cd253d Fix missing memoization of scope-less variable being reassigned 2023-06-07 22:15:59 -04:00
Lauren Tan 5673672ff9 Move playground to apps
Generally we should reserve the `packages` directory for packages that 

are needed to run the compiler, while `apps` is for frontends that might 

make use of the compiler (and optionally, related packages)
2023-06-07 14:40:42 -04:00
Joe Savona bf631a0bb6 Change rules for context variable promotion
This PR updates the conditions for which variables are promoted to context 
variables. 

The previous rule was to promote any variable where the variable was reassigned 
in some function expression other than the function that declared the variable. 
Notably, this meant that we did not use context variables for variables which 
were captured in a function expression, but reassigned _outside_ a function 
expression. 

The new rule is more consistent: we promote any variable which is a) reassigned 
somewhere and b) referenced in some function expression outside of their 
declaring function. The implementation builds two sets of identifiers, one for 
each criteria, then takes the union of these two sets. 

## Motivation 

The motivation for this change is to unblock additional validations and 
optimizations of function expressions. It's currently difficult to translate 
metadata that we infer about identifiers outside of a function expression into 
metadata about the identifiers within a function expression — for example to 
infer types within function expression bodies based on type information outside, 
propagate constants into functions, infer reference effects, etc. 

After this change, the only free variables inside function expressions will be 
variables that are effectively `const` - never reassigned anywhere. Thus it will 
be safe to renumber those identifiers to match the outer context (during 
EnterSSA), making it trivial to map metadata from outside the function into the 
function. 

This change also more closely models the runtime representation — any variable 
referenced in a function, and reassigned somewhere, would have to be compiled 
(ie in a JS engine) to use a context variable.
2023-06-05 22:11:08 -04:00
Lauren Tan 4e22fa6451 Try to fix test262 in ci 2023-06-06 15:25:20 -04:00
Lauren Tan 5ebb7f1a8e Try to compile with Forget in eslint plugin
Nothing interesting for now, but it does seem to successfully run the compiler
2023-06-06 10:56:21 -04:00
Lauren Tan 359df9e85c Enable TypeScript in eslint-plugin-react-forget 2023-06-06 10:56:21 -04:00
Lauren Tan 5c1faa901e Add workspace command to run all tests 2023-06-06 10:56:20 -04:00
Lauren Tan cd56c55e87 Basic noop rule for ReactForgetDiagnostics 2023-06-06 10:56:20 -04:00
Lauren Tan f82de29e73 Bootstrap new eslint plugin
Just scaffolds a new eslint plugin
2023-06-06 10:56:20 -04:00
Joe Savona 04d6bad1ae [ez] Update completed todo comment
lol at how out of date this comment is :-)
2023-06-05 16:46:38 -04:00
Joe Savona 39d837d918 Update fixtures from workspace rebase
I updated these yesterday, looks like they got added back in the workspace PR. 
Rebases are hard, all good!
2023-06-05 14:16:14 -04:00
Joe Savona 66ca1c75cb Fix dropped constant declaration bug 2023-06-05 14:08:29 -04:00
Joe Savona ad32811b64 [RFC] Improve validation against ref access in render
The goal of this PR is to improve ValidateNoRefAccessInRender to find function 
expressions which a) access refs and b) may be called during render. Currently 
we always allow ref access in any function expression, but that's obviously 
optimistic. 

For the approach, the observation is that we already have a system that tells us 
whether a function may get called — mutable range inference. So long as we 
consider a function "mutable", we'll infer a range for it, but the problem is 
that we don't currently view functions which depend on refs to be mutable. So 
here I'm doing ~~sort of~~ a hack to force function deps on refs to be treated 
as Effect.Capture. This is enough for the function to be considered mutable, for 
a mutable range to be assigned, and for us to detect that during ref validation. 

I don't love the hack, i'm open to other ideas!
2023-06-05 14:08:26 -04:00
Mofei Zhang b160ee8522 [tests] Tests and patch for context variables
--- 

- [patch] Find context variables within FunctionDeclarations (previously 
missing) 

- [todo] Need to fix non-allocating values / variables being DCE'd 

One approach is to label everything referenced by a lambda as context variables. 
I couldn't come up with other examples that break without this change, so I 
wonder if something lighter / hackier works just as well. (My only hesitation is 
that we may end up losing out on potential optimizations for everything aliased 
to these variables).
2023-06-05 15:04:46 -04:00
Mofei Zhang 6d1d05ff91 [runtime] Update makeReadOnly runtime
--- 

(wip, waiting for feedback on workplace post) 

- remove calls to `isInROMode`, as we want to log all mutations after 'freezing' 
a value (both within and outside of render cycle) 

- add `source` parameter -- this is the function name of the parent component / 
hook
2023-06-05 14:46:59 -04:00
Mofei Zhang 5ba0a03e00 [config] Clean up codegen imports and gating
- Gating checks for debugging / profiling can be moved to within the 
instrumentation or makeReadOnly functions. This simplifies codegen and reduces 
code bloat. 

- Warn if importing conflicting identifiers 

- Aggregate imports from the same source
2023-06-05 14:46:59 -04:00
Mofei Zhang a65e9cd1f1 [devx] emit calls to makeReadOnly for debugging
--- 

Emit calls to makeReadOnly for memoized values. 

```js 

function MyComponent() { 

let x; 

if (c_0) { 

x = // ... (recompute x) 

$[0] = __DEV__ ? makeReadOnly(x, "MyComponent") : x; 

} else { 

x = $[0] 

} 

} 

``` 

- import source / specifier should be configurable, as 

- we'll likely want to add gk gating to `makeReadOnly` itself to reduce codesize 
bloat 

- each Forget project needs different logging and filter configurations 

- codegen function name as an argument for easier debugging 

- only freeze memoized outputs
2023-06-05 14:46:58 -04:00
Lauren Tan 40d1459115 Scaffold workspaces
![image](https://github.com/facebook/react-forget/assets/1390709/bb27e33f-6a88-4b71-8ce2-aeb8db0372f7) 

This is an attempt to scaffold yarn workspaces into our repo with as minimal as 
possible changes to our current setup and directory structure. Essentially this 
PR moves current `src` into `packages/babel-plugin-react-forget` as a first step 
to keep everything working. Later on when we're ready we can split out a 
`react-compiler` package that is decoupled from Babel, but it's too early for 
that now
2023-06-05 13:35:39 -04:00
Joe Savona 3744930728 Fix last(?) order of evaluation bug
Not to get ahead of myself (sorry i had to), but i think this is the last order 
of evaluation bug. At least it's the last one we know of[1]. Per the previous 
PR, the issue is that constant propagation can copy the last value of a sequence 
expression to where the sequence is used, leaving the original sequence 
expression out of order after other instructions are moved around. We fix that 
here by explicitly skipping constant propagation for the last value of a 
sequence block. 

[1] There are some places where we _would_ have evaluation order bugs if we 
allowed arbitrary expressions, but we explicitly limit the expressions we allow 
in those places. For the curious: switch test case values and destructuring 
default values.
2023-06-04 21:41:27 -04:00
Joe Savona 1e0eb25cd0 Use sequence terminal, fix most remaining order-of-evaluation bugs
Changes the lowering for sequence expressions to use the new terminal. When 
converting to a ReactiveFunction, we convert these terminals into 
ReactiveSequenceValues, which nests the instructions and preserves order of 
evaluation in the output. 

The only catch is constant propagation — constant propagation breaks 
order-of-evaluation because it can effectively copy the final value of a 
sequence elsewhere, leaving the original sequence in the wrong place. I'll 
address that in a follow-up.
2023-06-04 21:26:01 -04:00
Joe Savona cd115ec128 Scaffold for sequence terminal
I realized that we can use our value block system to fix _most_ of the remaining 
order-of-evaluation issues we had with sequence expressions. This PR adds a new 
SequenceTerminal to HIR; there is already a ReactiveFunction equivalent 
(ReactiveSequenceValue) that the next PR will convert this terminal into.
2023-06-04 21:25:59 -04:00
Joe Savona e410815aeb Infer more primitive types
Handles three more cases: 

* Template literals 

* deletion (property/computed) 

* type casts 

Only the latter has an observable impact, though i added tests for deletion just 
in case and found a bug. For type casts, they're reasonably common internally 
for fixmes, so this PR will help to ensure we don't drop type information just 
because of a cast.
2023-06-04 20:27:24 -04:00
Joe Savona 084edadaa1 Distinguish error fixtures for invalid code
Renames some error fixtures for clarity, "error.invalid-*" are fixtures that are 
expected to fail for invalid input, where other "error.*" fixtures are basically 
todos. While i was here i clarified the error messages for invalid useMemo 
callbacks, and changes the error severity from Invariant to InvalidInput.
2023-06-04 11:41:42 -07:00
Joe Savona e41a8d6a1e Validate destructuring assignment to globals
Fixes one more category of bug. For assignment expressions, we validating 
against redeclaring a global variable when the assignment target was an 
identifier, but not when the global was reassigned via destructuring. This PR 
adds a `lowerIdentifierForAssignment()` helper and uses it for assignment of all 
identifier variants, including destructuring.
2023-06-04 11:29:55 -07:00
Joe Savona 2ae3592d29 Fix/review bug repros, mark fixed
I reviewed the test cases we have marked as bugs ("_bug.*") and realized that 
several of them are already fixed — woohoo! Then one wasn't fixed _yet_: our 
type inference loses track of refs if you stash them inside an object/array. But 
that's why I added the ValidateNoRefAccessInRender pass, which i've updated to 
detect and reject these invalid cases. There are now only a few bugs left (more 
fixes coming).
2023-06-04 11:08:54 -07:00
Lauren Tan 6d6518161a Cleanup packages directory
Prepare to move to a yarn workspaces setup
2023-06-02 13:06:36 -04:00