Skip to content

Commit 2bd1c75

Browse files
davesnxeps1lon
andauthored
Ensure function arity is preserved after build (facebook#31808)
Co-authored-by: eps1lon <[email protected]>
1 parent 6a4b46c commit 2bd1c75

File tree

8 files changed

+113
-6
lines changed

8 files changed

+113
-6
lines changed

packages/react-dom/src/client/ReactDOMRoot.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,17 +106,19 @@ ReactDOMHydrationRoot.prototype.render = ReactDOMRoot.prototype.render =
106106
}
107107

108108
if (__DEV__) {
109-
if (typeof arguments[1] === 'function') {
109+
// using a reference to `arguments` bails out of GCC optimizations which affect function arity
110+
const args = arguments;
111+
if (typeof args[1] === 'function') {
110112
console.error(
111113
'does not support the second callback argument. ' +
112114
'To execute a side effect after rendering, declare it in a component body with useEffect().',
113115
);
114-
} else if (isValidContainer(arguments[1])) {
116+
} else if (isValidContainer(args[1])) {
115117
console.error(
116118
'You passed a container to the second argument of root.render(...). ' +
117119
"You don't need to pass it again since you already passed it to create the root.",
118120
);
119-
} else if (typeof arguments[1] !== 'undefined') {
121+
} else if (typeof args[1] !== 'undefined') {
120122
console.error(
121123
'You passed a second argument to root.render(...) but it only accepts ' +
122124
'one argument.',
@@ -131,7 +133,9 @@ ReactDOMHydrationRoot.prototype.unmount = ReactDOMRoot.prototype.unmount =
131133
// $FlowFixMe[missing-this-annot]
132134
function (): void {
133135
if (__DEV__) {
134-
if (typeof arguments[0] === 'function') {
136+
// using a reference to `arguments` bails out of GCC optimizations which affect function arity
137+
const args = arguments;
138+
if (typeof args[0] === 'function') {
135139
console.error(
136140
'does not support a callback argument. ' +
137141
'To execute a side effect after rendering, declare it in a component body with useEffect().',

packages/react-reconciler/src/ReactFiberHooks.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3626,7 +3626,9 @@ function dispatchReducerAction<S, A>(
36263626
action: A,
36273627
): void {
36283628
if (__DEV__) {
3629-
if (typeof arguments[3] === 'function') {
3629+
// using a reference to `arguments` bails out of GCC optimizations which affect function arity
3630+
const args = arguments;
3631+
if (typeof args[3] === 'function') {
36303632
console.error(
36313633
"State updates from the useState() and useReducer() Hooks don't support the " +
36323634
'second callback argument. To execute a side effect after ' +
@@ -3666,7 +3668,9 @@ function dispatchSetState<S, A>(
36663668
action: A,
36673669
): void {
36683670
if (__DEV__) {
3669-
if (typeof arguments[3] === 'function') {
3671+
// using a reference to `arguments` bails out of GCC optimizations which affect function arity
3672+
const args = arguments;
3673+
if (typeof args[3] === 'function') {
36703674
console.error(
36713675
"State updates from the useState() and useReducer() Hooks don't support the " +
36723676
'second callback argument. To execute a side effect after ' +
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @emails react-core
8+
*/
9+
10+
'use strict';
11+
12+
let React;
13+
let ReactNoop;
14+
15+
describe('arity', () => {
16+
beforeEach(() => {
17+
jest.resetModules();
18+
19+
React = require('react');
20+
ReactNoop = require('react-noop-renderer');
21+
});
22+
23+
it("ensure useState setter's arity is correct", () => {
24+
function Component() {
25+
const [, setState] = React.useState(() => 'Halo!');
26+
27+
expect(setState.length).toBe(1);
28+
return null;
29+
}
30+
31+
ReactNoop.render(<Component />);
32+
});
33+
34+
it("ensure useReducer setter's arity is correct", () => {
35+
function Component() {
36+
const [, dispatch] = React.useReducer(() => 'Halo!');
37+
38+
expect(dispatch.length).toBe(1);
39+
return null;
40+
}
41+
42+
ReactNoop.render(<Component />);
43+
});
44+
});

scripts/rollup/validate/eslintrc.cjs.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,17 @@ module.exports = {
8686
rules: {
8787
'no-undef': 'error',
8888
'no-shadow-restricted-names': 'error',
89+
'no-restricted-syntax': [
90+
'error',
91+
// TODO: Can be removed once we upgrade GCC to a version without `optimizeArgumentsArray` optimization.
92+
{
93+
selector: 'Identifier[name=/^JSCompiler_OptimizeArgumentsArray_/]',
94+
message:
95+
'Google Closure Compiler optimized `arguments` access. ' +
96+
'This affects function arity. ' +
97+
'Create a reference to `arguments` to avoid this optimization',
98+
},
99+
],
89100
},
90101

91102
// These plugins aren't used, but eslint complains if an eslint-ignore comment

scripts/rollup/validate/eslintrc.cjs2015.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@ module.exports = {
8181
rules: {
8282
'no-undef': 'error',
8383
'no-shadow-restricted-names': 'error',
84+
'no-restricted-syntax': [
85+
'error',
86+
// TODO: Can be removed once we upgrade GCC to a version without `optimizeArgumentsArray` optimization.
87+
{
88+
selector: 'Identifier[name=/^JSCompiler_OptimizeArgumentsArray_/]',
89+
message:
90+
'Google Closure Compiler optimized `arguments` access. ' +
91+
'This affects function arity. ' +
92+
'Create a reference to `arguments` to avoid this optimization',
93+
},
94+
],
8495
},
8596

8697
// These plugins aren't used, but eslint complains if an eslint-ignore comment

scripts/rollup/validate/eslintrc.esm.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,17 @@ module.exports = {
8383
rules: {
8484
'no-undef': 'error',
8585
'no-shadow-restricted-names': 'error',
86+
'no-restricted-syntax': [
87+
'error',
88+
// TODO: Can be removed once we upgrade GCC to a version without `optimizeArgumentsArray` optimization.
89+
{
90+
selector: 'Identifier[name=/^JSCompiler_OptimizeArgumentsArray_/]',
91+
message:
92+
'Google Closure Compiler optimized `arguments` access. ' +
93+
'This affects function arity. ' +
94+
'Create a reference to `arguments` to avoid this optimization',
95+
},
96+
],
8697
},
8798

8899
// These plugins aren't used, but eslint complains if an eslint-ignore comment

scripts/rollup/validate/eslintrc.fb.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,17 @@ module.exports = {
7171
rules: {
7272
'no-undef': 'error',
7373
'no-shadow-restricted-names': 'error',
74+
'no-restricted-syntax': [
75+
'error',
76+
// TODO: Can be removed once we upgrade GCC to a version without `optimizeArgumentsArray` optimization.
77+
{
78+
selector: 'Identifier[name=/^JSCompiler_OptimizeArgumentsArray_/]',
79+
message:
80+
'Google Closure Compiler optimized `arguments` access. ' +
81+
'This affects function arity. ' +
82+
'Create a reference to `arguments` to avoid this optimization',
83+
},
84+
],
7485
},
7586

7687
// These plugins aren't used, but eslint complains if an eslint-ignore comment

scripts/rollup/validate/eslintrc.rn.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,17 @@ module.exports = {
7373
rules: {
7474
'no-undef': 'error',
7575
'no-shadow-restricted-names': 'error',
76+
'no-restricted-syntax': [
77+
'error',
78+
// TODO: Can be removed once we upgrade GCC to a version without `optimizeArgumentsArray` optimization.
79+
{
80+
selector: 'Identifier[name=/^JSCompiler_OptimizeArgumentsArray_/]',
81+
message:
82+
'Google Closure Compiler optimized `arguments` access. ' +
83+
'This affects function arity. ' +
84+
'Create a reference to `arguments` to avoid this optimization',
85+
},
86+
],
7687
},
7788

7889
// These plugins aren't used, but eslint complains if an eslint-ignore comment

0 commit comments

Comments
 (0)