Compare commits

...

3 Commits

Author SHA1 Message Date
Mofei Zhang
90cf7bba08 [compiler][ez] Only fail gating hoisting check for referenced identifiers
Reduce false positive bailouts by using the same `isReferencedIdentifier` logic that the compiler also uses for determining context variables and a function's own hoisted declarations.

Details:
Previously, we counted every babel identifier as a reference. This is
problematic because babel counts most string symbols as an identifier.

```js
print(x);  // x is an identifier as expected
obj.x      // x is.. also an identifier here
{x: 2}     // x is also an identifier here
```

This PR adds a check for `isReferencedIdentifier`. Note that only non-lval
references pass this check. This should be fine as we don't need to hoist function declarations before writes to the same lvalue (which should error in strict mode anyways)
```js
print(x);  // isReferencedIdentifier(x) -> true
obj.x      // isReferencedIdentifier(x) -> false
{x: 2}     // isReferencedIdentifier(x) -> false
x = 2      // isReferencedIdentifier(x) -> false
```
2025-03-13 11:52:25 -04:00
Mofei Zhang
c19f052b2d [compiler][ez] Move compiler gating tests
Move all gating tests to `gating/`
2025-03-13 11:52:25 -04:00
Mofei Zhang
d2d5350e65 [compiler][optim] more shapes for mixedreadonly
- Add `at`, `indexOf`, and `includes`
- Optimize MixedReadOnly which is currently only used by hook return values. Hook return values are typed as Frozen, this change propagates that to return values of aliasing function calls (such as `at`). One potential issue is that  developers may pass `enableAssumeHooksFollowRulesOfReact:false` and set `transitiveMixedData`, expecting their transitive mixed data to be mutable. This is a bit of an edge case and already doesn't have clear semantics.
2025-03-13 11:52:25 -04:00
48 changed files with 539 additions and 173 deletions

View File

