[compiler] Prevent overriding a derivationEntry on effect mutation and instead update typeOfValue and fix infinite loops#34967
Conversation
| typeOfValue, | ||
| if ( | ||
| isMutable(instr, operand) && | ||
| context.derivationCache.cache.has(operand.identifier.id) |
There was a problem hiding this comment.
If the derivation cache does not already have this entry, we still may want to record a typeOfValue. Or is this already handled by your fixpoint iteration logic?
function useHook() {
const [s, setS] = useState();
const cb = () => append(arr, s); // `arr` is mutable here and should get marked as `fromState`
const arr = [];
}There was a problem hiding this comment.
Ah I see, I didn't add it because I couldn't think of an example when it would record a derivation for the first time on mutation. I'll add it
| context.derivationCache.takeSnapshot(); | ||
|
|
||
| for (const block of fn.body.blocks.values()) { | ||
| recordPhiDerivations(block, context); |
There was a problem hiding this comment.
Hmm what's the reasoning for moving when we record phis? A block's phis often defines values used by the block so we may find that the derivation cache is missing values when processing instructions with this change.
In the below example, we want to call recordPhiDerivations to insert x@2 into the context. Then, when we walk over the instructions of the fallthrough block (LoadLocal x@2, Call doSomething), we can read the proper typeOfValue from context
let x = thing1; // x@0
if (cond) {
x = {}; // x@1
}
// x@2 = phi(x@0, x@1)
doSomething(x) // <- references x@2There was a problem hiding this comment.
Oh, my bad, I moved it when debugging the infinite loop. I'll move it back
…d instead update typeOfValue and fix infinite loops
Summary:
With this we are now comparing a snapshot of the derivationCache with the new changes every time we are done recording the derivations happening in the HIR.
We have to do this after recording everything since we still do some mutations on the cache when recording mutations.
Test Plan:
Test the following in playground:
```
// @validateNoDerivedComputationsInEffects_exp
function Component({ value }) {
const [checked, setChecked] = useState('');
useEffect(() => {
setChecked(value === '' ? [] : value.split(','));
}, [value]);
return (
<div>{checked}</div>
)
}
```
This no longer causes an infinite loop.
Added a test case in the next PR in the stack
…or for `no-deriving-state-in-effects` (#34995) Summary: Revamped the derivationCache graph. This fixes a bunch of bugs where sometimes we fail to track from which props/state we derived values from. Also, it is more intuitive and allows us to easily implement a Data Flow Tree. We can print this tree which gives insight on how the data is derived and should facilitate error resolution in complicated components Test Plan: Added a test case where we were failing to track derivations. Also updated the test cases with the new error containing the data flow tree --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34995). * #35044 * #35020 * #34973 * #34972 * __->__ #34995 * #34967
…d instead update typeOfValue and fix infinite loops (#34967) Summary: With this we are now comparing a snapshot of the derivationCache with the new changes every time we are done recording the derivations happening in the HIR. We have to do this after recording everything since we still do some mutations on the cache when recording mutations. Test Plan: Test the following in playground: ``` // @validateNoDerivedComputationsInEffects_exp function Component({ value }) { const [checked, setChecked] = useState(''); useEffect(() => { setChecked(value === '' ? [] : value.split(',')); }, [value]); return ( <div>{checked}</div> ) } ``` This no longer causes an infinite loop. Added a test case in the next PR in the stack --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34967). * #35044 * #35020 * #34973 * #34972 * #34995 * __->__ #34967 DiffTrain build for [01fb328](01fb328)
…d instead update typeOfValue and fix infinite loops (#34967) Summary: With this we are now comparing a snapshot of the derivationCache with the new changes every time we are done recording the derivations happening in the HIR. We have to do this after recording everything since we still do some mutations on the cache when recording mutations. Test Plan: Test the following in playground: ``` // @validateNoDerivedComputationsInEffects_exp function Component({ value }) { const [checked, setChecked] = useState(''); useEffect(() => { setChecked(value === '' ? [] : value.split(',')); }, [value]); return ( <div>{checked}</div> ) } ``` This no longer causes an infinite loop. Added a test case in the next PR in the stack --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34967). * #35044 * #35020 * #34973 * #34972 * #34995 * __->__ #34967 DiffTrain build for [01fb328](01fb328)
…or for `no-deriving-state-in-effects` (#34995) Summary: Revamped the derivationCache graph. This fixes a bunch of bugs where sometimes we fail to track from which props/state we derived values from. Also, it is more intuitive and allows us to easily implement a Data Flow Tree. We can print this tree which gives insight on how the data is derived and should facilitate error resolution in complicated components Test Plan: Added a test case where we were failing to track derivations. Also updated the test cases with the new error containing the data flow tree --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34995). * #35044 * #35020 * #34973 * #34972 * __->__ #34995 * #34967 DiffTrain build for [6347c6d](6347c6d)
…d instead update typeOfValue and fix infinite loops (facebook#34967) Summary: With this we are now comparing a snapshot of the derivationCache with the new changes every time we are done recording the derivations happening in the HIR. We have to do this after recording everything since we still do some mutations on the cache when recording mutations. Test Plan: Test the following in playground: ``` // @validateNoDerivedComputationsInEffects_exp function Component({ value }) { const [checked, setChecked] = useState(''); useEffect(() => { setChecked(value === '' ? [] : value.split(',')); }, [value]); return ( <div>{checked}</div> ) } ``` This no longer causes an infinite loop. Added a test case in the next PR in the stack --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34967). * facebook#35044 * facebook#35020 * facebook#34973 * facebook#34972 * facebook#34995 * __->__ facebook#34967
…or for `no-deriving-state-in-effects` (facebook#34995) Summary: Revamped the derivationCache graph. This fixes a bunch of bugs where sometimes we fail to track from which props/state we derived values from. Also, it is more intuitive and allows us to easily implement a Data Flow Tree. We can print this tree which gives insight on how the data is derived and should facilitate error resolution in complicated components Test Plan: Added a test case where we were failing to track derivations. Also updated the test cases with the new error containing the data flow tree --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34995). * facebook#35044 * facebook#35020 * facebook#34973 * facebook#34972 * __->__ facebook#34995 * facebook#34967
Summary:
With this we are now comparing a snapshot of the derivationCache with the new changes every time we are done recording the derivations happening in the HIR.
We have to do this after recording everything since we still do some mutations on the cache when recording mutations.
Test Plan:
Test the following in playground:
This no longer causes an infinite loop.
Added a test case in the next PR in the stack
Stack created with Sapling. Best reviewed with ReviewStack.
no-deriving-state-in-effects#34995