Commit Graph
1708 Commits
Author SHA1 Message Date
Joe Savona 41f52b73c2 Change reference effects for hooks
I realized we hadn't updated InferReferenceEffects to match our latest thinking 
on hooks. Specifically, we will default to assuming that hooks can mutate their 
arguments and return mutable values — this works with our model since we don't 
treat hooks specially for reactive scope construction. Ie, first we figure out 
what variables construct together, then we create scopes, then we prune scopes 
that contain hooks. So changing the reference effects for hooks "just works". 

Note that it is helpful for our unit tests to have an example hook that we know 
_does_ freeze its input and return a frozen value, so i've temporarily added 
`useFreeze()` to the list of defined hooks. That is meant as a stopgap: the 
right solution is to allow some way to tell the compiler about specific custom 
hooks and their semantics.
2023-02-08 14:24:14 -08:00
Joe Savona 7f60f32118 Dont memoize scopes with hook calls 2023-02-08 14:07:01 -08:00
Joe Savona c7e3bc4d41 Visitor extension for transforming ReactiveFunction
Adds a subclass of ReactiveFunctionVisitor, ReactiveFunctionTransform, which 
makes it easier to write passes that change the shape of a ReactiveFunction. The 
two use-cases converted so far are both flattening away certain categories of 
reactive scopes — this will make it easier to add a similar pass to prune scopes 
that contain hook calls.
2023-02-08 14:07:00 -08:00
Sathya Gunasekaran 394666118d [hir] Lower function expressions into HIR 2023-02-08 17:45:33 +00:00
Sathya Gunasekaran 662b8d2ff3 [hir] Add lvalue effect for PropertyLoad and ComputedLoad 2023-02-08 16:01:36 +00:00
Lauren Tan d47f608c61 Record reassignments
Record a variable that is declared in some other scope and that is being 
reassigned in the current one as a reassignment
2023-02-08 10:26:33 -05:00
Lauren Tan e7f4eae619 Reset canonicalId mutable range if not mutated after creation 2023-02-08 10:26:31 -05:00
Lauren Tan 6f661f3b79 Extend mutable ranges if a phi is mutated after creation 2023-02-08 10:26:29 -05:00
Lauren Tan d43a5014f4 Rename ReactiveScope.outputs to ReactiveScope.declarations 2023-02-08 10:26:27 -05:00
Lauren Tan 1809ffd06d Add new test cases for SSA
Add these as a separate commit so we can see how later PRs in the stack change 
them
2023-02-08 10:26:26 -05:00
Lauren Tan 5888cbdd9b Don't throw on invalid compiler flags 2023-02-08 10:26:24 -05:00
Sathya Gunasekaran 24b28ae257 [λ] Remove broken support for identifiers defined after use
This also adds some book keeping to throw if ever define identifiers after use 
to make sure we don't generate incorrect code.
2023-02-07 18:25:55 +00:00
Sathya Gunasekaran d1dbb00790 [hir] Throw if Effect.Store is not handled 2023-02-07 16:59:37 +00:00
Sathya Gunasekaran 3df1ae66c0 [λ] Use Effect.Capture for mutating deps
Leverage Effect.Capture to differentiate between mutating and non mutating deps.
2023-02-07 16:59:36 +00:00
Sathya Gunasekaran 85c92bcfbe [aliasing] Introduce Effect.Capture
Effect.Capture is very similar to Effect.Read, but the only difference is that 
this reference is stored somewhere via a Effect.Store. 

Previously, any operand associated with a Effect.Store in the same instruction 
would get aliased -- so there was no need to explicitly differentiate between a 
"normal read" and "read that gets stored". 

