22 Commits
Author SHA1 Message Date
5894c3a0be [compiler] Bail out with Todo on using and await using declarations (#36946)
## Summary

The compiler silently rewrote functions containing `using` and `await
using` declarations (explicit resource management). BuildHIR's
`VariableDeclaration` case only special-cases `var`; every other kind
falls through to `InstructionKind.Const`. A `using` declaration
therefore compiled as a plain memoized `const`, and the implicit dispose
call at scope exit was dropped from the compiled output. No diagnostic
was emitted. The Rust port mirrored the same bug in `build_hir.rs`.

The Rust port had a second, harder failure: its
`VariableDeclarationKind` enum had no `await using` variant, so a Babel
AST containing one failed serde deserialization at the NAPI boundary
("unknown variant `await using`") and threw for the whole file.

The fix records the same per-function Todo bail as the existing `var`
case, in both implementations, then continues lowering the declaration
as `const` so references do not break while the error unwinds (mirroring
how `var` continues as `let`). This matches the compiler's established
Todo-bail precedent for unsupported syntax: the function is skipped with
a logged `CompileError` diagnostic, `panicThreshold` is respected, and
sibling functions in the same file still compile. This deliberately
contrasts with oxc-project/oxc#24217, which handles the same syntax with
a silent per-function skip; nothing in this compiler is skipped without
a surfaced diagnostic.

Changes:

- TS: `BuildHIR.ts` records a Todo `CompilerErrorDetail` for `using` and
`await using` kinds, in the style of the existing `var` case.
- Rust: same Todo `record_error` in `build_hir.rs`. New `AwaitUsing`
variant (serde name `"await using"`) in `react_compiler_ast`, so `await
using` survives the NAPI boundary, covered by a serde round-trip unit
test.
- Test harness: enables the `explicitResourceManagement` parser plugin
in snap and in the e2e script's Babel baseline so fixtures can use the
syntax.

Fixtures (identical snapshots for the TS and Rust pipelines):

- `error.todo-using-declaration` and
`error.todo-await-using-declaration` show the Todo diagnostic with code
frames.
- `using-declaration-bailout-sibling-compiles` shows the bailing
function left untouched (disposal preserved) while a sibling component
in the same file is memoized.

The first commit snapshots the previous broken behavior (`using`
memoized as `const` with disposal dropped); the second commit lands the
fix and updates the snapshots.

## How did you test this change?

All results below are from the branch rebased onto current main.

TS implementation:

- `yarn snap`: 1809 tests, 1809 passed, 0 failed.
- `yarn workspace babel-plugin-react-compiler lint`: clean. `yarn
prettier-check` at the repo root: clean.
- Manually verified pre-fix output: a component with `using resource =
getResource(props.id)` compiled to a memoized `const` with no disposal.

Rust implementation:

- `cargo test --workspace`: 42 passed, 0 failed (includes the new serde
round-trip unit test for both `using` kinds).
- `bash scripts/test-babel-ast.sh`: passed.
- `bash scripts/test-rust-port.sh`: 1808 passed, 0 failed.
- `yarn snap --rust`: 1809 tests, 1809 passed, 0 failed, against the
same `.expect.md` snapshots as the TS run.
- `scripts/test-e2e.ts` (babel variant): the three using fixtures pass
code and events parity.
- Manually verified `await using` now deserializes across the NAPI
boundary and records the Todo instead of throwing.

<div><a
href="https://cursor.com/agents/bc-5fe4350d-5d42-4c0e-9001-429ed0b5e5b7"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a
href="https://cursor.com/background-agent?bcId=bc-5fe4350d-5d42-4c0e-9001-429ed0b5e5b7"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

---------

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-07 20:46:37 -07:00
laurenandGitHub cda292d3ff [compiler] Port JSX tag classification fix to Rust (not-lowercase is a component) (#36951) 2026-07-07 09:46:24 -07:00
gtkatakuraandGitHub efedd75011 [compiler]: add useWindowVirtualizer to known incompatible libraries (#36912)
## Summary

#34493 added `@tanstack/react-virtual`'s `useVirtualizer` to the known
incompatible libraries, but not `useWindowVirtualizer`.

Both hooks are thin wrappers around the same internal
`useVirtualizerBase`, so they return the same referentially-stable
virtualizer instance. Its methods (e.g. `getVirtualItems()`,
`getTotalSize()`) return internally-mutated values rather than new ones,
which is exactly the "interior mutability" pattern that breaks
memoization described in the module type provider.

Because only `useVirtualizer` was registered, code using
`useWindowVirtualizer` is silently compiled with the same unsafe
memoization. In our app this froze `getVirtualItems()` to its
first-render value (an empty `[]` before measurement), producing
permanently-empty virtualized lists — the same class of bug #34493
fixed, just via the window variant.

This registers `useWindowVirtualizer` alongside `useVirtualizer` with
the identical shape, in **both** implementations:
-
`compiler/packages/babel-plugin-react-compiler/src/HIR/DefaultModuleTypeProvider.ts`
-
`compiler/crates/react_compiler_hir/src/default_module_type_provider.rs`
(Rust port)

See also the community report referenced in #34493:
https://github.com/TanStack/virtual/issues/736#issuecomment-3065658277

## How did you test this change?

Each addition mirrors the existing `useVirtualizer` entry exactly (same
kind, params, return type, and `knownIncompatible` message shape); both
are data-only additions to the module type providers, following the
precedent set by #34493 which changed only the TS file. The Rust change
keeps the two providers in sync.
2026-07-06 16:54:22 -07:00
de34f43004 [compiler] Fix failing Rust compiler test case for todo-locally-require-fbt (#36767)
Two fundamental changes (plus a lot of formatting that got mixed in :/
): Modify how we determine if a local binding exists for the case where
the scope is extracted from a function, rather than a module, which is
the case for snap tests. And, loosen the rust port tester to allow debug
output to be printed from one compiler or another as long as both sides
error in the same phase with the same error message (basically, the rust
port emits debug information before throwing an error, whereas the TS
version does one or the other -- but it's not actually a real
difference).

With this change and loosening, the Rust compiler conforms on the
todo-locally-require-fbt case.

---------

Co-authored-by: mvitousek <[email protected]>
2026-07-02 00:16:29 -05:00
BoshenandGitHub 8e28314c42 [rust-compiler] Use rustc-hash FxHasher for all maps and sets (#36811)
Swaps the default hashers across the Rust compiler crates for
rustc-hash's faster `FxHasher`.

## Why

`FxHasher` is a simple, fast, non-cryptographic hasher. std's default
(SipHash) is DoS-resistant but heavy — the compiler keys maps/sets
almost entirely on small integer IDs (`IdentifierId`, `BlockId`,
`ScopeId`, …) where that protection buys nothing. Switching gives:

- **Performance** — faster hashing on the hot ID-keyed maps/sets used
throughout the passes.
- **Slight binary size reduction** — drops the heavy SipHash hasher
pulled in by std's `HashMap`/`HashSet`.

## Changes

- `std::collections::HashMap`/`HashSet` →
`rustc_hash::FxHashMap`/`FxHashSet`
- `indexmap` `IndexMap`/`IndexSet` now use `FxBuildHasher`, inlined as
`IndexMap<K, V, FxBuildHasher>` (no `FxIndexMap` type aliases)
- `rustc-hash = "2"` added to all 12 crate manifests
- `rustc_hash`/`indexmap` imports consolidated into single brace imports
at the top of each file

The change is serde-neutral: `FxHashMap` and `IndexMap<_, _,
FxBuildHasher>` serialize to byte-identical JSON, and `IndexMap` keeps
insertion order.

`cargo check`, `cargo fmt --check`, and `cargo test` all pass with no
warnings.
2026-06-22 14:30:43 -07:00
BoshenandGitHub c8ae4d2ab4 [rust-compiler] Switch to hmac-sha256 and bump napi/similar (#36809)
## Summary

Dependency maintenance for the Rust compiler crates.

### Fast Refresh hash: sha2 + hmac → hmac-sha256
The Fast Refresh source hash (`enableResetCacheOnSourceFileChanges`)
only needs an HMAC-SHA256 of the source text, matching the TS compiler's
`createHmac('sha256', code).digest('hex')`. RustCrypto's `sha2` + `hmac`
pulled in **11 crates** (`sha2`, `hmac`, `digest`, `block-buffer`,
`typenum`, `crypto-common`, `hybrid-array`, `const-oid`, `cpufeatures`,
`cmov`, `ctutils`) — generic-hashing / constant-time machinery that is
irrelevant for a non-security content fingerprint. This replaces them
with the single **zero-dependency** `hmac-sha256` crate: a net reduction
of **10 crates**.

HMAC-SHA256 is a standardized deterministic algorithm, so the emitted
hash is unchanged. A new unit test
`source_file_hash_matches_node_create_hmac` pins the result against
Node's `createHmac('sha256', code).digest('hex')` for several inputs.

### Other bumps
- `napi` / `napi-derive` 2 → 3
- `similar` 2 → 3 (dev-dependency)
- Drop the unused `react_compiler_lowering` dependency from
`react_compiler_ssa`

`cargo check --workspace --all-targets` passes, including the napi 3
native crate.
2026-06-17 16:07:24 -07:00
laurenandGitHub 450d1e694f [compiler] Count loop reassignments as the enclosing scope reassigning the variable (#36732)
A counter initialized before a memo scope and incremented inside it
(`a++` or `a = a + 1` in a `for` body) was emitted as a scope
*dependency*, compared at its pre-loop value (constant every render)
while the cache stored its post-loop value. The memo could never hit, so
the scope recomputed on every render.

Root cause: the phi-union rule in
`InferReactiveScopeVariables.findDisjointMutableValues` only unioned a
phi into the scope when the phi value was mutated after creation, which
range-extension only does for object mutation. Primitive reassignments
around a loop back-edge never extend ranges, so the counter's SSA
versions stayed outside the scope and downstream dependency propagation
classified the pre-loop read as a dep.

The fix unions a phi with its operands and declaration when any operand
is defined at or after the phi's block, i.e. the value is reassigned
around a loop back-edge. This matches the shape the compiler already
produced for non-primitive loop reassignment (`x = [...x, i]`).
Implemented identically in the TypeScript compiler and the Rust port.

Both `a++` and `a = a + 1` variants are pinned by fixtures; the first
commit documents the previously-wrong codegen, the second fixes it
(counter becomes a scope output, dep on `count` only).

Corpus delta beyond the new fixtures is 4 fixtures, all strict
improvements with byte-identical eval output: `for-in-statement-break`,
`for-in-statement-continue`, `for-in-statement-type-inference` (loops
previously re-ran every render, now memoized), and `sequence-expression`
(two memo blocks collapse into one).

Known limitation, unchanged from before: conditional reassignment in a
loop (`for (...) { if (c) a++; }`) routes through a join phi that this
rule cannot see; that shape behaves as it did before this change.

Verification: TS snap 1806/1806, Rust snap 1806/1806, cargo workspace
green, scoped TS-vs-Rust HIR parity harness green.

Closes #34971
2026-06-17 15:54:14 -07:00
laurenandGitHub c9f0af7565 [rust-compiler] Represent string values as JsString (WTF-16 aware) (#36731)
Last of the boundary trilogy, after #36729 and #36730 (both merged);
rebased onto main as a standalone 3-commit change.

JS strings are WTF-16: a lone surrogate in source (`"\uD83E"`) is a
legal string value, but Rust `String` is UTF-8 and cannot hold it. The
compiler previously leaned on the napi bridge's `__SURROGATE_XXXX__`
marker encoding end to end, so the core compiler compared, concatenated,
and constant-folded marker text as if it were the actual string value.

`JsString` (in `react_compiler_diagnostics`, our lowest layer) holds the
common well-formed case as a plain UTF-8 `String` with zero overhead and
falls back to UTF-16 code units only for ill-formed values.
`StringLiteral.value` and `PrimitiveValue::String` carry it through the
pipeline; constant folding concatenates via code units so split
surrogate halves re-pair exactly as they do in JS; markers are emitted
only at the napi edge, where the babel bridge requires them (serde_json
can neither parse nor emit a lone `\uXXXX` escape).

The representation is encapsulated behind an opaque struct (private
`Repr` enum, borrowed `JsStringRef` view via `as_ref`) so the
"well-formed values are always UTF-8" invariant that makes the derived
`PartialEq`/`Hash` sound holds by construction, per review feedback.

The marker decoder scans byte-wise (an earlier draft range-sliced at
fixed offsets and panicked on multibyte UTF-8 following `__SURROGATE_`),
validates hex digits, and accepts uppercase only, exactly mirroring what
the bridge emits; lowercase marker-shaped user text survives verbatim.
The HIR debug printer renders unpaired surrogates as `\uXXXX` escapes
byte-identical to the TS printer.

This closes the lone-surrogate divergence on the e2e harness. Verified
on the rebased branch: cargo workspace tests, Rust snap channel
1804/1804, and HIR + Code parity on the lone-surrogate fixture through
the comparison harness.
2026-06-15 23:43:55 -07:00
dbc5501a7d [compiler] Remove OXC and SWC plugins in favor of them being handled by those projects (#36743)
I believe the consensus is that the OXC and SWC plugins should live in
those projects, and instead consume the React compiler as a crate

---------

Co-authored-by: mvitousek <[email protected]>
2026-06-11 15:41:04 -07:00
ed0367f4c0 [rust-compiler] Carry uninspected AST subtrees as raw JSON text (#36730)
Stacked on #36729 (upstream rejects cross-fork base branches, so this
targets main as a draft; the first commit belongs to the parent PR.
Review the last three commits. Will rebase and mark ready when #36729
lands.)

Unmodeled AST subtrees (type annotations, class bodies, unknown
statements) were stored as `serde_json::Value` trees: every node
allocated through a `Map<String, Value>`, and pass-through subtrees were
repeatedly traversed by code that never looks inside them. They are now
`RawNode`, a newtype over `Box<RawValue>` holding the original JSON text
verbatim.

Design notes, since two obvious alternatives fail:
- Bare `RawValue` fields break under `#[serde(tag = "type")]` enums:
internally-tagged deserialization buffers content into serde's private
`Content` tree, which `RawValue` cannot read from.
`RawNode::deserialize` instead streams whatever deserializer it is
handed through `serde_transcode` into a fresh JSON string, which works
behind tagged enums, `flatten`, and `from_value` alike.
- Default-limit reparses break deep ASTs: internal `RawNode` reparse
sites use `from_json_str_unbounded` (disables serde_json's 128-level
recursion limit, matching how the top-level parse is configured);
regression-tested with a 400-deep statement chain.

`parse_value` fails loudly on malformed text rather than masking
corruption with `Value::Null`; RawNode holds valid JSON by construction.

Size-neutral in the shipped binary; the win is structural (no
speculative `Value` trees on the hot path, pass-through subtrees stay
untouched text).

Verified on this exact tree: cargo workspace tests, both snap channels
1804/1804.

---------

Co-authored-by: Boshen <[email protected]>
2026-06-10 20:19:43 -07:00
496f32baab [rust-compiler] Return the compiled AST by value instead of JSON (#36729)
`compile_program` serialized the transformed `File` to a JSON string and
every in-process consumer immediately deserialized it back, so each
oxc/swc compile paid a full serialize/parse round-trip of the entire
program for nothing. `CompileResult::Success.ast` is now
`Option<react_compiler_ast::File>`; the napi bridge keeps its JSON
boundary by serializing at the edge, while the oxc and swc frontends
consume the typed AST directly.

This ports the typed-AST patch the Oxc team carries on their fork
(co-authored with Boshen), which also makes their integration patch-free
going forward.

Verified: cargo workspace tests, both snap channels 1804/1804, e2e
comparison harness at parity baseline (1802 byte-identical, fbt
local-require the one known divergence).

First of a stack of three with #36730 and #36731.

Co-authored-by: Boshen <[email protected]>
2026-06-10 20:19:29 -07:00
laurenandGitHub 31e757b24a [rust-compiler] Drop the regex dependency from the napi binary (#36727)
The regex crate services exactly one pattern, the dynamic-gating
directive `^use memo if\(([^\)]*)\)$`, while costing ~570KB of `.text`
(regex + regex_automata + regex_syntax + aho_corasick) in the shipped
binary; after LTO the removal saves ~1MB through dead-code cascade.

Replaced with an exact hand parse: strip the `use memo if(` prefix and
`)` suffix, reject conditions containing a close paren. Equivalence with
the TS `DYNAMIC_GATING_DIRECTIVE` regex verified on the full gating
fixture directory: 30/30 byte-identical TS-vs-Rust on the e2e comparison
harness, dynamic-gating snap fixtures green.

Independent of #36726; the two compose to take the default release
binary from 11.2MB to 6.1MB.
2026-06-09 15:38:32 -07:00
4deb1057b8 [compiler] Port React Compiler to Rust (#36173)
This is an experimental, work-in-progress port of React Compiler to
Rust. Key points:

* Work-in-progress - we are sharing early, prior to testing internally
at Meta, to get feedback from partners in parallel with continued
development.
* No builds available yet, you'll have to do some hacking if you want to
try this.
* All fixtures pass, no known gaps but there may be lurking bugs.
* The architecture was heavily guided by humans (me, @josephsavona) but
majority coded by AI. I was very hands-on in setting the architecture,
the testing and verification strategy, incremental migration approach,
etc. I also kept a close eye on the code and spent a decent amount of
time going back and forth to get code quality to a decent level.
* The public API is basically "Rust Babel AST" + Scope Info in, Rust
Babel AST out. We use a Rust representation of the Babel AST as our
"public API", as it were, and then each integration (Babel, OXC, SWC)
converts to/from their native representation. For now integrations must
also provide scope information - in the future React Compiler may
compute bindings and references itself from the AST.
* Internally, the Rust version uses the same architecture as the
TypeScript version. The compiler converts from the AST into our own
intermediate representation (HIR, short for High-level Intermediate
Representation) which uses a control-flow graph (CFG) and single-static
assignment (SSA). We go through the same series of passes, with the same
overall algorithms. It's very much a pass-by-pass port. The main
differences are in the data representation - using arena-like structures
(and indices into these arenas) to work within Rust's borrowing system.
* Early performance numbers are derived from AI and i haven't spent much
time validating the benchmark setup, beyond the fact that the
optimization opportunities it discovered made complete sense and the
fixes were right. With that caveat, itt does appear that the Rust
version is quite fast already: 3x faster when operating as a Babel
plugin. The serialization cost is quite high, but the actual
transformation logic is ~10x faster, so it's net faster. Native
integrations (oxc, swc) should be even faster.
* There are 3 integrations right now: an alternative Babel plugin (which
will eventually get removed as we integrate into
babel-plugin-react-compiler), and examples of what OXC and SWC
integrations could look like (see react_compiler_oxc and
react_compiler_swc crates).

correctness:
* all 1725 fixtures pass in snap when comparing the temporary rust
version of the plugin with the main version. this compares generated
code output as well as errors.
* all fixtures also pass a full comparison of the per-pass compiler
intermediate representation — the intermediate state (including log
events and errors) are ~identical after every single pass (modulo some
normalization of ids)
* The OXC and SWC example integrations seem to be working well, though i
haven't manually verified this to the same extent as i have the Babel
integration.

development:
* `yarn snap --rust` is the primary test suite, testing that we error or
compile as expected. It does not test the inner state of the compiler
along the way, though, making it less suitable for finding subtle logic
gaps btw the TS and Rust versions. It's also Babel based, making it less
easy to test OXC and SWC integrations.
* `compiler/scripts/test-e2e.sh` is an e2e test of all 3 variants (babel
wrapper around Rust, OXC/SWC integrations) against the TS
implementation. This does a partial comparison, focused on final output
code only (doesn't test error details etc). Useful for getting the swc
and oxc integrations closer to parity.
* `compiler/script/test-rust-port.sh` does detailed testing of the
internal compiler state after each pass, in addition to checking the
final output code. This is the key script used to port the compiler,
ensuring not just that the output was the same but that each pass was
capturing all the same detail. This script can be pointed at *any*
directory of JS files, which we expect to use for internal testing at
Meta.


## For Partners

We're excited to partner with teams to integrate the Rust version of
React Compiler into other tools, like OXC and SWC. If you're interested
in working with us on this, the best place to start is by taking a look
at the react_compiler_swc and react_compiler_oxc crates. These give you
an idea of the API shape that we're thinking of.

Note that the conversion from any AST into our HIR is complex, and we
can only maintain one version. Hence we've aligned on using a Babel-like
AST as our public API. Another key point is that we don't yet implement
our own scope analysis (since the TS version of the compiler relied on
Babel's scope analysis), so for now we require that the scope data be
serialized. It's a denormalized graph, and some metadata has to be
stored to associate nodes with scopes. We're open to feedback about the
AST and scope representation - we iterated a bit just to get things to
work, but it can be more optimal.

Key changes that we are considering:
* Currently the compiler returns `Option<Program>`, which is `Some` if
anything changed. This requires replacing the entire program. We plan to
change this to return a series of patches to apply, in a form that is
reasonably usable and efficient for all the integrations we care about
(Babel, OXC, SWC, etc).
* The Rust representation of the Babel AST is fine enough, but we could
make it more optimal by doing arena allocation. We also plan to change
the string representation to smol_str.
* The scope representation, and association of data btw AST and scope,
is very much a first pass approach that is good enough. We expect to
implement our own scope resolution, though, so we hopefully won't need
to iterate on the scope representation and can just throw it away.

In terms of the shape of the integration, we anticipate that each
integration would have the following:

* Implementor repo (OXC, SWC, etc): lightweight code transform and lint
pipeline integration that delegates to `crates/react_compiler_<name>`
from our repo
* Our repo: one crate per implementor, eg react_compiler_swc,
react_compiler_oxc, where most of the logic lives.

This setup lets us make changes to the integration layer easily within
our repo. Feedback appreciated!

---------

Co-authored-by: Joe Savona <[email protected]>
Co-authored-by: Mike Vitousek <[email protected]>
Co-authored-by: Mike Vitousek <[email protected]>
Co-authored-by: lauren <[email protected]>
Co-authored-by: lauren <[email protected]>
2026-06-09 14:53:06 -07:00
Joe Savona 2e19063984 [compiler][be] Remove unused experimental Rust port
I wrote this a couple summers back as an experiment to see how easily we could translate the compiler to Rust. We make extensive use of in-place mutation of the IR, and the experiment proved that this we can get reasonable ergonomics for this in Rust which was cool. We've since ended up using some of the code here for Relay, allowing Relay Compiler to parse JS files to do more fine-grained extraction of data. For React Compiler though, we plan to continue using JavaScript and explore lightweight native wrappers for things like OXC and SWC plugins. We're also working with the Hermes team to eventually compile the compiler with Static Hermes.

As Tomo always says: always bet on JavaScript.

ghstack-source-id: c5770a2efc
Pull Request resolved: https://github.com/facebook/react/pull/32219
2025-01-24 12:23:31 -08:00
Lauren Tan 0e06b111b7 Fix rust lints
ghstack-source-id: baf433a98a70d9105c8088d82e04a3d96783e9e6
Pull Request resolved: https://github.com/facebook/react/pull/30616
2024-08-06 14:48:32 -04:00
Jan KassensandGitHub 6886e867c3 Rust: add stub for ensure_sufficient_stack (#2943) 2024-05-07 15:41:03 -04:00
Joe Savona f33e63838d Update copyrights to reference Meta instead of Facebook
Thanks @zpao!!! This was mostly his work, i just fixed up the last bit.
2024-04-03 08:43:36 -07:00
Joe Savona 852301828b Remove reactive_ir crate 2024-04-02 21:03:25 -07:00
Joe Savona 8a43e954a2 s/Forget/React Compiler/ in Rust port 2024-04-02 16:49:31 -07:00
Lauren Tan 6a71868d4c [sprout] Convert for-of-mutate to sprout 2023-09-05 12:35:18 -04:00
Joe Savona 7d11445d8e Revamp compilation modes
We currently have multiple flags for targeting which functions to compile, but 
they are actually mutually exclusive. This PR consolidates to a single 
`compilationMode: 'annotation' | 'infer' | 'all'` flag: 

* Annotation compiles only functions that explicitly opt-in with "use forget" 

* Infer compiles explicitly opted-in functions (via "use forget") as well as any 
known/inferred components or hooks: 

* Component declarations 

* Component or hook-like functions (same rules as the ESLint plugin but with an 
extra check for whether it uses JSX or calls a hook) 

* All compiles all top-level functions. We should get rid of this in a follow-up 
and make tests use infer mode by default, and add explicit opt-ins where 
necessary. 

In all modes, "use no forget" always takes precedence and can be used to 
opt-out. The default mode is now "infer".
2023-08-29 22:09:40 +01:00
lauren a0dc166991 [rfc] Remove top level forget directory
Sorry about the thrash in advance! This removes the top level `forget` directory 
which adds unnecessary nesting to our repo 

Hopefully everything still works
2023-08-22 15:04:54 -04:00