[compiler][fixtures] Bug repros: codegen, alignScope, phis

[ghstack-poisoned]
This commit is contained in:
Mofei Zhang
2024-06-12 15:51:01 -04:00
parent 55c9d45f3b
commit 2827cbc594
9 changed files with 401 additions and 0 deletions
@@ -0,0 +1,92 @@
## Input
```javascript
import { makeArray, print } from "shared-runtime";
/**
* Exposes bug involving iife inlining + codegen.
* We currently inline iifes to labeled blocks (not value-blocks).
*
* Here, print(1) and the evaluation of makeArray(...) get the same scope
* as the compiler infers that the makeArray call may mutate its arguments.
* Since print(1) does not get its own scope (and is thus not a declaration
* or dependency), it does not get promoted.
* As a result, print(1) gets reordered across the labeled-block instructions
* to be inlined at the makeArray callsite.
*
* Current evaluator results:
* Found differences in evaluator results
* Non-forget (expected):
* (kind: ok) [null,2]
* logs: [1,2]
* Forget:
* (kind: ok) [null,2]
* logs: [2,1]
*/
function useTest() {
return makeArray<number | void>(
print(1),
(function foo() {
print(2);
return 2;
})()
);
}
export const FIXTURE_ENTRYPOINT = {
fn: useTest,
params: [],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
import { makeArray, print } from "shared-runtime";
/**
* Exposes bug involving iife inlining + codegen.
* We currently inline iifes to labeled blocks (not value-blocks).
*
* Here, print(1) and the evaluation of makeArray(...) get the same scope
* as the compiler infers that the makeArray call may mutate its arguments.
* Since print(1) does not get its own scope (and is thus not a declaration
* or dependency), it does not get promoted.
* As a result, print(1) gets reordered across the labeled-block instructions
* to be inlined at the makeArray callsite.
*
* Current evaluator results:
* Found differences in evaluator results
* Non-forget (expected):
* (kind: ok) [null,2]
* logs: [1,2]
* Forget:
* (kind: ok) [null,2]
* logs: [2,1]
*/
function useTest() {
const $ = _c(1);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
let t1;
print(2);
t1 = 2;
t0 = makeArray(print(1), t1);
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}
export const FIXTURE_ENTRYPOINT = {
fn: useTest,
params: [],
};
```
@@ -0,0 +1,36 @@
import { makeArray, print } from "shared-runtime";
/**
* Exposes bug involving iife inlining + codegen.
* We currently inline iifes to labeled blocks (not value-blocks).
*
* Here, print(1) and the evaluation of makeArray(...) get the same scope
* as the compiler infers that the makeArray call may mutate its arguments.
* Since print(1) does not get its own scope (and is thus not a declaration
* or dependency), it does not get promoted.
* As a result, print(1) gets reordered across the labeled-block instructions
* to be inlined at the makeArray callsite.
*
* Current evaluator results:
* Found differences in evaluator results
* Non-forget (expected):
* (kind: ok) [null,2]
* logs: [1,2]
* Forget:
* (kind: ok) [null,2]
* logs: [2,1]
*/
function useTest() {
return makeArray<number | void>(
print(1),
(function foo() {
print(2);
return 2;
})()
);
}
export const FIXTURE_ENTRYPOINT = {
fn: useTest,
params: [],
};
@@ -0,0 +1,78 @@
## Input
```javascript
import { arrayPush } from "shared-runtime";
/**
* Evaluator error:
* Found differences in evaluator results
* Non-forget (expected):
* (kind: ok) [2]
* [2]
* Forget:
* (kind: ok) [2]
* [2,2]
*/
function Foo(cond) {
let x = null;
if (cond) {
x = [];
} else {
}
// Here, x = phi(x$null, x$[]) does not receive the correct ValueKind
arrayPush(x, 2);
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: Foo,
params: [{ cond: true }],
sequentialRenders: [{ cond: true }, { cond: true }],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
import { arrayPush } from "shared-runtime";
/**
* Evaluator error:
* Found differences in evaluator results
* Non-forget (expected):
* (kind: ok) [2]
* [2]
* Forget:
* (kind: ok) [2]
* [2,2]
*/
function Foo(cond) {
const $ = _c(1);
let x = null;
if (cond) {
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = [];
$[0] = t0;
} else {
t0 = $[0];
}
x = t0;
}
arrayPush(x, 2);
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: Foo,
params: [{ cond: true }],
sequentialRenders: [{ cond: true }, { cond: true }],
};
```
@@ -0,0 +1,29 @@
import { arrayPush } from "shared-runtime";
/**
* Evaluator error:
* Found differences in evaluator results
* Non-forget (expected):
* (kind: ok) [2]
* [2]
* Forget:
* (kind: ok) [2]
* [2,2]
*/
function Foo(cond) {
let x = null;
if (cond) {
x = [];
} else {
}
// Here, x = phi(x$null, x$[]) does not receive the correct ValueKind
arrayPush(x, 2);
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: Foo,
params: [{ cond: true }],
sequentialRenders: [{ cond: true }, { cond: true }],
};
@@ -0,0 +1,29 @@
## Input
```javascript
/**
* Similar fixture to `error.todo-align-scopes-nested-block-structure`, but
* a simpler case.
*/
function useFoo(cond) {
let s = null;
if (cond) {
s = {};
} else {
return null;
}
mutate(s);
return s;
}
```
## Error
```
Invariant: Invalid nesting in program blocks or scopes. Items overlap but are not nested: 4:10(5:13)
```
@@ -0,0 +1,14 @@
/**
* Similar fixture to `error.todo-align-scopes-nested-block-structure`, but
* a simpler case.
*/
function useFoo(cond) {
let s = null;
if (cond) {
s = {};
} else {
return null;
}
mutate(s);
return s;
}
@@ -0,0 +1,68 @@
## Input
```javascript
/**
* Fixture showing that it's not sufficient to only align direct scoped
* accesses of a block-fallthrough pair.
* Below is a simplified view of HIR blocks in this fixture.
* Note that here, s is mutated in both bb1 and bb4. However, neither
* bb1 nor bb4 have terminal fallthroughs or are fallthroughs themselves.
*
* This means that we need to recursively visit all scopes accessed between
* a block and its fallthrough and extend the range of those scopes which overlap
* with an active block/fallthrough pair,
*
* bb0
* ┌──────────────┐
* │let s = null │
* │test cond1 │
* │ <fallthr=bb3>│
* └┬─────────────┘
* │ bb1
* ├─►┌───────┐
* │ │s = {} ├────┐
* │ └───────┘ │
* │ bb2 │
* └─►┌───────┐ │
* │return;│ │
* └───────┘ │
* bb3 │
* ┌──────────────┐◄┘
* │test cond2 │
* │ <fallthr=bb5>│
* └┬─────────────┘
* │ bb4
* ├─►┌─────────┐
* │ │mutate(s)├─┐
* ▼ └─────────┘ │
* bb5 │
* ┌───────────┐ │
* │return s; │◄──┘
* └───────────┘
*/
function useFoo(cond1, cond2) {
let s = null;
if (cond1) {
s = {};
} else {
return null;
}
if (cond2) {
mutate(s);
}
return s;
}
```
## Error
```
Invariant: Invalid nesting in program blocks or scopes. Items overlap but are not nested: 4:10(5:15)
```
@@ -0,0 +1,53 @@
/**
* Fixture showing that it's not sufficient to only align direct scoped
* accesses of a block-fallthrough pair.
* Below is a simplified view of HIR blocks in this fixture.
* Note that here, s is mutated in both bb1 and bb4. However, neither
* bb1 nor bb4 have terminal fallthroughs or are fallthroughs themselves.
*
* This means that we need to recursively visit all scopes accessed between
* a block and its fallthrough and extend the range of those scopes which overlap
* with an active block/fallthrough pair,
*
* bb0
* ┌──────────────┐
* │let s = null │
* │test cond1 │
* │ <fallthr=bb3>│
* └┬─────────────┘
* │ bb1
* ├─►┌───────┐
* │ │s = {} ├────┐
* │ └───────┘ │
* │ bb2 │
* └─►┌───────┐ │
* │return;│ │
* └───────┘ │
* bb3 │
* ┌──────────────┐◄┘
* │test cond2 │
* │ <fallthr=bb5>│
* └┬─────────────┘
* │ bb4
* ├─►┌─────────┐
* │ │mutate(s)├─┐
* ▼ └─────────┘ │
* bb5 │
* ┌───────────┐ │
* │return s; │◄──┘
* └───────────┘
*/
function useFoo(cond1, cond2) {
let s = null;
if (cond1) {
s = {};
} else {
return null;
}
if (cond2) {
mutate(s);
}
return s;
}
@@ -488,6 +488,8 @@ const skipFilter = new Set([
"bug-invalid-hoisting-functionexpr",
"original-reactive-scopes-fork/bug-nonmutating-capture-in-unsplittable-memo-block",
"original-reactive-scopes-fork/bug-hoisted-declaration-with-scope",
"bug-codegen-inline-iife",
"bug-phi-reference-effect",
// 'react-compiler-runtime' not yet supported
"flag-enable-emit-hook-guards",