Commit Graph
444 Commits
Author SHA1 Message Date
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
Joe Savona 47074a2def Support JsxSpreadAttribute
Changes the representation of JsxElement props to be an array of attributes, 
each of which can be a named attribute or spread attribute.
2023-01-31 16:43:46 -08:00
Joe Savona df07522b89 [be] Move Result into Utils/
The `Utils/` folder is meant to be a catch-all for code that doesn't have an 
obvious home in other directories.
2023-01-31 16:14:23 -08:00
Lauren Tan e8650951ea [playground] Add diff view toggle
Quick hack to show a diff view comparing previous pass to current. Default is 
the output view 

![Screenshot 2023-01-31 at 5 37 09 
PM](https://user-images.githubusercontent.com/1390709/215899637-672d578a-6fb9-4580-ae87-ae0be0878a59.png) 

![Screenshot 2023-01-31 at 5 37 12 
PM](https://user-images.githubusercontent.com/1390709/215899640-7aff3c06-fc67-476a-82f9-59d65b4f9ac4.png)
2023-01-31 17:37:22 -05:00
mofeiZ 5fbfce6d3b [test case] Failing assignment inside of nested if statement
``` 

function useBar(props) { 

let z; 

if (props.a) { 

if (props.b) { 

z = baz(); 

} 

} 

return z; 

} 

``` 

Currently fails with 

``` 

InvariantViolation: A phi cannot have two operands initialized before its 
declaration 

```
2023-01-31 16:53:06 -05:00
Joe Savona 0c5176c618 [valueblocks] Cleanup
Removes dead code related the now-unused old representation for value blocks.
2023-01-31 13:39:41 -08:00
Joe Savona fa525e0b6f [valueblocks] For.init is a value block 2023-01-31 13:39:40 -08:00
Joe Savona 894eadfa67 [valueblocks] For.update is a proper value block 2023-01-31 13:39:39 -08:00
Joe Savona 6930b5f77e [valueblocks] For.test is a proper value block 2023-01-31 13:39:39 -08:00
Joe Savona 90e1265442 [valueblocks] While.test is a proper value block
Changes ReactiveWhileTerminal’s test to use the new value block representation. 
This means logical and condition expressions will work as while test values now.
2023-01-31 13:39:38 -08:00
Joe Savona 50f300bc92 [valueblocks] Update some passes to use the new visitor
Updates some passes from ReactiveScopes/ to use the visitor added in the 
previous PR. The +124/-354 line count on this diff tells the story  — the new 
visitor avoids a lot of boilerplate and helps focus on the logic not the 
traversal. 

Note that there are a few passes which transform the function such as 
adding/removing scopes. A follow-up will extend the visitor to support that and 
convert the remaining passes.
2023-01-31 13:39:38 -08:00
Joe Savona 400bf4588c [valueblocks] More general visitor for ReactiveFunctions
This adds a truly general-purpose visitor pattern for ReactiveFunction, modeled 
on what's worked well in Relay Compiler. All types of node that have children 
get a visitFoo/traverseFoo pair of functions. By default the visitFoo() function 
delegates to the traverseFoo() function, but the visit variant is meant to be 
overridden and can delegate to the traverseFoo() variant — this gives you 
precise control so that you can save/restore state before/after traversing 
children. 

Probably the only interesting thing is that visitLValue() does not call 
visitPlace() by default though it technically could. So far that is making sense 
in the passes i converted. 

Note that once all passes are updated to use this, i'll delete the other visitor 
helpers for ReactiveFunction.
2023-01-31 13:39:37 -08:00
Joe Savona 149353badb [valueblocks] Support sequence expressions (comma operator) 2023-01-31 13:39:37 -08:00
Joe Savona d6505572cb [valueblocks] Disallow AssignmentExpression in value blocks (temporarily)
There's a bug with assignment expression in normal value blocks due to LeaveSSA. 
Until that's resolved i'm temporarily distinguishing "loop" blocks and "value" 
blocks, and disallowing assignment expressions in value blocks specifically.
2023-01-31 13:39:36 -08:00
Joe Savona 8c13c91f27 [valueblocks] ternary tests showing assignment bug
A ternary that reassigns the same variable in both branches causes some 
weirdness with LeaveSSA, this PR just adds the failing case.
2023-01-31 13:39:36 -08:00