From 7adc694a536de0e7fd0dcad7d4fdcded22aa6c49 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 4 Aug 2025 11:06:37 -0400 Subject: [PATCH] [compiler] Add repros for various invariants We received some bug reports about invariants reported by the compiler in their codebase. Adding them as repros. --- ...-infer-mutation-aliasing-effects.expect.md | 46 +++++++++++++++++++ ...ror.bug-infer-mutation-aliasing-effects.js | 18 ++++++++ ...bug-invariant-codegen-methodcall.expect.md | 31 +++++++++++++ .../error.bug-invariant-codegen-methodcall.js | 5 ++ ...nt-couldnt-find-binding-for-decl.expect.md | 37 +++++++++++++++ ...invariant-couldnt-find-binding-for-decl.js | 11 +++++ ...-invariant-expected-break-target.expect.md | 32 +++++++++++++ ...ror.bug-invariant-expected-break-target.js | 15 ++++++ ...xpected-consistent-destructuring.expect.md | 44 ++++++++++++++++++ ...riant-expected-consistent-destructuring.js | 16 +++++++ ...iant-local-or-context-references.expect.md | 46 +++++++++++++++++++ ...g-invariant-local-or-context-references.js | 18 ++++++++ ...-unexpected-terminal-in-optional.expect.md | 34 ++++++++++++++ ...variant-unexpected-terminal-in-optional.js | 8 ++++ ....bug-invariant-unnamed-temporary.expect.md | 30 ++++++++++++ .../error.bug-invariant-unnamed-temporary.js | 11 +++++ 16 files changed, 402 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-infer-mutation-aliasing-effects.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-infer-mutation-aliasing-effects.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-codegen-methodcall.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-codegen-methodcall.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-couldnt-find-binding-for-decl.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-couldnt-find-binding-for-decl.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-break-target.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-break-target.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-consistent-destructuring.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-consistent-destructuring.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-local-or-context-references.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-local-or-context-references.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unexpected-terminal-in-optional.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unexpected-terminal-in-optional.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unnamed-temporary.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unnamed-temporary.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-infer-mutation-aliasing-effects.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-infer-mutation-aliasing-effects.expect.md new file mode 100644 index 0000000000000..a1c64e50483f8 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-infer-mutation-aliasing-effects.expect.md @@ -0,0 +1,46 @@ + +## Input + +```javascript +import {useCallback, useRef} from 'react'; + +export default function useThunkDispatch(state, dispatch, extraArg) { + const stateRef = useRef(state); + stateRef.current = state; + + return useCallback( + function thunk(action) { + if (typeof action === 'function') { + return action(thunk, () => stateRef.current, extraArg); + } else { + dispatch(action); + return undefined; + } + }, + [dispatch, extraArg] + ); +} + +``` + + +## Error + +``` +Found 1 error: + +Invariant: [InferMutationAliasingEffects] Expected value kind to be initialized + + thunk$14. + +error.bug-infer-mutation-aliasing-effects.ts:10:22 + 8 | function thunk(action) { + 9 | if (typeof action === 'function') { +> 10 | return action(thunk, () => stateRef.current, extraArg); + | ^^^^^ [InferMutationAliasingEffects] Expected value kind to be initialized + 11 | } else { + 12 | dispatch(action); + 13 | return undefined; +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-infer-mutation-aliasing-effects.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-infer-mutation-aliasing-effects.js new file mode 100644 index 0000000000000..3309406fc70ca --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-infer-mutation-aliasing-effects.js @@ -0,0 +1,18 @@ +import {useCallback, useRef} from 'react'; + +export default function useThunkDispatch(state, dispatch, extraArg) { + const stateRef = useRef(state); + stateRef.current = state; + + return useCallback( + function thunk(action) { + if (typeof action === 'function') { + return action(thunk, () => stateRef.current, extraArg); + } else { + dispatch(action); + return undefined; + } + }, + [dispatch, extraArg] + ); +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-codegen-methodcall.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-codegen-methodcall.expect.md new file mode 100644 index 0000000000000..4ea831de8751e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-codegen-methodcall.expect.md @@ -0,0 +1,31 @@ + +## Input + +```javascript +const YearsAndMonthsSince = () => { + const diff = foo(); + const months = Math.floor(diff.bar()); + return <>{months}; +}; + +``` + + +## Error + +``` +Found 1 error: + +Invariant: [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. Got a `Identifier` + +error.bug-invariant-codegen-methodcall.ts:3:17 + 1 | const YearsAndMonthsSince = () => { + 2 | const diff = foo(); +> 3 | const months = Math.floor(diff.bar()); + | ^^^^^^^^^^ [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. Got a `Identifier` + 4 | return <>{months}; + 5 | }; + 6 | +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-codegen-methodcall.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-codegen-methodcall.js new file mode 100644 index 0000000000000..948182653cbe0 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-codegen-methodcall.js @@ -0,0 +1,5 @@ +const YearsAndMonthsSince = () => { + const diff = foo(); + const months = Math.floor(diff.bar()); + return <>{months}; +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-couldnt-find-binding-for-decl.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-couldnt-find-binding-for-decl.expect.md new file mode 100644 index 0000000000000..b50ad7035939e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-couldnt-find-binding-for-decl.expect.md @@ -0,0 +1,37 @@ + +## Input + +```javascript +import {useEffect} from 'react'; + +export function Foo() { + useEffect(() => { + try { + // do something + } catch ({status}) { + // do something + } + }, []); +} + +``` + + +## Error + +``` +Found 1 error: + +Invariant: (BuildHIR::lowerAssignment) Could not find binding for declaration. + +error.bug-invariant-couldnt-find-binding-for-decl.ts:7:14 + 5 | try { + 6 | // do something +> 7 | } catch ({status}) { + | ^^^^^^ (BuildHIR::lowerAssignment) Could not find binding for declaration. + 8 | // do something + 9 | } + 10 | }, []); +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-couldnt-find-binding-for-decl.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-couldnt-find-binding-for-decl.js new file mode 100644 index 0000000000000..c005fec1bd5a5 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-couldnt-find-binding-for-decl.js @@ -0,0 +1,11 @@ +import {useEffect} from 'react'; + +export function Foo() { + useEffect(() => { + try { + // do something + } catch ({status}) { + // do something + } + }, []); +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-break-target.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-break-target.expect.md new file mode 100644 index 0000000000000..226ab20ac269b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-break-target.expect.md @@ -0,0 +1,32 @@ + +## Input + +```javascript +import {useMemo} from 'react'; + +export default function useFoo(text) { + return useMemo(() => { + try { + let formattedText = ''; + try { + formattedText = format(text); + } catch { + console.log('error'); + } + return formattedText || ''; + } catch (e) {} + }, [text]); +} + +``` + + +## Error + +``` +Found 1 error: + +Invariant: Expected a break target +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-break-target.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-break-target.js new file mode 100644 index 0000000000000..4616e0232aafe --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-break-target.js @@ -0,0 +1,15 @@ +import {useMemo} from 'react'; + +export default function useFoo(text) { + return useMemo(() => { + try { + let formattedText = ''; + try { + formattedText = format(text); + } catch { + console.log('error'); + } + return formattedText || ''; + } catch (e) {} + }, [text]); +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-consistent-destructuring.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-consistent-destructuring.expect.md new file mode 100644 index 0000000000000..a30ccffcd7bd0 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-consistent-destructuring.expect.md @@ -0,0 +1,44 @@ + +## Input + +```javascript +import {useMemo} from 'react'; +import {useFoo, formatB, Baz} from './lib'; + +export const Example = ({data}) => { + let a; + let b; + + if (data) { + ({a, b} = data); + } + + const foo = useFoo(a); + const bar = useMemo(() => formatB(b), [b]); + + return ; +}; + +``` + + +## Error + +``` +Found 1 error: + +Invariant: Expected consistent kind for destructuring + +Other places were `Reassign` but 'mutate? #t8$46[7:9]{reactive}' is const. + +error.bug-invariant-expected-consistent-destructuring.ts:9:9 + 7 | + 8 | if (data) { +> 9 | ({a, b} = data); + | ^ Expected consistent kind for destructuring + 10 | } + 11 | + 12 | const foo = useFoo(a); +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-consistent-destructuring.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-consistent-destructuring.js new file mode 100644 index 0000000000000..c37b19314431b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-expected-consistent-destructuring.js @@ -0,0 +1,16 @@ +import {useMemo} from 'react'; +import {useFoo, formatB, Baz} from './lib'; + +export const Example = ({data}) => { + let a; + let b; + + if (data) { + ({a, b} = data); + } + + const foo = useFoo(a); + const bar = useMemo(() => formatB(b), [b]); + + return ; +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-local-or-context-references.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-local-or-context-references.expect.md new file mode 100644 index 0000000000000..bbf753f965091 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-local-or-context-references.expect.md @@ -0,0 +1,46 @@ + +## Input + +```javascript +import {useState} from 'react'; +import {bar} from './bar'; + +export const useFoot = () => { + const [, setState] = useState(null); + try { + const {data} = bar(); + setState({ + data, + error: null, + }); + } catch (err) { + setState(_prevState => ({ + loading: false, + error: err, + })); + } +}; + +``` + + +## Error + +``` +Found 1 error: + +Invariant: Expected all references to a variable to be consistently local or context references + +Identifier err$7 is referenced as a context variable, but was previously referenced as a [object Object] variable. + +error.bug-invariant-local-or-context-references.ts:15:13 + 13 | setState(_prevState => ({ + 14 | loading: false, +> 15 | error: err, + | ^^^ Expected all references to a variable to be consistently local or context references + 16 | })); + 17 | } + 18 | }; +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-local-or-context-references.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-local-or-context-references.js new file mode 100644 index 0000000000000..561bc25fb72ad --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-local-or-context-references.js @@ -0,0 +1,18 @@ +import {useState} from 'react'; +import {bar} from './bar'; + +export const useFoot = () => { + const [, setState] = useState(null); + try { + const {data} = bar(); + setState({ + data, + error: null, + }); + } catch (err) { + setState(_prevState => ({ + loading: false, + error: err, + })); + } +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unexpected-terminal-in-optional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unexpected-terminal-in-optional.expect.md new file mode 100644 index 0000000000000..743d2b9071e6a --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unexpected-terminal-in-optional.expect.md @@ -0,0 +1,34 @@ + +## Input + +```javascript +const Foo = ({json}) => { + try { + const foo = JSON.parse(json)?.foo; + return {foo}; + } catch { + return null; + } +}; + +``` + + +## Error + +``` +Found 1 error: + +Invariant: Unexpected terminal in optional + +error.bug-invariant-unexpected-terminal-in-optional.ts:3:16 + 1 | const Foo = ({json}) => { + 2 | try { +> 3 | const foo = JSON.parse(json)?.foo; + | ^^^^ Unexpected terminal in optional + 4 | return {foo}; + 5 | } catch { + 6 | return null; +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unexpected-terminal-in-optional.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unexpected-terminal-in-optional.js new file mode 100644 index 0000000000000..961640bfbd387 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unexpected-terminal-in-optional.js @@ -0,0 +1,8 @@ +const Foo = ({json}) => { + try { + const foo = JSON.parse(json)?.foo; + return {foo}; + } catch { + return null; + } +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unnamed-temporary.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unnamed-temporary.expect.md new file mode 100644 index 0000000000000..f8c46659bf7c2 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unnamed-temporary.expect.md @@ -0,0 +1,30 @@ + +## Input + +```javascript +import Bar from './Bar'; + +export function Foo() { + return ( + { + return {displayValue}; + }} + /> + ); +} + +``` + + +## Error + +``` +Found 1 error: + +Invariant: Expected temporaries to be promoted to named identifiers in an earlier pass + +identifier 15 is unnamed. +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unnamed-temporary.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unnamed-temporary.js new file mode 100644 index 0000000000000..4a06093d9f1ef --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-invariant-unnamed-temporary.js @@ -0,0 +1,11 @@ +import Bar from './Bar'; + +export function Foo() { + return ( + { + return {displayValue}; + }} + /> + ); +}