Skip to content

Commit e0814ac

Browse files
committed
[Compiler] Don't throw calculate in render when there is a global function call in the effect
Summary: Global function calls can introduce unexpected side effects, for this first iteration we are bailing out the validation when we encounter one. Local function calls remain
1 parent d6a7017 commit e0814ac

File tree

3 files changed

+81
-0
lines changed

3 files changed

+81
-0
lines changed

compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects_exp.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ function validateEffect(
350350
sourceIds: Set<IdentifierId>;
351351
}> = [];
352352

353+
const globals: Set<IdentifierId> = new Set();
353354
for (const block of effectFunction.body.blocks.values()) {
354355
for (const pred of block.preds) {
355356
if (!seenBlocks.has(pred)) {
@@ -393,6 +394,16 @@ function validateEffect(
393394
// If the callee is a prop we can't confidently say that it should be derived in render
394395
return;
395396
}
397+
398+
if (globals.has(instr.value.callee.identifier.id)) {
399+
// If the callee is a global we can't confidently say that it should be derived in render
400+
return;
401+
}
402+
} else if (instr.value.kind === 'LoadGlobal') {
403+
globals.add(instr.lvalue.identifier.id);
404+
for (const operand of eachInstructionOperand(instr)) {
405+
globals.add(operand.identifier.id);
406+
}
396407
}
397408
}
398409
seenBlocks.add(block.id);
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
2+
## Input
3+
4+
```javascript
5+
// @validateNoDerivedComputationsInEffects_exp
6+
import {useEffect, useState} from 'react';
7+
8+
function Component({propValue}) {
9+
const [value, setValue] = useState(null);
10+
useEffect(() => {
11+
setValue(propValue);
12+
globalCall();
13+
}, [propValue]);
14+
15+
return <div>{value}</div>;
16+
}
17+
18+
export const FIXTURE_ENTRYPOINT = {
19+
fn: Component,
20+
params: [{propValue: 'test'}],
21+
};
22+
23+
```
24+
25+
## Code
26+
27+
```javascript
28+
import { c as _c } from "react/compiler-runtime"; // @validateNoDerivedComputationsInEffects_exp
29+
import { useEffect, useState } from "react";
30+
31+
function Component(t0) {
32+
const $ = _c(5);
33+
const { propValue } = t0;
34+
const [value, setValue] = useState(null);
35+
let t1;
36+
let t2;
37+
if ($[0] !== propValue) {
38+
t1 = () => {
39+
setValue(propValue);
40+
globalCall();
41+
};
42+
t2 = [propValue];
43+
$[0] = propValue;
44+
$[1] = t1;
45+
$[2] = t2;
46+
} else {
47+
t1 = $[1];
48+
t2 = $[2];
49+
}
50+
useEffect(t1, t2);
51+
let t3;
52+
if ($[3] !== value) {
53+
t3 = <div>{value}</div>;
54+
$[3] = value;
55+
$[4] = t3;
56+
} else {
57+
t3 = $[4];
58+
}
59+
return t3;
60+
}
61+
62+
export const FIXTURE_ENTRYPOINT = {
63+
fn: Component,
64+
params: [{ propValue: "test" }],
65+
};
66+
67+
```
68+
69+
### Eval output
70+
(kind: exception) globalCall is not defined

0 commit comments

Comments
 (0)