[repro] Repro for control flow bug in PropagateScopeDependency

--- 

Thanks to @josephsavona for finding this bug. This is another example of why we 
really want hir-everywhere. 

Forget output currently nullthrows because we believe `obj.a` is run 
unconditionally in source (missing the break/returns out of this scope)
This commit is contained in:
Mofei Zhang
2024-03-21 17:44:13 -04:00
parent 3a6a2e7e4a
commit e047db8d03
9 changed files with 357 additions and 4 deletions
@@ -0,0 +1,63 @@
## Input
```javascript
function useFoo({ obj, objIsNull }) {
const x = [];
b0: {
if (objIsNull) {
break b0;
}
x.push(obj.a);
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{ obj: null, objIsNull: true }],
sequentialRenders: [
{ obj: null, objIsNull: true },
{ obj: { a: 2 }, objIsNull: false },
],
};
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react";
function useFoo(t0) {
const $ = useMemoCache(3);
const { obj, objIsNull } = t0;
let x;
if ($[0] !== objIsNull || $[1] !== obj.a) {
x = [];
bb1: {
if (objIsNull) {
break bb1;
}
x.push(obj.a);
}
$[0] = objIsNull;
$[1] = obj.a;
$[2] = x;
} else {
x = $[2];
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{ obj: null, objIsNull: true }],
sequentialRenders: [
{ obj: null, objIsNull: true },
{ obj: { a: 2 }, objIsNull: false },
],
};
```
@@ -0,0 +1,19 @@
function useFoo({ obj, objIsNull }) {
const x = [];
b0: {
if (objIsNull) {
break b0;
}
x.push(obj.a);
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{ obj: null, objIsNull: true }],
sequentialRenders: [
{ obj: null, objIsNull: true },
{ obj: { a: 2 }, objIsNull: false },
],
};
@@ -0,0 +1,69 @@
## Input
```javascript
function useFoo({ obj, objIsNull }) {
const x = [];
if (objIsNull) {
return;
}
x.push(obj.b);
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{ obj: null, objIsNull: true }],
sequentialRenders: [
{ obj: null, objIsNull: true },
{ obj: { a: 2 }, objIsNull: false },
],
};
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react";
function useFoo(t0) {
const $ = useMemoCache(4);
const { obj, objIsNull } = t0;
let x;
let t1;
if ($[0] !== objIsNull || $[1] !== obj.b) {
t1 = Symbol.for("react.early_return_sentinel");
bb7: {
x = [];
if (objIsNull) {
t1 = undefined;
break bb7;
}
x.push(obj.b);
}
$[0] = objIsNull;
$[1] = obj.b;
$[2] = x;
$[3] = t1;
} else {
x = $[2];
t1 = $[3];
}
if (t1 !== Symbol.for("react.early_return_sentinel")) {
return t1;
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{ obj: null, objIsNull: true }],
sequentialRenders: [
{ obj: null, objIsNull: true },
{ obj: { a: 2 }, objIsNull: false },
],
};
```
@@ -0,0 +1,17 @@
function useFoo({ obj, objIsNull }) {
const x = [];
if (objIsNull) {
return;
}
x.push(obj.b);
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{ obj: null, objIsNull: true }],
sequentialRenders: [
{ obj: null, objIsNull: true },
{ obj: { a: 2 }, objIsNull: false },
],
};
@@ -0,0 +1,70 @@
## Input
```javascript
function useFoo({ obj, objIsNull }) {
const x = [];
b0: {
if (objIsNull) {
break b0;
} else {
x.push(obj.a);
}
x.push(obj.b);
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{ obj: null, objIsNull: true }],
sequentialRenders: [
{ obj: null, objIsNull: true },
{ obj: { a: 2 }, objIsNull: false },
],
};
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react";
function useFoo(t0) {
const $ = useMemoCache(3);
const { obj, objIsNull } = t0;
let x;
if ($[0] !== objIsNull || $[1] !== obj) {
x = [];
bb1: {
if (objIsNull) {
break bb1;
} else {
x.push(obj.a);
}
x.push(obj.b);
}
$[0] = objIsNull;
$[1] = obj;
$[2] = x;
} else {
x = $[2];
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{ obj: null, objIsNull: true }],
sequentialRenders: [
{ obj: null, objIsNull: true },
{ obj: { a: 2 }, objIsNull: false },
],
};
```
### Eval output
(kind: ok) []
[2,null]
@@ -0,0 +1,21 @@
function useFoo({ obj, objIsNull }) {
const x = [];
b0: {
if (objIsNull) {
break b0;
} else {
x.push(obj.a);
}
x.push(obj.b);
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{ obj: null, objIsNull: true }],
sequentialRenders: [
{ obj: null, objIsNull: true },
{ obj: { a: 2 }, objIsNull: false },
],
};
@@ -0,0 +1,76 @@
## Input
```javascript
function useFoo({ obj, objIsNull }) {
const x = [];
if (objIsNull) {
return;
} else {
x.push(obj.a);
}
x.push(obj.b);
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{ obj: null, objIsNull: true }],
sequentialRenders: [
{ obj: null, objIsNull: true },
{ obj: { a: 2 }, objIsNull: false },
],
};
```
## Code
```javascript
import { unstable_useMemoCache as useMemoCache } from "react";
function useFoo(t0) {
const $ = useMemoCache(4);
const { obj, objIsNull } = t0;
let x;
let t1;
if ($[0] !== objIsNull || $[1] !== obj) {
t1 = Symbol.for("react.early_return_sentinel");
bb8: {
x = [];
if (objIsNull) {
t1 = undefined;
break bb8;
} else {
x.push(obj.a);
}
x.push(obj.b);
}
$[0] = objIsNull;
$[1] = obj;
$[2] = x;
$[3] = t1;
} else {
x = $[2];
t1 = $[3];
}
if (t1 !== Symbol.for("react.early_return_sentinel")) {
return t1;
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{ obj: null, objIsNull: true }],
sequentialRenders: [
{ obj: null, objIsNull: true },
{ obj: { a: 2 }, objIsNull: false },
],
};
```
### Eval output
(kind: ok)
[2,null]
@@ -0,0 +1,19 @@
function useFoo({ obj, objIsNull }) {
const x = [];
if (objIsNull) {
return;
} else {
x.push(obj.a);
}
x.push(obj.b);
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{ obj: null, objIsNull: true }],
sequentialRenders: [
{ obj: null, objIsNull: true },
{ obj: { a: 2 }, objIsNull: false },
],
};
@@ -531,10 +531,9 @@ const skipFilter = new Set([
"rules-of-hooks/rules-of-hooks-93dc5d5e538a",
"rules-of-hooks/rules-of-hooks-69521d94fa03",
// bug
"bug-jsx-memberexpr-tag-in-lambda",
"bug-invalid-code-when-bailout",
"component-syntax-ref-gating.flow",
// bugs
"bug-reduce-reactive-deps-return-in-scope",
"bug-reduce-reactive-deps-break-in-scope",
// 'react-forget-runtime' not yet supported
"flag-enable-emit-hook-guards",