Commit Graph
19463 Commits
Author SHA1 Message Date
Mofei Zhang c00e7a2af2 [test] Test case for optional chaining in codegen
```js 

// here, `a?.b.c` is a single optional chain 

// (evaluates to undefined if a is nullish) 

a?.b.c; 

// here, 'a?.b` is an optional chain, and `.c` is an unconditional load 

// (nullthrows if a is nullish) 

(a?.b).c; 

``` 

--- 

Next PR in stack will add a bailout for `(a?.b).c`. 

(If we want to properly handle `(a?.b).c`, we might want to model optional 
chains explicitly in the HIR. We currently assume that any `PropertyLoad` whose 
lhs is an optional property load is read conditionally.)
2023-03-30 18:43:55 -04:00
Sathya Gunasekaran 0eeedee95e [hir] Rewrite identifiers to be consistent
If we resolve identifiers to be different from the binding, update the binding 
to the new name.
2023-03-31 12:35:17 +01:00
Sathya Gunasekaran 3b3d15eaeb [hir] Check if callee before pruning member path 2023-03-31 16:36:04 +01:00
Lauren Tan 46a9d40914 [babel] Invoke gating module as a call expression
This is incredibly obvious in hindsight, but for exposure logging to work 
correctly we need to *call* the underlying `MobileConfig.getBool` function at 
the callsite – otherwise the bool is evaluated once (and only once) when the 
module is loaded. 

Tested internally and verified that in dogfooding the exposure logging was 
working correctly
2023-03-31 11:15:51 -04:00
Sebastian Markbåge 43a70a610d Limit the meaning of "custom element" to not include is (#26524)
This PR has a bunch of surrounding refactoring. See individual commits.

The main change is that we no longer special case `typeof is ===
'string'` as a special case according to the
`enableCustomElementPropertySupport` flag.

Effectively this means that you can't use custom properties/events,
other than the ones React knows about on `<input is="my-input">`
extensions.

This is unfortunate but there's too many paths that are forked in
inconsistent ways since we fork based on tag name. I think __the
solution is to let all React elements set unknown properties/events in
the same way as this flag__ but that's a bigger change than this flag
implies.

Since `is` is not universally supported yet anyway, this doesn't seem
like a huge loss. Attributes still work.

We still support passing the `is` prop and turn that into the
appropriate createElement call.

@josepharhar
2023-03-30 18:38:50 -04:00
mofeiZ 5beecef28f [patch] Remove invalid invariant in deriveMinimalDeps
Confirmed that this fixes invariant violation on -
2023-03-30 17:33:37 -04:00
dan 1308e49a69 [Flight Plugin] Scan for "use client" (#26474)
## Summary

Our toy webpack plugin for Server Components is pretty broken right now
because, now that `.client.js` convention is gone, it ends up adding
every single JS file it can find (including `node_modules`) as a
potential async dependency. Instead, it should only look for files with
the `'use client'` directive.

The ideal way is to implement this by bundling the RSC graph first.
Then, we would know which `'use client'` files were actually discovered
— and so there would be no point to scanning the disk for them. That's
how Next.js bundler does it.

We're not doing that here.

This toy plugin is very simple, and I'm not planning to do heavy
lifting. I'm just bringing it up to date with the convention. The change
is that we now read every file we discover (alas), bail if it has no
`'use client'`, and parse it if it does (to verify it's actually used as
a directive). I've changed to use `acorn-loose` because it's forgiving
of JSX (and likely TypeScript/Flow). Otherwise, this wouldn't work on
uncompiled source.

## Test plan

Verified I can get our initial Server Components Demo running after this
change. Previously, it would get stuck compiling and then emit thousands
of errors.

Also confirmed the fixture still works. (It doesn’t work correctly on
the first load after dev server starts, but that’s already the case on
main so seems unrelated.)
2023-03-30 22:05:03 +01:00
Sebastian Markbåge 1a1d61fed9 Warn for ARIA typos on custom elements (#26523)
Normally we allow any attribute/property on custom elements. However
it's a shared namespace. The `aria-` namespace applies to all generic
elements which are shared with custom elements. So arguably adding
custom extensions there is a really bad idea since it can conflict with
future additions.

It's possible there is a new standard one that's polyfilled by a custom
element but the same issue applies to React in general that we might
warn for very new additions so we just have to be quick on that.

cc @josepharhar
2023-03-30 16:31:15 -04:00
Mengdi Chen 5b8cf20b38 Add Circle CI API token to request header if available (#26519)
Follow up of #26499
A Circle CI team member got back to me. It is indeed not necessary, but
they had a regression not long ago on fetching without token.

https://discuss.circleci.com/t/is-api-token-required-when-fetching-artifacts/47606/5

To mitigate the impact of this kind of issues, let's add this token to
requests' header when it's available.
2023-03-30 16:06:56 -04:00
Lauren Tan d67b3cbdc0 [printer] Add missing terminal printer for do-while 2023-03-30 15:50:08 -04:00
Lauren Tan 89ea2d5f7c [be] Fix missing break and update no-fallthrough eslint rule
- Fixes a missing break in InferTypes - I disabled no-fallthrough previously 
because it would erroneously report that certain cases with non-builtin throws 
(eg `invariant`) would fall through. This brings the rule back but allows 
disabling it with a `// break omitted` comment, since it's still helpful in 
catching some actual missing breaks.
2023-03-30 15:50:07 -04:00
Mofei Zhang e43f91edc3 [env] Type inference for global object
- Add `DEFAULT_SHAPES` ShapeRegistry, which holds builtins and all 
`ObjectShapes` used in `DEFAULT_GLOBALS`. 