This difference is now explicit with FunctionExpression where every dependency 
is "read" but only a few are "captured" for store (and mutation). In a follow up 
PR, the mutating deps will have an Effect.Capture to differentiate from the 
other non mutating deps (Effect.Read).
2023-02-07 16:59:35 +00:00
Sathya Gunasekaran 4e07b8a869 [hir] Do not alias Identifier as Store
Identifiers are never stored (Effect.Store), they are always mutated 
(Effect.Mutate) and aliased in the InferAlias pass.
2023-02-07 16:59:35 +00:00
Lauren Tan 195f473cb4 s/useMemoCache/unstable_useMemoCache
uMC is still prefixed with unstable in React 
(https://github.com/facebook/react/blob/653dd2348ccfd7bfa4e11d814e247ed3ff7c5fa7/packages/react/src/React.js#L143)
2023-02-07 11:40:06 -05:00
Sathya Gunasekaran 1f7cd2ff21 [hir] Remove unnecessary null check 2023-02-07 15:08:38 +00:00
Lauren Tan 9cac0b0068 Ensure Forget runs first if specified in a Babel config
This commit adds a new Program visitor to our Babel plugin which then calls our 
FunctionDeclaration visitor. Babel does some "smart" merging of plugin passes so 
so even if plugin A is inserted prior to plugin B, if A does not have a Program 
visitor and B does, B will run first. 

Note that we also can't use Forget inside of a Babel preset as plugins run 
_before_ presets (https://babeljs.io/docs/en/plugins/#plugin-ordering).
2023-02-07 11:11:58 -05:00
Lauren Tan e159844b0d Add generated code to errors thrown by BabelPlugin
If we've generated an erroneous AST (eg duplicate declarations), this lets us 
observe what the code looked like to aid debugging
2023-02-06 19:03:54 -05:00
Lauren Tan 0d2653dbd4 Use parent of AssigmentExpressions when bailing out
For some reason the expression itself wont print the codeframe, but its parent 
will, so print that instead
2023-02-06 17:32:30 -05:00
Joe Savona 382226ab31 Add missing return statements to fixtures 2023-02-06 14:09:15 -08:00
Sathya Gunasekaran 500cfddc3a [λ] Remove unused params in FunctionExpression 2023-02-06 14:03:13 +00:00
Lauren Tan cd108cd430 Add enableOnlyOnUseForgetDirective flag
When this flag is enabled, Forget will only compile function declarations opted 
in via the `'use forget'` directive. By default this is false. 

Tested internally, see related diffs
2023-02-06 16:47:35 -05:00
Joe Savona b009626431 Improve DCE to handle unused loop phis
Improves DCE, using fixpoint iteration to detect values that are updated across 
loops but otherwise never read. There is still some further optimization we can 
do (the dce-loop case could optimize out `y`), but this seems like plenty for 
now. 

Actually, we probably have to add some return statements to our fixtures before 
landing this, because otherwise most of the code goes away.
2023-02-03 15:46:00 -08:00
Joe Savona 19e21b73a7 Initial pass at dead code elimination
This is a first pass at DCE without having read any literate on the subject, so 
lemme know if there's a better approach. That said the algorithm is: 

* Keep a `Set<Identifier>` of identifiers that are used (and whose constructing 
logic cannot be removed). 

* Do a first RPO iteration of all block's phis. Any phi operand that 
participates in a loop is preemptively marked as "used" even if it isn't 
strictly used somewhere. This step is necessary bc these operands may otherwise 
not be used. 

* Do a second post-order iteration of all blocks, including iterating first 
their terminals, then reverse iteration of instructions, then their phis. Mark 
the operands of each as used as we encounter them, and prune instructions whose 
lvalue is never used. 

For now I was conservative about which types of instructions can be pruned. For 
example, call instructions are never pruned, even if the result of the call is 
never used. 

However one catch is that we currently prune instructions that cause values to 
become frozen. We had planned to add runtime calls (in dev) to freeze values for 
runtime enforcement, and if we want to do that we can always add these 
instructions back (or replace them with explicit freeze calls). 

There are a few potential next steps but we should discuss whether they're worth 
it: 

* Use fixpoint iteration to find exactly which operands are actually used. This 
would allow us to to prune cases such as `let x = 0; while (...) { x += 1 }` eg 
where there's a phi but the result is never used. Such cases should be rare in 
practice though. 

* Eliminate more types of instructions, eg eliminate function calls that don't 
have any mutable arguments.
2023-02-03 14:55:49 -08:00
Joe Savona 812e0ce701 [valueblocks] Join blocks instead of replacing operands (fix edge case)
There's a bug in the HIR->ReactiveFunction conversion for certain categories of 
compound value blocks where we replace operands (which must be a Place) with a 
ReactiveValue. This approach worked in practice for lots of cases so I thought a 
type coercion was safe, but then I found a case where this assumption breaks 
(see new test). 

The updated logic fixes the bug and is simpler. When a value block gets split up 
(because there was a nested value block), instead of replacing the earlier value 
in the later instructions, we append the instructions together. This can result 
in some extra nesting (which if we wanted we could flatten away) but ensures 
that we maintain type-safety.
2023-02-03 14:16:17 -08:00
Joe Savona cc33497c44 [valueblocks] Add InstrId to SeqExperession value
A SequenceExpression currently doesn't store the InstructionId that produced its 
final `.value`. This PR adds that instruction id, which is then used in the next 
PR as we compose SequenceExpressions.
2023-02-03 14:16:17 -08:00
Joe Savona 29a95d2dea [be] Use generator in InferTypes, extract helper
Just small things I noticed when looking at InferTypes. I was thinking about how 
we'd adjust this pass to account for hooks, i'll probably pause that for now but 
putting this up in case you like the changes. If not no big deal!
2023-02-03 12:59:13 -08:00
Mofei Zhang e30a9e9258 [hir syntax] Handle TemplateLiteral syntax 2023-02-03 15:44:37 -05:00
Mofei Zhang 34595b84c8 [syntax] Followup: clean up InferReactiveIdentifiers 2023-02-03 15:44:36 -05:00
Sathya Gunasekaran 4b55399fb8 [λ] Use context identifiers in inner functions
This threads through context identifiers to inner functions and also uses them 
as dependencies if they are mutated in the inner function.
2023-02-03 17:42:07 +00:00
mofeiZ ecb084c4b8 [ReactiveHIR] Infer reactive identifiers and promote temporaries
Messed up ghstack, this is a duplicate of #1093
2023-02-03 14:52:46 -05:00
Joe Savona 34a7b58334 Restrict switch case test values until they use value blocks
We currently lower switch case test values within the wrong scope: the test 
value really should be a value block rather than a `Place`. Until then, this PR 
adds a bailout for complex test values: we allow primitives and identifiers 
which should cover most real-world use-cases.
2023-02-02 09:09:25 -08:00
Sathya Gunasekaran dc65e7c5a9 [aliasing] Make InferAliasForStores use the visitor infra
No need for InferAliasForStores to know about the semantics of each instruction 
anymore. It's just a simple pass that iterates over every operand and lvalue. 

The FunctionExpression is special cased because it's slightly different but I 
have a follow up that removes this special casing.
2023-02-02 17:41:35 +00:00
Sathya Gunasekaran 40f304392e [aliasing] Alias object loads to it's lvalue as well
This doesn't change codegen as the lvalue is unused but it lets us make this 
pass be semantically the same across all instructions -- "alias lvalue and 
operands of an instr".
2023-02-02 17:41:31 +00:00
Sathya Gunasekaran 018899d778 [aliasing] Make aliasing account for MutableRange.end being exclusive 2023-02-02 17:41:27 +00:00
Sathya Gunasekaran 98f67c407b [aliasing] Alias ComputedLoad operands 2023-02-02 15:45:16 +00:00
Sathya Gunasekaran 5e1929c002 [aliasing] Alias ComputedStore operands 2023-02-02 15:45:12 +00:00
Joe Savona de929fcc40 Partial support for update expressions
Adds limited support for UpdateExpressions (`x++`). We now support the postfix 
form (`x++` ok, `++x` is a todo) and only when the argument is an identifier. We 
can relax these restrictions with more work, but this PR should be sufficient 
for the examples we've seen so far.
2023-02-02 07:53:24 -08:00
Sathya Gunasekaran 7a92b2fe5d [be] Cleanup logic that matches mutatedId and mutatedDep 2023-02-02 14:05:37 +00:00
Sathya Gunasekaran 12274f30b9 [be] Inline buildMutatedDeps 2023-02-02 14:05:36 +00:00
Sathya Gunasekaran aa2403e068 [λ] Run analyseFunctions on inner func exprs
Previously we would skip out on calling analyseFunctions on inner function  
exprs so we missed out on catching aliased mutation in a different scope.
2023-02-02 14:05:35 +00:00
Sathya Gunasekaran 0522d5233b [λ] Store and define captured bindings as context
This lets us treat global references differently from captured references.
2023-02-02 14:05:34 +00:00
Lauren Tan 8a0d3169fd Record todo bailouts in CodegenReactiveFunction
Went over this pass and converted any todos to bailouts, otherwise we continue 
to throw an invariant if there's an internal error
2023-02-01 14:49:47 -05:00
Lauren Tan 1baf22a421 [playground] Fix error wrapping for realsies
CSS is hard (jk i'm just terrible at it now)
2023-02-01 14:14:45 -05:00
Lauren Tan 8c9d1b85be Failing test from - - 2023-02-01 13:46:20 -05:00
Lauren Tan f53318d0ba [playground] Fix errors not wrapping 2023-02-01 13:17:04 -05:00
Joe Savona c2dda028fd Improve debugging for - errors 2023-02-01 09:42:46 -08:00
Joe Savona 2069269903 Support TypeCastExpression
Support TypeCastExpressions — `(x: TypeAnnotation)`. This is pretty 
straightforward, it's semantically identical to a raw identifier. 

One catch is that our prettier config is hard-coded to use the babel-ts parser, 
i wasn't sure how to make that dynamic based on the file extension so for now i 
just ignored .flow.js files in our pretter config.
2023-02-01 08:42:33 -08:00