Skip to content

Commit ee2c0be

Browse files
committed
[compiler][repro] Postfix operator is incorrectly compiled
This bug was reported via our wg and appears to only affect values created as a ref. Currently, postfix operators used in a callback gets compiled to: ```js modalId.current = modalId.current + 1; // 1 const id = modalId.current; // 1 return id; ``` which is semantically incorrect. The postfix increment operator should return the value before incrementing. In other words something like this should have been compiled instead: ```js const id = modalId.current; // 0 modalId.current = modalId.current + 1; // 1 return id; ``` This bug does not trigger when the incremented value is a plain primitive, instead there is a TODO bailout.
1 parent 6c86e56 commit ee2c0be

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
2+
## Input
3+
4+
```javascript
5+
import {useRef} from 'react';
6+
7+
/**
8+
* The postfix increment operator should return the value before incrementing.
9+
* ```js
10+
* const id = modalId.current; // 0
11+
* modalId.current = modalId.current + 1; // 1
12+
* return id;
13+
* ```
14+
* The bug is that
15+
* This bug does not trigger when the incremented value is a plain primitive.
16+
*/
17+
function useFoo() {
18+
const modalId = useRef(0);
19+
const showModal = () => {
20+
const id = modalId.current++;
21+
return id;
22+
};
23+
const showModal2 = () => {
24+
const id = ++modalId.current;
25+
return id;
26+
};
27+
return {modalId, showModal, showModal2};
28+
}
29+
30+
export const FIXTURE_ENTRYPOINT = {
31+
fn: useFoo,
32+
params: [],
33+
};
34+
35+
```
36+
37+
## Code
38+
39+
```javascript
40+
import { c as _c } from "react/compiler-runtime";
41+
import { useRef } from "react";
42+
43+
/**
44+
* The postfix increment operator should return the value before incrementing.
45+
* ```js
46+
* const id = modalId.current; // 0
47+
* modalId.current = modalId.current + 1; // 1
48+
* return id;
49+
* ```
50+
* The bug is that
51+
* This bug does not trigger when the incremented value is a plain primitive.
52+
*/
53+
function useFoo() {
54+
const $ = _c(2);
55+
const modalId = useRef(0);
56+
let t0;
57+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
58+
t0 = () => {
59+
modalId.current = modalId.current + 1;
60+
const id = modalId.current;
61+
return id;
62+
};
63+
$[0] = t0;
64+
} else {
65+
t0 = $[0];
66+
}
67+
const showModal = t0;
68+
let t1;
69+
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
70+
const showModal2 = () => {
71+
const id_0 = (modalId.current = modalId.current + 1);
72+
return id_0;
73+
};
74+
75+
t1 = { modalId, showModal, showModal2 };
76+
$[1] = t1;
77+
} else {
78+
t1 = $[1];
79+
}
80+
return t1;
81+
}
82+
83+
export const FIXTURE_ENTRYPOINT = {
84+
fn: useFoo,
85+
params: [],
86+
};
87+
88+
```
89+
90+
### Eval output
91+
(kind: ok) {"modalId":{"current":0},"showModal":"[[ function params=0 ]]","showModal2":"[[ function params=0 ]]"}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import {useRef} from 'react';
2+
3+
/**
4+
* The postfix increment operator should return the value before incrementing.
5+
* ```js
6+
* const id = modalId.current; // 0
7+
* modalId.current = modalId.current + 1; // 1
8+
* return id;
9+
* ```
10+
* The bug is that
11+
* This bug does not trigger when the incremented value is a plain primitive.
12+
*/
13+
function useFoo() {
14+
const modalId = useRef(0);
15+
const showModal = () => {
16+
const id = modalId.current++;
17+
return id;
18+
};
19+
const showModal2 = () => {
20+
const id = ++modalId.current;
21+
return id;
22+
};
23+
return {modalId, showModal, showModal2};
24+
}
25+
26+
export const FIXTURE_ENTRYPOINT = {
27+
fn: useFoo,
28+
params: [],
29+
};

0 commit comments

Comments
 (0)