- Add a few typed objects / functions into `DEFAULT_GLOBALS` (used for tests) 

- Add type inference and `infer-global-object` test
2023-03-30 15:03:11 -04:00
Mofei Zhang 25388d3fda [be] Clean up null -> PolyType in ObjectShape
--- 

Question - should the unifier ignore `PolyType` for now? 

```js 

class Unifier { 

// ... 

bindVariableTo(v: TypeVar, type: Type) { 

if (type.kind === "Poly") { 

return; 

} 

// ... 

```
2023-03-30 15:03:11 -04:00
Mofei Zhang ffc1b5b700 [be] More comments for ObjectShapes; rename BuiltIn shapes 2023-03-30 15:03:10 -04:00
Mofei Zhang 44b2f504ea [rfc][env] Hook, object, and function types for Environment globals
Adds `GlobalRegistry`, which holds the names and types of known global objects, 
i.e. 

```js 

type GlobalRegistry = Map<string, PrimitiveType | ObjectType | FunctionType | 
HookType | PolyType>; 

// ... 

globalRegistry.get("NaN"); // {kind: "Primitive"} 

globalRegistry.get("parseInt"); // {kind: "Function", shapeId: "..."} 

globalRegistry.get("Math"); // {kind: "Object", shapeId: "..."} 

``` 

Since we currently do not track module imports and module-level declarations, 
builtin and custom hooks currently also live in GlobalRegistry. 

```js 

globalRegistry.get("useState"); // {kind: "Hook", definition: {...}} 

globalRegistry.get("useFreeze"); // {kind: Hook, definition: {...}} 

``` 

This PR does not allow Forget users to define their own globals. When we add 
this as a configuration, we should not expose `ShapeRegistry` to the user, as a 
user-provided ShapeRegistry may accidentally be not well formed. (i.e. missing 
(1) required shapes (BuiltInArray for [] and BuiltInObject for {}) or (2) some 
recursive shapeIds) 

```js 

export type UserType = UserObject | UserFunction | "Primitive" | "BuiltinObject" 
| ...; 

export type UserObject = { 

kind: "Object", 

properties: Map<string, UserType> 

} 

export type UserFunction = { 

kind: "Function", 

properties: Map<string, UserType>, 

signature: ... 

} 

export type UserGlobals = Map<string, UserType>; 

class Environment { 

constructor(globals: Map<string, UserType>, ...) { 

// ... 

addUserDefinedGlobals(this.#globals, this.#shapes); 

```
2023-03-30 15:03:10 -04:00
Mofei Zhang 45331ef21b [be][env] Move EnvironmentOptions -> EnvironmentConfig
--- 

Simplify Environment options by: 

- EnvironmentOptions -> EnvironmentConfig 

config is now directly passed around instead of being eagerly merged. 

- Moving merging / initialization logic into `Environment` constructor. From my 
understanding, there is no need to decouple merged options from an environment. 