@@ -1143,7 +1143,7 @@ function checkFunctionReferencedBeforeDeclarationAtTopLevel(
* A null scope means there's no function scope, which means we're at the
* top level scope.
*/
if (scope === null) {
if (scope === null && id.isReferencedIdentifier()) {
errors.pushErrorDetail(
new CompilerErrorDetail({
reason: `Encountered a function used before its declaration, which breaks Forget's gating codegen due to hoisting`,

View File

@@ -663,7 +663,7 @@ const testComplexConfigDefaults: PartialEnvironmentConfig = {
source: 'react-compiler-runtime',
importSpecifierName: 'shouldInstrument',
},
globalGating: '__DEV__',
globalGating: 'DEV',
},
enableEmitHookGuards: {
source: 'react-compiler-runtime',

View File

@@ -535,6 +535,30 @@ addObject(BUILTIN_SHAPES, BuiltInRefValueId, [
['*', {kind: 'Object', shapeId: BuiltInRefValueId}],
]);
/**
* MixedReadOnly =
* | primitive
* | simple objects (Record<string, MixedReadOnly>)
* | Array<MixedReadOnly>
*
* APIs such as Relay — but also Flux and other data stores — often return a
* union of types with some interesting properties in terms of analysis.
*
* Given this constraint, if data came from Relay, then we should be able to
* infer things like `data.items.map(): Array`. That may seem like a leap at
* first but remember, we assume you're not patching builtins. Thus the only way
* data.items.map can exist and be a function, given the above set of data types
* and builtin JS methods, is if `data.items` was an Array, and `data.items.map`
* is therefore calling Array.prototype.map. Then we know that function returns
* an Array as well. This relies on the fact that map() is being called, so if
* data.items was some other type it would error at runtime - so it's sound.
*
* Note that this shape is currently only used for hook return values, which
* means that it's safe to type aliasing method-call return kinds as `Frozen`.
*
* Also note that all newly created arrays from method-calls (e.g. `.map`)
* have the appropriate mutable `BuiltInArray` shape
*/
addObject(BUILTIN_SHAPES, BuiltInMixedReadonlyId, [
[
'toString',
@@ -546,6 +570,36 @@ addObject(BUILTIN_SHAPES, BuiltInMixedReadonlyId, [
returnValueKind: ValueKind.Primitive,
}),
],
[
'indexOf',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Read,
returnType: {kind: 'Primitive'},
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Primitive,
}),
],
[
'includes',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Read,
returnType: {kind: 'Primitive'},
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Primitive,
}),
],
[
'at',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [Effect.Read],
restParam: null,
returnType: {kind: 'Object', shapeId: BuiltInMixedReadonlyId},
calleeEffect: Effect.Capture,
returnValueKind: ValueKind.Frozen,
}),
],
[
'map',
addFunction(BUILTIN_SHAPES, [], {
@@ -642,9 +696,9 @@ addObject(BUILTIN_SHAPES, BuiltInMixedReadonlyId, [
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: {kind: 'Poly'},
returnType: {kind: 'Object', shapeId: BuiltInMixedReadonlyId},
calleeEffect: Effect.ConditionallyMutate,
returnValueKind: ValueKind.Mutable,
returnValueKind: ValueKind.Frozen,
noAlias: true,
mutableOnlyIfOperandsAreMutable: true,
}),

View File

@@ -1,35 +0,0 @@
## Input
```javascript
// @gating
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
export default ErrorView;
```
## Code
```javascript
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
import { c as _c } from "react/compiler-runtime"; // @gating
const ErrorView = isForgetEnabled_Fixtures()
? (error, _retry) => {
const $ = _c(2);
let t0;
if ($[0] !== error) {
t0 = <MessageBox error={error} />;
$[0] = error;
$[1] = t0;
} else {
t0 = $[1];
}
return t0;
}
: (error, _retry) => <MessageBox error={error}></MessageBox>;
export default ErrorView;
```

View File

@@ -1,4 +0,0 @@
// @gating
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
export default ErrorView;

View File

@@ -21,7 +21,7 @@ import {
import { c as _c } from "react/compiler-runtime"; // @enableEmitFreeze @enableEmitInstrumentForget
function useFoo(props) {
if (__DEV__ && shouldInstrument)
if (DEV && shouldInstrument)
useRenderCounter("useFoo", "/codegen-emit-imports-same-source.ts");
const $ = _c(2);
let t0;

View File

@@ -28,7 +28,7 @@ import { c as _c } from "react/compiler-runtime"; // @enableEmitInstrumentForget
function Bar(props) {
"use forget";
if (__DEV__ && shouldInstrument)
if (DEV && shouldInstrument)
useRenderCounter("Bar", "/codegen-instrument-forget-test.ts");
const $ = _c(2);
let t0;
@@ -48,7 +48,7 @@ function NoForget(props) {
function Foo(props) {
"use forget";
if (__DEV__ && shouldInstrument)
if (DEV && shouldInstrument)
useRenderCounter("Foo", "/codegen-instrument-forget-test.ts");
const $ = _c(2);
let t0;

View File

@@ -1,14 +0,0 @@
// @gating @compilationMode(annotation)
export default function Bar(props) {
'use forget';
return <div>{props.bar}</div>;
}
function NoForget(props) {
return <Bar>{props.noForget}</Bar>;
}
export function Foo(props) {
'use forget';
return <Foo>{props.bar}</Foo>;
}

View File

@@ -0,0 +1,50 @@
## Input
```javascript
// @gating
import {Stringify} from 'shared-runtime';
const ErrorView = ({error, _retry}) => <Stringify error={error}></Stringify>;
export default ErrorView;
export const FIXTURE_ENTRYPOINT = {
fn: eval('ErrorView'),
params: [{}],
};
```
## Code
```javascript
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
import { c as _c } from "react/compiler-runtime"; // @gating
import { Stringify } from "shared-runtime";
const ErrorView = isForgetEnabled_Fixtures()
? (t0) => {
const $ = _c(2);
const { error } = t0;
let t1;
if ($[0] !== error) {
t1 = <Stringify error={error} />;
$[0] = error;
$[1] = t1;
} else {
t1 = $[1];
}
return t1;
}
: ({ error, _retry }) => <Stringify error={error}></Stringify>;
export default ErrorView;
export const FIXTURE_ENTRYPOINT = {
fn: eval("ErrorView"),
params: [{}],
};
```
### Eval output
(kind: ok) <div>{}</div>

View File

@@ -0,0 +1,10 @@
// @gating
import {Stringify} from 'shared-runtime';
const ErrorView = ({error, _retry}) => <Stringify error={error}></Stringify>;
export default ErrorView;
export const FIXTURE_ENTRYPOINT = {
fn: eval('ErrorView'),
params: [{}],
};

View File

@@ -15,9 +15,22 @@ function NoForget(props) {
function Foo(props) {
'use forget';
return <Foo>{props.bar}</Foo>;
if (props.bar < 0) {
return props.children;
}
return (
<Foo bar={props.bar - 1}>
<NoForget />
</Foo>
);
}
global.DEV = true;
export const FIXTURE_ENTRYPOINT = {
fn: eval('Foo'),
params: [{bar: 2}],
};
```
## Code
@@ -29,7 +42,7 @@ import { c as _c } from "react/compiler-runtime"; // @enableEmitInstrumentForget
const Bar = isForgetEnabled_Fixtures()
? function Bar(props) {
"use forget";
if (__DEV__ && shouldInstrument)
if (DEV && shouldInstrument)
useRenderCounter("Bar", "/codegen-instrument-forget-gating-test.ts");
const $ = _c(2);
let t0;
@@ -53,23 +66,50 @@ function NoForget(props) {
const Foo = isForgetEnabled_Fixtures()
? function Foo(props) {
"use forget";
if (__DEV__ && shouldInstrument)
if (DEV && shouldInstrument)
useRenderCounter("Foo", "/codegen-instrument-forget-gating-test.ts");
const $ = _c(2);
let t0;
if ($[0] !== props.bar) {
t0 = <Foo>{props.bar}</Foo>;
$[0] = props.bar;
$[1] = t0;
} else {
t0 = $[1];
const $ = _c(3);
if (props.bar < 0) {
return props.children;
}
return t0;
const t0 = props.bar - 1;
let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <NoForget />;
$[0] = t1;
} else {
t1 = $[0];
}
let t2;
if ($[1] !== t0) {
t2 = <Foo bar={t0}>{t1}</Foo>;
$[1] = t0;
$[2] = t2;
} else {
t2 = $[2];
}
return t2;
}
: function Foo(props) {
"use forget";
return <Foo>{props.bar}</Foo>;
if (props.bar < 0) {
return props.children;
}
return (
<Foo bar={props.bar - 1}>
<NoForget />
</Foo>
);
};
global.DEV = true;
export const FIXTURE_ENTRYPOINT = {
fn: eval("Foo"),
params: [{ bar: 2 }],
};
```
### Eval output
(kind: ok) <div></div>

View File

@@ -11,5 +11,18 @@ function NoForget(props) {
function Foo(props) {
'use forget';
return <Foo>{props.bar}</Foo>;
if (props.bar < 0) {
return props.children;
}
return (
<Foo bar={props.bar - 1}>
<NoForget />
</Foo>
);
}
global.DEV = true;
export const FIXTURE_ENTRYPOINT = {
fn: eval('Foo'),
params: [{bar: 2}],
};

View File

@@ -0,0 +1,60 @@
## Input
```javascript
// @gating
import {identity, useHook as useRenamed} from 'shared-runtime';
const _ = {
useHook: () => {},
};
identity(_.useHook);
function useHook() {
useRenamed();
return <div>hello world!</div>;
}
export const FIXTURE_ENTRYPOINT = {
fn: useHook,
params: [{}],
};
```
## Code
```javascript
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
import { c as _c } from "react/compiler-runtime"; // @gating
import { identity, useHook as useRenamed } from "shared-runtime";
const _ = {
useHook: isForgetEnabled_Fixtures() ? () => {} : () => {},
};
identity(_.useHook);
const useHook = isForgetEnabled_Fixtures()
? function useHook() {
const $ = _c(1);
useRenamed();
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = <div>hello world!</div>;
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}
: function useHook() {
useRenamed();
return <div>hello world!</div>;
};
export const FIXTURE_ENTRYPOINT = {
fn: useHook,
params: [{}],
};
```
### Eval output
(kind: ok) <div>hello world!</div>

View File

@@ -0,0 +1,16 @@
// @gating
import {identity, useHook as useRenamed} from 'shared-runtime';
const _ = {
useHook: () => {},
};
identity(_.useHook);
function useHook() {
useRenamed();
return <div>hello world!</div>;
}
export const FIXTURE_ENTRYPOINT = {
fn: useHook,
params: [{}],
};

View File

@@ -17,6 +17,11 @@ function Foo(props) {
return <Foo>{props.bar}</Foo>;
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};
```
## Code
@@ -66,5 +71,12 @@ const Foo = isForgetEnabled_Fixtures()
return <Foo>{props.bar}</Foo>;
};
export const FIXTURE_ENTRYPOINT = {
fn: eval("Bar"),
params: [{ bar: 2 }],
};
```
### Eval output
(kind: ok) <div>2</div>

View File

@@ -12,3 +12,8 @@ function Foo(props) {
'use forget';
return <Foo>{props.bar}</Foo>;
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};

View File

@@ -12,11 +12,23 @@ function NoForget(props) {
return <Bar>{props.noForget}</Bar>;
}
export function Foo(props) {
function Foo(props) {
'use forget';
return <Foo>{props.bar}</Foo>;
if (props.bar < 0) {
return props.children;
}
return (
<Foo bar={props.bar - 1}>
<NoForget />
</Foo>
);
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};
```
## Code
@@ -47,25 +59,50 @@ export default Bar;
function NoForget(props) {
return <Bar>{props.noForget}</Bar>;
}
export const Foo = isForgetEnabled_Fixtures()
const Foo = isForgetEnabled_Fixtures()
? function Foo(props) {
"use forget";
const $ = _c(2);
let t0;
if ($[0] !== props.bar) {
t0 = <Foo>{props.bar}</Foo>;
$[0] = props.bar;
$[1] = t0;
} else {
t0 = $[1];
const $ = _c(3);
if (props.bar < 0) {
return props.children;
}
return t0;
const t0 = props.bar - 1;
let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <NoForget />;
$[0] = t1;
} else {
t1 = $[0];
}
let t2;
if ($[1] !== t0) {
t2 = <Foo bar={t0}>{t1}</Foo>;
$[1] = t0;
$[2] = t2;
} else {
t2 = $[2];
}
return t2;
}
: function Foo(props) {
"use forget";
return <Foo>{props.bar}</Foo>;
if (props.bar < 0) {
return props.children;
}
return (
<Foo bar={props.bar - 1}>
<NoForget />
</Foo>
);
};
export const FIXTURE_ENTRYPOINT = {
fn: eval("Bar"),
params: [{ bar: 2 }],
};
```
### Eval output
(kind: ok) <div>2</div>

View File

@@ -0,0 +1,26 @@
// @gating @compilationMode(annotation)
export default function Bar(props) {
'use forget';
return <div>{props.bar}</div>;
}
function NoForget(props) {
return <Bar>{props.noForget}</Bar>;
}
function Foo(props) {
'use forget';
if (props.bar < 0) {
return props.children;
}
return (
<Foo bar={props.bar - 1}>
<NoForget />
</Foo>
);
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};

View File

@@ -17,6 +17,11 @@ export function Foo(props) {
return <Foo>{props.bar}</Foo>;
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};
```
## Code
@@ -66,5 +71,12 @@ export const Foo = isForgetEnabled_Fixtures()
return <Foo>{props.bar}</Foo>;
};
export const FIXTURE_ENTRYPOINT = {
fn: eval("Bar"),
params: [{ bar: 2 }],
};
```
### Eval output
(kind: ok) <div>2</div>

View File

@@ -12,3 +12,8 @@ export function Foo(props) {
'use forget';
return <Foo>{props.bar}</Foo>;
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};

View File

@@ -17,6 +17,11 @@ function Foo(props) {
return <Foo>{props.bar}</Foo>;
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};
```
## Code
@@ -65,5 +70,12 @@ const Foo = isForgetEnabled_Fixtures()
return <Foo>{props.bar}</Foo>;
};
export const FIXTURE_ENTRYPOINT = {
fn: eval("Bar"),
params: [{ bar: 2 }],
};
```
### Eval output
(kind: ok) <div>2</div>

View File

@@ -12,3 +12,8 @@ function Foo(props) {
'use forget';
return <Foo>{props.bar}</Foo>;
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};

View File

@@ -13,6 +13,11 @@ component Component(value: string) {
export default memo<Props>(Component);
export const FIXTURE_ENTRYPOINT = {
fn: eval('Component'),
params: [{value: 'foo'}],
};
```
## Code
@@ -43,5 +48,12 @@ const Component = isForgetEnabled_Fixtures()
export default memo<Props>(Component);
export const FIXTURE_ENTRYPOINT = {
fn: eval("Component"),
params: [{ value: "foo" }],
};
```
### Eval output
(kind: ok) <div>foo</div>

View File

@@ -8,3 +8,8 @@ component Component(value: string) {
}
export default memo<Props>(Component);
export const FIXTURE_ENTRYPOINT = {
fn: eval('Component'),
params: [{value: 'foo'}],
};

View File

@@ -35,4 +35,7 @@ export default React.forwardRef(
);
```
### Eval output
(kind: exception) Fixture not implemented
logs: ['forwardRef render functions accept exactly two parameters: props and ref. %s','Did you forget to use the ref parameter?']

View File

@@ -3,17 +3,17 @@
```javascript
// @gating
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
import {Stringify} from 'shared-runtime';
const Renderer = props => (
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
export default props => (
<Foo>
<Bar></Bar>
<ErrorView></ErrorView>
</Foo>
);
export default Renderer;
```
## Code
@@ -21,12 +21,14 @@ export default Renderer;
```javascript
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
import { c as _c } from "react/compiler-runtime"; // @gating
import { Stringify } from "shared-runtime";
const ErrorView = isForgetEnabled_Fixtures()
? (error, _retry) => {
const $ = _c(2);
let t0;
if ($[0] !== error) {
t0 = <MessageBox error={error} />;
t0 = <Stringify error={error} />;
$[0] = error;
$[1] = t0;
} else {
@@ -34,9 +36,9 @@ const ErrorView = isForgetEnabled_Fixtures()
}
return t0;
}
: (error, _retry) => <MessageBox error={error}></MessageBox>;
: (error, _retry) => <Stringify error={error}></Stringify>;
const Renderer = isForgetEnabled_Fixtures()
export default isForgetEnabled_Fixtures()
? (props) => {
const $ = _c(1);
let t0;
@@ -59,7 +61,8 @@ const Renderer = isForgetEnabled_Fixtures()
<ErrorView></ErrorView>
</Foo>
);
export default Renderer;
```
### Eval output
(kind: exception) Fixture not implemented

View File

@@ -0,0 +1,11 @@
// @gating
import {Stringify} from 'shared-runtime';
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
export default props => (
<Foo>
<Bar></Bar>
<ErrorView></ErrorView>
</Foo>
);

View File

@@ -3,15 +3,22 @@
```javascript
// @gating
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
import {Stringify} from 'shared-runtime';
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
export const Renderer = props => (
<Foo>
<Bar></Bar>
<div>
<span></span>
<ErrorView></ErrorView>
</Foo>
</div>
);
export const FIXTURE_ENTRYPOINT = {
fn: eval('Renderer'),
params: [{}],
};
```
## Code
@@ -19,12 +26,14 @@ export const Renderer = props => (
```javascript
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
import { c as _c } from "react/compiler-runtime"; // @gating
import { Stringify } from "shared-runtime";
const ErrorView = isForgetEnabled_Fixtures()
? (error, _retry) => {
const $ = _c(2);
let t0;
if ($[0] !== error) {
t0 = <MessageBox error={error} />;
t0 = <Stringify error={error} />;
$[0] = error;
$[1] = t0;
} else {
@@ -32,7 +41,7 @@ const ErrorView = isForgetEnabled_Fixtures()
}
return t0;
}
: (error, _retry) => <MessageBox error={error}></MessageBox>;
: (error, _retry) => <Stringify error={error}></Stringify>;
export const Renderer = isForgetEnabled_Fixtures()
? (props) => {
@@ -40,10 +49,10 @@ export const Renderer = isForgetEnabled_Fixtures()
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = (
<Foo>
<Bar />
<div>
<span />
<ErrorView />
</Foo>
</div>
);
$[0] = t0;
} else {
@@ -52,11 +61,17 @@ export const Renderer = isForgetEnabled_Fixtures()
return t0;
}
: (props) => (
<Foo>
<Bar></Bar>
<div>
<span></span>
<ErrorView></ErrorView>
</Foo>
</div>
);
export const FIXTURE_ENTRYPOINT = {
fn: eval("Renderer"),
params: [{}],
};
```
### Eval output
(kind: ok) <div><span></span><div>{"error":{}}</div></div>

View File

@@ -0,0 +1,16 @@
// @gating
import {Stringify} from 'shared-runtime';
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
export const Renderer = props => (
<div>
<span></span>
<ErrorView></ErrorView>
</div>
);
export const FIXTURE_ENTRYPOINT = {
fn: eval('Renderer'),
params: [{}],
};

View File

@@ -3,15 +3,24 @@
```javascript
// @gating
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
import {Stringify} from 'shared-runtime';
export default Renderer = props => (
<Foo>
<Bar></Bar>
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
const Renderer = props => (
<div>
<span></span>
<ErrorView></ErrorView>
</Foo>
</div>
);
export default Renderer;
export const FIXTURE_ENTRYPOINT = {
fn: eval('Renderer'),
params: [{}],
};
```
## Code
@@ -19,12 +28,14 @@ export default Renderer = props => (
```javascript
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
import { c as _c } from "react/compiler-runtime"; // @gating
import { Stringify } from "shared-runtime";
const ErrorView = isForgetEnabled_Fixtures()
? (error, _retry) => {
const $ = _c(2);
let t0;
if ($[0] !== error) {
t0 = <MessageBox error={error} />;
t0 = <Stringify error={error} />;
$[0] = error;
$[1] = t0;
} else {
@@ -32,18 +43,18 @@ const ErrorView = isForgetEnabled_Fixtures()
}
return t0;
}
: (error, _retry) => <MessageBox error={error}></MessageBox>;
: (error, _retry) => <Stringify error={error}></Stringify>;
export default Renderer = isForgetEnabled_Fixtures()
const Renderer = isForgetEnabled_Fixtures()
? (props) => {
const $ = _c(1);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = (
<Foo>
<Bar />
<div>
<span />
<ErrorView />
</Foo>
</div>
);
$[0] = t0;
} else {
@@ -52,11 +63,19 @@ export default Renderer = isForgetEnabled_Fixtures()
return t0;
}
: (props) => (
<Foo>
<Bar></Bar>
<div>
<span></span>
<ErrorView></ErrorView>
</Foo>
</div>
);
export default Renderer;
export const FIXTURE_ENTRYPOINT = {
fn: eval("Renderer"),
params: [{}],
};
```
### Eval output
(kind: ok) <div><span></span><div>{"error":{}}</div></div>

View File

@@ -0,0 +1,18 @@
// @gating
import {Stringify} from 'shared-runtime';
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
const Renderer = props => (
<div>
<span></span>
<ErrorView></ErrorView>
</div>
);
export default Renderer;
export const FIXTURE_ENTRYPOINT = {
fn: eval('Renderer'),
params: [{}],
};

View File

@@ -1,9 +0,0 @@
// @gating
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
export default Renderer = props => (
<Foo>
<Bar></Bar>
<ErrorView></ErrorView>
</Foo>
);

View File

@@ -1,9 +0,0 @@
// @gating
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
export const Renderer = props => (
<Foo>
<Bar></Bar>
<ErrorView></ErrorView>
</Foo>
);

View File

@@ -1,11 +0,0 @@
// @gating
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
const Renderer = props => (
<Foo>
<Bar></Bar>
<ErrorView></ErrorView>
</Foo>
);
export default Renderer;

View File

@@ -222,7 +222,6 @@ const skipFilter = new Set([
'array-at-mutate-after-capture',
'array-join',
'array-push-effect',
'arrow-function-expr-gating-test',
'assignment-in-nested-if',
'await-side-effecting-promise',
'await',
@@ -335,16 +334,10 @@ const skipFilter = new Set([
'babel-existing-react-import',
'babel-existing-react-kitchensink-import',
'call',
'codegen-instrument-forget-gating-test',
'codegen-instrument-forget-test',
'conditional-on-mutable',
'constructor',
'frozen-after-alias',
'gating-test-export-default-function',
'gating-test-export-function-and-default',
'gating-test-export-function',
'gating-test',
'gating-with-hoisted-type-reference.flow',
'hook-call',
'hooks-freeze-arguments',
'hooks-freeze-possibly-mutable-arguments',
@@ -352,8 +345,6 @@ const skipFilter = new Set([
'independent',
'interdependent-across-if',
'interdependent',
'multi-arrow-expr-export-gating-test',
'multi-arrow-expr-gating-test',
'mutable-liverange-loop',
'sequence-expression',
'ssa-call-jsx-2',
@@ -361,7 +352,6 @@ const skipFilter = new Set([
'ssa-newexpression',
'ssa-shadowing',
'template-literal',
'multi-arrow-expr-export-default-gating-test',
// works, but appears differently when printing
// due to optional function argument
@@ -407,7 +397,6 @@ const skipFilter = new Set([
'infer-functions-hook-with-hook-call',
'infer-functions-hook-with-jsx',
'infer-function-expression-component',
'infer-function-expression-React-memo-gating',
'infer-skip-components-without-hooks-or-jsx',
'class-component-with-render-helper',
'fbt/fbtparam-with-jsx-element-content',
@@ -422,7 +411,7 @@ const skipFilter = new Set([
'transitive-freeze-function-expressions',
// nothing to compile/run
'repro-no-gating-import-without-compiled-functions',
'gating/repro-no-gating-import-without-compiled-functions',
// TODOs
'rules-of-hooks/todo.bail.rules-of-hooks-279ac76f53af',