This prepares Environment for the next PR, which adds non-stateful properties to 
Environment (i.e. a `GlobalRegistry`) that should be converted from config 
values (i.e. not directly exposed to the user due to potentially inconsistent 
inputs)
2023-03-30 15:03:09 -04:00
Mofei Zhang 8e37df6dab [be] Hook type inference should only happen at LoadGlobal
--- 

#1254 added inference for hooks loaded from globals. This is the only time we 
need to generate a type equation assigning `lval` to a resolved`Hook` type. 

@gsathya Would love to get your feedback here on the change. From my 
understanding, this change is technically incorrect, since the type equation we 
generate should be dependent on the `callee` type (i.e. `Hook` if callee is a 
hook, `Function` if callee is a function). 

Would the next step be to consolidate `Hook` and `Function` types? 

```js 

type Function { 

... 

isHook: boolean, // set by inference 

} 

type FunctionSignature { 

isHook: boolean, // set when adding to ShapeRegistry 

} 

```
2023-03-30 15:03:09 -04:00
Sebastian Markbåge 73deff0d51 Refactor DOMProperty and CSSProperty (#26513)
This is a step towards getting rid of the meta programming in
DOMProperty and CSSProperty.

This moves isAttributeNameSafe and isUnitlessNumber to a separate shared
modules.

isUnitlessNumber is now a single switch instead of meta-programming.
There is a slight behavior change here in that I hard code a specific
set of vendor-prefixed attributes instead of prefixing all the unitless
properties. I based this list on what getComputedStyle returns in
current browsers. I removed Opera prefixes because they were [removed in
Opera](https://dev.opera.com/blog/css-vendor-prefixes-in-opera-12-50-snapshots/)
itself. I included the ms ones mentioned [in the original
PR](https://github.com/facebook/react/commit/5abcce534382d85887f3d33475e8e54e3b5d8457).
These shouldn't really be used anymore anyway so should be pretty safe.
Worst case, they'll fallback to the other property if you specify both.

Finally I inline the mustUseProperty special cases - which are also the
only thing that uses propertyName. These are really all controlled
components and all booleans.

I'm making a small breaking change here by treating `checked` and
`selected` specially only on the `input` and `option` tags instead of
all tags. That's because those are the only DOM nodes that actually have
those properties but we used to set them as expandos instead of
attributes before. That's why one of the tests is updated to now use
`input` instead of testing an expando on a `div` which isn't a real use
case. Interestingly this also uncovered that we update checked twice for
some reason but keeping that logic for now.

Ideally `multiple` and `muted` should move into `select` and
`audio`/`video` respectively for the same reason.

No change to the attribute-behavior fixture.
2023-03-30 14:30:57 -04:00
Andrew Clark 2d51251e60 Clean up deferRenderPhaseUpdateToNextBatch (#26511)
This is a change to some undefined behavior that we though we would do
at one point but decided not to roll out. It's already disabled
everywhere, so this just deletes the branch from the implementation and
the tests.
2023-03-30 14:10:19 -04:00
Sathya Gunasekaran e81063e5ef [rfc] Desugar FunctionDeclaration to a FunctionExpression 2023-03-30 15:48:54 +01:00
Sathya Gunasekaran 05f48e2aac [hir] Refactor FunctionExpression lowering into separate function
This will allow us to reuse all the lowering for FunctionDeclaration.
2023-03-30 15:48:53 +01:00
Joseph Savona 0ffc7f632b Update useMemoCache test to confirm that cache persists across errors (#26510)
## Summary

Updates the `useMemoCache()` tests to validate that the memo cache
persists when a component does a setState during render or throws during
render. Forget's compilation output follows the general pattern used in
this test and is resilient to rendering running partway and then again
with different inputs.

## How did you test this change?

`yarn test` (this is a test-only change)
2023-03-30 07:47:22 -07:00
Sebastian Markbåge 29a3be78bd Move ReactDOMFloat to react-dom/src/ (#26514)
This is not really part of the bindings, it's more part of the package
entry points. /shared/ is not really right neither because it's more
like an isomorphic entry point and not some utility.
2023-03-29 23:39:24 -04:00
Sebastian Markbåge 4c2fc01900 Generate safe javascript url instead of throwing with disableJavaScriptURLs is on (#26507)
We currently throw an error when disableJavaScriptURLs is on and trigger
an error boundary. I kind of thought that's what would happen with CSP
or Trusted Types anyway. However, that's not what happens. Instead, in
those environments what happens is that the error is triggered when you
try to actually visit those links. So if you `preventDefault()` or
something it'll never show up and since the error just logs to the
console or to a violation logger, it's effectively a noop to users.

We can simulate the same without CSP by simply generating a different
`javascript:` url that throws instead of executing the potential attack
vector.

This still allows these to be used - at least as long as you
preventDefault before using them in practice. This might be legit for
forms. We still don't recommend using them for links-as-buttons since
it'll be possible to "Open in a New Tab" and other weird artifacts. For
links we still recommend the technique of assigning a button role etc.

It also is a little nicer when an attack actually happens because at
least it doesn't allow an attacker to trigger error boundaries and
effectively deny access to a page.
2023-03-29 23:39:02 -04:00
mofeiZ c2154b2785 [playground] Only collect first level of function declarations
#1433 means that Forget now will compile nested function declarations, so we no 
longer need to compile these separately
2023-03-29 17:14:58 -04:00
Andrew Clark f0aafa1a7e Convert a few more tests to waitFor test helpers (#26509)
Continuing my journey to migrate all the Scheduler flush* methods to
async versions of the same helpers.
2023-03-29 17:02:15 -04:00
Andrew Clark 90995ef8b0 Delete "triangle" resuming fuzz tester (#26508)
This deletes the ReactIncrementalTriangle test suite, which I originally
added back in 2017 when I was working on Fiber's "resuming" feature. It
was meant to simulate a similar scenario as Seb's "Sierpinski Triangle"
Fiber demo.

We eventually ended up removing resuming, but we kept this fuzz tester
around since it wasn't really harming anything. However, over the years,
we've had to make many small tweaks to decouple it from implementation
details, to the point that it doesn't test anything useful anymore. And
the thing that it originally tested has long since been removed.

If or when we do add back resuming, we would write a different fuzz
tester from scratch rather than build on this one.

So rather than continue to contrive ways to prevent it from breaking, I
propose we delete it.

We still have other fuzz testers for things like Suspense and context
propagation. Only this particular one has outlived its usefulness.
2023-03-29 16:48:02 -04:00
Sebastian Silbermann f118b7cebf [Flight] Gated test for dropped transport of undefined object values (#26478)
## Summary

With https://github.com/facebook/react/pull/26349 we now serialize
`undefined`. However, deserializing it on the client is currently
indistinguishable from the value missing entirely due to how
`JSON.parse` treats `undefined` return value of reviver functions.

This leads to inconsistent behavior of the `Object.hasOwn` or `in`
operator (used for narrowing in TypeScript). In TypeScript-speak, `{
prop: T | undefined}` will arrive as `{ prop?: T }`.

## How did you test this change?

- Added test that is expected to fail. Though ideally the implementation
of the component would not care whether it's used on the client or
server.
2023-03-29 18:27:55 +02:00
Sebastian Silbermann fd0511c728 [Flight] Add support BigInt support (#26479)
## Summary

Adds support for sending `BigInt` to Flight and Flight Reply

## How did you test this change?

- added tests
2023-03-29 18:23:43 +02:00
Sebastian Markbåge 85de6fde51 Refactor DOM special cases per tags including controlled fields (#26501)
I use a shared helper when setting properties into a helper whether it's
initial or update.

I moved the special cases per tag to commit phase so we can check it
only once. This also effectively inlines getHostProps which can be done
in a single check per prop key.

The diffProperties operation is simplified to mostly just generating a
plain diff of all properties, generating an update payload. This might
generate a few more entries that are now ignored in the commit phase.
that previously would've been ignored earlier. We could skip this and
just do the whole diff in the commit phase by always scheduling a commit
phase update.

I tested the attribute table (one change documented below) and a few
select DOM fixtures.
2023-03-28 22:40:03 -04:00
Mengdi Chen 5cbe6258bc Remove unnecessary CIRCLE_CI_API_TOKEN checks (#26499)
Token is not required for GET
2023-03-28 16:31:34 -04:00
Andrew Clark 1f5cdf8c77 Update Suspense fuzz tests to use act (#26498)
This updates the Suspense fuzz tester to use `act` to recursively flush
timers instead of doing it manually.

This still isn't great because ideally the fuzz tester wouldn't fake
timers at all. It should resolve promises using a custom queue instead
of Jest's fake timer queue, like we've started doing in our other
Suspense tests (i.e. the `resolveText` pattern). That's because our
internal `act` API (not the public one, the one we use in our tests)
uses Jest's fake timer queue as a way to force Suspense fallbacks to
appear.

However I'm not interested in upgrading this test suite to a better
strategy right now because if I were writing a Suspense fuzzer today I
would probably use an entirely different approach. So this is just an
incremental improvement to make it slightly less decoupled to React
implementation details.
2023-03-28 14:40:28 -04:00
Ricky f62cb39ee5 Make disableSchedulerTimeoutInWorkLoop a static ff (#26497)
## Overview

There's a known infinite loop with this but we're not running an
experiment any time soon.
2023-03-28 14:11:52 -04:00
Joe Savona 57bc5fd56e Support AssignmentPattern in params (param default values)
I already taught `lowerAssignment()` to handle assignment patterns for 
destructuring, we just have to call this helper for assignment pattern params 
too.
2023-03-28 09:52:55 -07:00
Sathya Gunasekaran 0999b6b815 [hir] Treat captured refs in throw or return terminals as mutations
In a lambda, a return/throw terminal could return a captured context ref needs 
to be treated as a mutation to correctly alias the returned  context ref and the 
lvalue.
2023-03-29 17:15:00 +01:00
Sathya Gunasekaran dd0476a1b5 [hir] Infer mutable ranges for terminals
Terminal operands are generally not mutating so this hasn't mattered so far. But 
in a lambda, a return terminal could return a captured context ref which needs 
to be treated as a mutation to correctly alias the returned context ref and the 
lvalue.
2023-03-29 15:48:55 +01:00
Mengdi ChenandRuslan Lesiutin f718199313 [DevTools] browser extension: improve script injection logic (#26492)
## Summary

- Drop extension support for Chrome / Edge <v102 since they have less
than 0.1% usage ([see data](https://caniuse.com/usage-table))
- Improve script injection logic when possible so that the scripts
injected by the extension are no longer shown in Network (which caused a
lot of confusion in the past)

## How did you test this change?

Built and tested locally, works as usual on Firefox.

For Chrome/Edge

**Before:**
Scripts shown in Network tab
<img width="1279" alt="Untitled 2"
src="https://user-images.githubusercontent.com/1001890/228074363-1d00d503-d4b5-4339-8dd6-fd0467e36e3e.png">

**After:**
No scripts shown
<img width="1329" alt="image"
src="https://user-images.githubusercontent.com/1001890/228074596-2084722b-bf3c-495e-a852-15f122233155.png">

---------

Co-authored-by: Ruslan Lesiutin <rdlesyutin@gmail.com>
2023-03-28 12:45:53 -04:00
Sathya Gunasekaran e0180ce86a [lambdas] Track ReactiveScopeDepenency of ComputedLoad
Fixes an issue where we did not track mutations to captured computed loads in 
lambdas.
2023-03-28 16:29:31 +01:00
Ricky 41b4714f19 Remove disableNativeComponentFrames (#26490)
## Overview

I'm landing this flag internally so we can delete this
2023-03-28 09:46:26 -04:00
Andrew Clark fc90eb6368 Codemod more tests to waitFor pattern (#26494) 2023-03-28 00:03:57 -04:00
Andrew Clark e0bbc26623 Improve tests that deal with microtasks (#26493)
I rewrote some of our tests that deal with microtasks with the aim of
making them less coupled to implementation details. This is related to
an upcoming change to move update processing into a microtask.
2023-03-27 23:17:55 -04:00
mofeiZ ec0abcd643 [hir] Strip JSXEmptyExpression syntax
`JSXEmptyExpression` is never added to a React element's children [in 
`react.buildChildren`](https://github.com/babel/babel/blob/main/packages/babel-types/src/builders/react/buildChildren.ts), 
which is [used 
by](https://github.com/babel/babel/blob/main/packages/babel-plugin-transform-react-jsx/src/create-plugin.ts#L649) 
`plugin-transform-react-jsx`]. 

An alternative would be to represent JSX expressions differently in HIR, then 
codegen `JSXEmptyExpression`s back when we encounter an `EmptyExpression` 

```js 

-   children: Array<Place>, 

-   children: Array<Place | "EmptyExpression">, 

``` 

(We could also retain `JSXEmptyExpression` as an `InstructionValue` that 
produces a Primitive. However, this would make babel types in Codegen a bit more 
messy, as `JSXEmptyExpression` does not extend `Expression` (which currently is 
the result of every `InstructionValue`).)
2023-03-27 18:12:18 -04:00
Andrew Clark 8faf751937 Codemod some expiration tests to waitForExpired (#26491)
Continuing my journey to migrate all the Scheduler flush* methods to
async versions of the same helpers.

`unstable_flushExpired` is a rarely used helper that is only meant to be
used to test a very particular implementation detail (update starvation
prevention, or what we sometimes refer to as "expiration").

I've prefixed the new helper with `unstable_`, too, to indicate that our
tests should almost always prefer one of the other patterns instead.
2023-03-27 15:52:25 -04:00
Joe Savona 43176b129e [be] Simplify BuildHIR w lowerValueToTemporary helper
Creates a new helper, `const temp: Place = lowerValueToTemporary(builder, 
value)` which creates a new temporary and an instruction to write that value to 
the temporary. We have this pattern all over BuildHIR, and the new helper makes 
this all a bit tidier.
2023-03-27 11:35:34 -07:00
Joe Savona 445e550e00 Support await expressions
Adds support for `await` expressions. We have primarily seen await used inside 
callbacks, not directly within component render logic, but because we construct 
HIR for lambdas it is helpful to be able to model await rather than require 
everyone to rewrite to use the Promise API. Note a subtlety: awaiting a promise 
is a mutative operation, so we a) model it as a Mutate effect and b) avoid DCE 
of await expressions since they may cause side effects. See the test cases for 
examples.
2023-03-27 10:41:49 -07:00
Joe Savona 4a826985db More tests for AssignmentPattern 2023-03-27 10:34:16 -07:00
Joe Savona 6d434cc777 Generalize helper for reorderable expressions
Adds a new helper method that we can use when processing expressions whose 
evaluation ordering may not be preserved. This was previously the case only for 
switch test case values, but we can use this for AssignmentPattern 
(destructuring default values) as well.
2023-03-27 10:34:11 -07:00
Joe Savona 80bdab7447 Support AssignmentPattern (default values in destructuring)
"Supports" default values in destructuring (AssignmentPattern) by lowering to a 
ternary, even in the output. Examples: 

```javascript 

// Input: 

const [x = 'default'] = y; 

// Output: 

const [t0] = y; 

const x = t0 === undefined ? 'default' : t0; 

``` 

```javascript 

// Input 2 

const [{x} = makeObject()] = y; 

// Output 2 

const [t0] = y; 

const {x} = t0 === undefined ? makeObject() : t0; 

``` 

Note that this is how Babel lowers AssignmentPattern, so it isn't too bad. This 
should help avoid the need to update product code, even if the output isn't 
perfectly ideal.
2023-03-27 10:34:11 -07:00
Joe Savona 61e97dc278 Support RegExp literals
New InstructionValue variant since RegExp literals are valid expressions.
2023-03-27 10:34:10 -07:00
Joe Savona 179b24b56e JSXNamespacedName support
This is kind of a hack, but i think it's worth it given that JSXNamespacedName 
is relatively uncommon. Adding a new InstructionValue variant to represent a 
namespaced name is one option, but then that isn't a valid expression and can't 
appear as an operand anywhere else. Instead, we lower namespaced names as a 
primitive (string) as `${namespace}:${name}` — exploiting the fact the namespace 
and name can't have a colon, and non-namespaced tagnames also can't have colons. 

It's a bit of a hack but it's contained to the JSX processing code. If folks 
have strong opinions on this i'm happy to change but this felt reasonable as a 
quick and reliable way to unblock support. 

NOTE: there is a larger question of what to do about compiling `fbt` tags. 
Before we can do anything with them, though, we need to parse them.
2023-03-27 10:34:09 -07:00