fix(react_compiler): codegen destructuring reassignment targets (#24131)

## Root cause

The reactive-function backend (`codegen_reactive_function.rs`) only knew
how to turn a plain `BindingIdentifier` lvalue into an
`AssignmentTarget`. Any **destructuring reassignment** to an existing
binding — `[x] = arr`, `({a} = obj)`, `({a} = {a:{}}), ([x] = [[]])` —
hit an unported `invariant_err("Destructuring reassignment targets are
not yet ported to oxc")`.

`codegen_function` deliberately swallows any emission error and falls
back to an **empty body** (a shim from the de-Babel batches). So every
function containing such an assignment silently compiled to `function
f() {}` — params and body both dropped — with **no diagnostic**. This is
a hard miscompile, not a whitespace diff.

## Fix

Port `ox_binding_pattern_to_assignment_target` to recursively reshape
`BindingPattern` → `AssignmentTarget`, since oxc (unlike Babel) models
declaration patterns and assignment targets as distinct node families.
Adds handling for:

- array patterns → `ArrayAssignmentTarget` (elements + holes + rest)
- object patterns → `ObjectAssignmentTarget`, distinguishing shorthand
(`{a}` / `{a = 1}` → `AssignmentTargetPropertyIdentifier`) from keyed
(`{a: b}` → `AssignmentTargetPropertyProperty`)
- rest elements (`...x`)
- nested patterns and defaults (`AssignmentTargetWithDefault`)

Mirrors Babel, which reuses the same pattern nodes as the assignment
LHS.

## Impact

23 corpus snapshots changed — **all move toward the fork golden, none
regress**; 14 now match the fork exactly. Verified old-vs-new token
distance to each fork golden.

Within this batch (`reduce-reactive-deps` /
`propagate-scope-deps-hir-fork`):

- `ssa-renaming-via-destructuring-with-mutation` — was empty function,
now matches the fork exactly.
- `ssa-renaming-ternary-destruction` /
`ssa-renaming-ternary-destruction-with-mutation` — were empty functions,
now compile with **matching dependency sets, cache keys, scope
boundaries, and dead-code elimination**; the only residual is
codegen-only (sequence-expression parenthesisation `([x]=[[]], …)` vs
`(([x]=[[]]), …)` and object-literal whitespace).

Other improved fixtures across the corpus (also previously
empty-bodied): `destructuring`, `destructuring-assignment`,
`destructuring-assignment-array-default`,
`destructure-direct-reassignment`, `destructure-in-branch-ssa`,
`destructuring-object-pattern-within-rest`,
`escape-analysis-destructured-rest-element`,
`call-args-destructuring-assignment`,
`array-pattern-spread-creates-array`, the `nonmutated-spread-*` set,
`repro-reassign-props`, `switch-with-only-default`,
`new-mutability__ssa-renaming-ternary-destruction`.

## Remaining work (out of scope here)

The rest of the batch's diffs are pure codegen and live in
`oxc_codegen`, not the dependency passes:
- sequence-expression parenthesisation of assignment operands (`(a=[],
b)` vs `((a=[]), b)`)
- JSX multi-line wrapping, TS type printing, object/array-literal
whitespace

The two `try-catch-*` fixtures (stray `;`) belong to a sibling
`fix/rc-try-catch` branch and are left untouched.
This commit is contained in:
Boshen authored and GitHub committed 2026-07-04 10:43:43 +08:00
1 parent b82c394e2f
commit cb2a5051af
24 files changed
+740 -28

No files matched your search

@@ -2566,6 +2566,12 @@ fn ox_codegen_dependency<'a>(
/// Convert a `BindingPattern` (from `ox_codegen_lvalue`) into an `AssignmentTarget`
/// for reassignment / `StoreLocal` emission.
///
/// oxc models declaration binding patterns (`BindingPattern`) and assignment targets
/// (`AssignmentTarget`) as distinct node families, so a destructuring reassignment
/// like `[x] = arr` or `({a} = obj)` must be re-shaped from the pattern produced by
/// `ox_codegen_lvalue` into the corresponding assignment-target tree. Mirrors Babel,
/// which reuses the same `ArrayPattern`/`ObjectPattern` nodes as assignment LHS.
fn ox_binding_pattern_to_assignment_target<'a>(
cx: &OxcContext<'a, '_, '_>,
pattern: oxc::BindingPattern<'a>,
@@ -2573,17 +2579,119 @@ fn ox_binding_pattern_to_assignment_target<'a>(
match pattern {
oxc::BindingPattern::BindingIdentifier(id) => {
let id = id.unbox();
Ok(oxc::AssignmentTarget::AssignmentTargetIdentifier(
oxc_ast::ast::IdentifierReference::boxed(SPAN, id.name, &cx.ast),
Ok(oxc::AssignmentTarget::new_assignment_target_identifier(SPAN, id.name, &cx.ast))
}
oxc::BindingPattern::ArrayPattern(arr) => {
let arr = arr.unbox();
let mut elements: oxc_allocator::Vec<
'a,
Option<oxc::AssignmentTargetMaybeDefault<'a>>,
> = oxc_allocator::ArenaVec::new_in(&cx.ast);
for element in arr.elements {
match element {
Some(bp) => elements.push(Some(ox_binding_pattern_to_maybe_default(cx, bp)?)),
None => elements.push(None),
}
}
let rest = ox_binding_rest_to_assignment_rest(cx, arr.rest)?;
Ok(oxc::AssignmentTarget::new_array_assignment_target(SPAN, elements, rest, &cx.ast))
}
oxc::BindingPattern::ObjectPattern(obj) => {
let obj = obj.unbox();
let mut properties: oxc_allocator::Vec<'a, oxc::AssignmentTargetProperty<'a>> =
oxc_allocator::ArenaVec::new_in(&cx.ast);
for prop in obj.properties {
properties.push(ox_binding_property_to_assignment_property(cx, prop)?);
}
let rest = ox_binding_rest_to_assignment_rest(cx, obj.rest)?;
Ok(oxc::AssignmentTarget::new_object_assignment_target(SPAN, properties, rest, &cx.ast))
}
// A top-level default (`x = 1`) is not a valid assignment target on its own;
// defaults only appear nested and are handled by `ox_binding_pattern_to_maybe_default`.
oxc::BindingPattern::AssignmentPattern(_) => {
Err(invariant_err("Unexpected default in destructuring assignment target", None))
}
}
}
/// Convert a `BindingPattern` element into an `AssignmentTargetMaybeDefault`, turning a
/// nested default (`[x = 1] = arr`) into an `AssignmentTargetWithDefault`.
fn ox_binding_pattern_to_maybe_default<'a>(
cx: &OxcContext<'a, '_, '_>,
pattern: oxc::BindingPattern<'a>,
) -> Result<oxc::AssignmentTargetMaybeDefault<'a>, CompilerError> {
match pattern {
oxc::BindingPattern::AssignmentPattern(assign) => {
let assign = assign.unbox();
let binding = ox_binding_pattern_to_assignment_target(cx, assign.left)?;
Ok(oxc::AssignmentTargetMaybeDefault::new_assignment_target_with_default(
SPAN,
binding,
assign.right,
&cx.ast,
))
}
_ => Err(unimplemented_err(
"Destructuring reassignment targets are not yet ported to oxc",
None,
other => Ok(oxc::AssignmentTargetMaybeDefault::from(
ox_binding_pattern_to_assignment_target(cx, other)?,
)),
}
}
/// Convert an object `BindingProperty` into an `AssignmentTargetProperty`, preserving the
/// shorthand form (`{a}` / `{a = 1}`) vs the keyed form (`{a: b}` / `{a: b = 1}`).
fn ox_binding_property_to_assignment_property<'a>(
cx: &OxcContext<'a, '_, '_>,
prop: oxc::BindingProperty<'a>,
) -> Result<oxc::AssignmentTargetProperty<'a>, CompilerError> {
if prop.shorthand {
let (binding, init) = match prop.value {
oxc::BindingPattern::BindingIdentifier(id) => (id.unbox(), None),
oxc::BindingPattern::AssignmentPattern(assign) => {
let assign = assign.unbox();
let oxc::BindingPattern::BindingIdentifier(id) = assign.left else {
return Err(invariant_err(
"Expected an identifier in shorthand destructuring property",
None,
));
};
(id.unbox(), Some(assign.right))
}
_ => {
return Err(invariant_err(
"Expected an identifier in shorthand destructuring property",
None,
));
}
};
let reference = oxc_ast::ast::IdentifierReference::new(SPAN, binding.name, &cx.ast);
return Ok(oxc::AssignmentTargetProperty::new_assignment_target_property_identifier(
SPAN, reference, init, &cx.ast,
));
}
let binding = ox_binding_pattern_to_maybe_default(cx, prop.value)?;
Ok(oxc::AssignmentTargetProperty::new_assignment_target_property_property(
SPAN,
prop.key,
binding,
prop.computed,
&cx.ast,
))
}
/// Convert a binding rest element (`...x`) into an assignment-target rest.
fn ox_binding_rest_to_assignment_rest<'a>(
cx: &OxcContext<'a, '_, '_>,
rest: Option<oxc_allocator::Box<'a, oxc::BindingRestElement<'a>>>,
) -> Result<Option<oxc::AssignmentTargetRest<'a>>, CompilerError> {
match rest {
Some(rest) => {
let target = ox_binding_pattern_to_assignment_target(cx, rest.unbox().argument)?;
Ok(Some(oxc_ast::ast::AssignmentTargetRest::new(SPAN, target, &cx.ast)))
}
None => Ok(None),
}
}
/// Convert an expression to a `SimpleAssignmentTarget` for update expressions.
fn ox_expression_to_simple_assignment_target<'a>(
cx: &OxcContext<'a, '_, '_>,
@@ -2,10 +2,56 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/array-pattern-spread-creates-array.js
---
import { c as _c } from "react/compiler-runtime";
// @validatePreserveExistingMemoizationGuarantees @validateExhaustiveMemoizationDependencies:false
import { useMemo } from "react";
import { makeObject_Primitives, ValidateMemoization } from "shared-runtime";
function Component() {}
function Component(props) {
const $ = _c(9);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = makeObject_Primitives();
$[0] = t0;
} else {
t0 = $[0];
}
const x = t0;
let rest;
if ($[1] !== props.array) {
[, ...rest] = props.array;
rest.push(x);
$[1] = props.array;
$[2] = rest;
} else {
rest = $[2];
}
const rest_0 = rest;
let t1;
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <ValidateMemoization inputs={[]} output={x} />;
$[3] = t1;
} else {
t1 = $[3];
}
let t2;
if ($[4] !== props.array) {
t2 = [props.array];
$[4] = props.array;
$[5] = t2;
} else {
t2 = $[5];
}
let t3;
if ($[6] !== rest_0 || $[7] !== t2) {
t3 = <>{t1}<ValidateMemoization inputs={t2} output={rest_0} /></>;
$[6] = rest_0;
$[7] = t2;
$[8] = t3;
} else {
t3 = $[8];
}
return t3;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{ array: [
@@ -2,4 +2,16 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/call-args-destructuring-assignment.js
---
function Component() {}
import { c as _c } from "react/compiler-runtime";
function Component(props) {
const $ = _c(1);
let x;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
x = makeObject();
x.foo([x] = makeObject());
$[0] = x;
} else {
x = $[0];
}
return x;
}
@@ -3,7 +3,17 @@ source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/destructure-direct-reassignment.js
---
// @enablePreserveExistingMemoizationGuarantees:false
function foo() {}
function foo(props) {
let x;
let y;
({x, y} = {
x: props.a,
y: props.b
});
console.log(x);
x = props.c;
return x + y;
}
export const FIXTURE_ENTRYPOINT = {
fn: foo,
params: ["TodoAdd"],
@@ -2,7 +2,46 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/destructure-in-branch-ssa.ts
---
function useFoo() {}
import { c as _c } from "react/compiler-runtime";
function useFoo(props) {
const $ = _c(9);
let x = null;
let y = null;
let z;
let myList;
if ($[0] !== props) {
myList = [];
if (props.doDestructure) {
({x, y, z} = props);
myList.push(z);
}
$[0] = props;
$[1] = myList;
$[2] = x;
$[3] = y;
$[4] = z;
} else {
myList = $[1];
x = $[2];
y = $[3];
z = $[4];
}
let t0;
if ($[5] !== myList || $[6] !== x || $[7] !== y) {
t0 = {
x,
y,
myList
};
$[5] = myList;
$[6] = x;
$[7] = y;
$[8] = t0;
} else {
t0 = $[8];
}
return t0;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{
@@ -2,7 +2,26 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/destructuring-assignment-array-default.js
---
function Component() {}
import { c as _c } from "react/compiler-runtime";
function Component(props) {
const $ = _c(2);
let x;
if (props.cond) {
const [t0] = props.y;
let t1;
if ($[0] !== t0) {
t1 = t0 === undefined ? ["default"] : t0;
$[0] = t0;
$[1] = t1;
} else {
t1 = $[1];
}
[x] = t1;
} else {
x = props.fallback;
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: ["TodoAdd"],
@@ -2,7 +2,41 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/destructuring-assignment.js
---
function foo() {}
import { c as _c } from "react/compiler-runtime";
function foo(a, b, c) {
const $ = _c(5);
let d;
let g;
let n;
let o;
const [t0, t1] = a;
d = t0;
const [t2] = t1;
const { e: t3 } = t2;
({f: g} = t3);
const { l: t4, o: t5 } = b;
const { m: t6 } = t4;
const [t7] = t6;
[n] = t7;
o = t5;
let t8;
if ($[0] !== d || $[1] !== g || $[2] !== n || $[3] !== o) {
t8 = {
d,
g,
n,
o
};
$[0] = d;
$[1] = g;
$[2] = n;
$[3] = o;
$[4] = t8;
} else {
t8 = $[4];
}
return t8;
}
export const FIXTURE_ENTRYPOINT = {
fn: foo,
params: ["TodoAdd"],
@@ -2,7 +2,32 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/destructuring-object-pattern-within-rest.js
---
function Component() {}
import { c as _c } from "react/compiler-runtime";
function Component(props) {
const $ = _c(6);
let t0;
let y;
if ($[0] !== props.value) {
[y, ...t0] = props.value;
$[0] = props.value;
$[1] = t0;
$[2] = y;
} else {
t0 = $[1];
y = $[2];
}
const { z } = t0;
let t1;
if ($[3] !== y || $[4] !== z) {
t1 = [y, z];
$[3] = y;
$[4] = z;
$[5] = t1;
} else {
t1 = $[5];
}
return t1;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{ value: ["y", { z: "z!" }] }]
@@ -2,7 +2,74 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/destructuring.js
---
function foo() {}
import { c as _c } from "react/compiler-runtime";
function foo(a, b, c) {
const $ = _c(18);
let d;
let h;
let t0;
if ($[0] !== a) {
[d, t0, ...h] = a;
$[0] = a;
$[1] = d;
$[2] = h;
$[3] = t0;
} else {
d = $[1];
h = $[2];
t0 = $[3];
}
const [t1] = t0;
let g;
let t2;
if ($[4] !== t1) {
({e: t2, ...g} = t1);
$[4] = t1;
$[5] = g;
$[6] = t2;
} else {
g = $[5];
t2 = $[6];
}
const { f } = t2;
const { l: t3, p } = b;
const { m: t4 } = t3;
let o;
let t5;
if ($[7] !== t4) {
[t5, ...o] = t4;
$[7] = t4;
$[8] = o;
$[9] = t5;
} else {
o = $[8];
t5 = $[9];
}
const [n] = t5;
let t6;
if ($[10] !== d || $[11] !== f || $[12] !== g || $[13] !== h || $[14] !== n || $[15] !== o || $[16] !== p) {
t6 = [
d,
f,
g,
h,
n,
o,
p
];
$[10] = d;
$[11] = f;
$[12] = g;
$[13] = h;
$[14] = n;
$[15] = o;
$[16] = p;
$[17] = t6;
} else {
t6 = $[17];
}
return t6;
}
export const FIXTURE_ENTRYPOINT = {
fn: foo,
params: ["TodoAdd"],
@@ -2,7 +2,37 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/escape-analysis-destructured-rest-element.js
---
function Component() {}
import { c as _c } from "react/compiler-runtime";
function Component(props) {
const $ = _c(7);
let b;
if ($[0] !== props.a) {
const { a, ...t0 } = props.a;
b = t0;
$[0] = props.a;
$[1] = b;
} else {
b = $[1];
}
let d;
if ($[2] !== props.c) {
[, ...d] = props.c;
$[2] = props.c;
$[3] = d;
} else {
d = $[3];
}
let t0;
if ($[4] !== b || $[5] !== d) {
t0 = <div b={b} d={d} />;
$[4] = b;
$[5] = d;
$[6] = t0;
} else {
t0 = $[6];
}
return t0;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: ["TodoAdd"],
@@ -2,8 +2,29 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/new-mutability/ssa-renaming-ternary-destruction.js
---
import { c as _c } from "react/compiler-runtime";
// @enablePropagateDepsInHIR @enableNewMutationAliasingModel
function useFoo() {}
function useFoo(props) {
const $ = _c(5);
let x;
if ($[0] !== props.bar) {
x = [];
x.push(props.bar);
$[0] = props.bar;
$[1] = x;
} else {
x = $[1];
}
if ($[2] !== props.cond || $[3] !== props.foo) {
props.cond ? ([x] = [[]], x.push(props.foo)) : null;
$[2] = props.cond;
$[3] = props.foo;
$[4] = x;
} else {
x = $[4];
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{
@@ -2,8 +2,35 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/nonmutated-spread-hook-return.js
---
import { c as _c } from "react/compiler-runtime";
import { identity, Stringify, useIdentity } from "shared-runtime";
function Component() {}
function Component(props) {
const $ = _c(6);
const t0 = useIdentity(props);
let rest;
let x;
if ($[0] !== t0) {
({x, ...rest} = t0);
$[0] = t0;
$[1] = rest;
$[2] = x;
} else {
rest = $[1];
x = $[2];
}
const z = rest.z;
identity(z);
let t1;
if ($[3] !== x || $[4] !== z) {
t1 = <Stringify x={x} z={z} />;
$[3] = x;
$[4] = z;
$[5] = t1;
} else {
t1 = $[5];
}
return t1;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{
@@ -2,8 +2,32 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/nonmutated-spread-props-jsx.js
---
import { c as _c } from "react/compiler-runtime";
import { identity, Stringify } from "shared-runtime";
function Component() {}
function Component(t0) {
const $ = _c(6);
let rest;
let x;
if ($[0] !== t0) {
({x, ...rest} = t0);
$[0] = t0;
$[1] = rest;
$[2] = x;
} else {
rest = $[1];
x = $[2];
}
let t1;
if ($[3] !== rest || $[4] !== x) {
t1 = <Stringify {...rest} x={x} />;
$[3] = rest;
$[4] = x;
$[5] = t1;
} else {
t1 = $[5];
}
return t1;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{
@@ -2,8 +2,35 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/nonmutated-spread-props-local-indirection.js
---
import { c as _c } from "react/compiler-runtime";
import { identity, Stringify } from "shared-runtime";
function Component() {}
function Component(t0) {
const $ = _c(6);
let rest;
let x;
if ($[0] !== t0) {
({x, ...rest} = t0);
$[0] = t0;
$[1] = rest;
$[2] = x;
} else {
rest = $[1];
x = $[2];
}
const restAlias = rest;
const z = restAlias.z;
identity(z);
let t1;
if ($[3] !== x || $[4] !== z) {
t1 = <Stringify x={x} z={z} />;
$[3] = x;
$[4] = z;
$[5] = t1;
} else {
t1 = $[5];
}
return t1;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{
@@ -2,8 +2,34 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/nonmutated-spread-props.js
---
import { c as _c } from "react/compiler-runtime";
import { identity, Stringify } from "shared-runtime";
function Component() {}
function Component(t0) {
const $ = _c(6);
let rest;
let x;
if ($[0] !== t0) {
({x, ...rest} = t0);
$[0] = t0;
$[1] = rest;
$[2] = x;
} else {
rest = $[1];
x = $[2];
}
const z = rest.z;
identity(z);
let t1;
if ($[3] !== x || $[4] !== z) {
t1 = <Stringify x={x} z={z} />;
$[3] = x;
$[4] = z;
$[5] = t1;
} else {
t1 = $[5];
}
return t1;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{
@@ -2,9 +2,26 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/propagate-scope-deps-hir-fork/ssa-renaming-ternary-destruction-with-mutation.js
---
import { c as _c } from "react/compiler-runtime";
// @enablePropagateDepsInHIR
import { mutate } from "shared-runtime";
function useFoo() {}
function useFoo(props) {
const $ = _c(4);
let x;
if ($[0] !== props.bar || $[1] !== props.cond || $[2] !== props.foo) {
x = [];
x.push(props.bar);
props.cond ? ([x] = [[]], x.push(props.foo)) : null;
mutate(x);
$[0] = props.bar;
$[1] = props.cond;
$[2] = props.foo;
$[3] = x;
} else {
x = $[3];
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{
@@ -2,8 +2,29 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/propagate-scope-deps-hir-fork/ssa-renaming-ternary-destruction.js
---
import { c as _c } from "react/compiler-runtime";
// @enablePropagateDepsInHIR
function useFoo() {}
function useFoo(props) {
const $ = _c(5);
let x;
if ($[0] !== props.bar) {
x = [];
x.push(props.bar);
$[0] = props.bar;
$[1] = x;
} else {
x = $[1];
}
if ($[2] !== props.cond || $[3] !== props.foo) {
props.cond ? ([x] = [[]], x.push(props.foo)) : null;
$[2] = props.cond;
$[3] = props.foo;
$[4] = x;
} else {
x = $[4];
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{
@@ -2,9 +2,29 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/propagate-scope-deps-hir-fork/ssa-renaming-via-destructuring-with-mutation.js
---
import { c as _c } from "react/compiler-runtime";
// @enablePropagateDepsInHIR
import { mutate } from "shared-runtime";
function useFoo() {}
function useFoo(props) {
const $ = _c(4);
let x;
if ($[0] !== props.bar || $[1] !== props.cond || $[2] !== props.foo) {
({x} = { x: [] });
x.push(props.bar);
if (props.cond) {
({x} = { x: [] });
x.push(props.foo);
}
mutate(x);
$[0] = props.bar;
$[1] = props.cond;
$[2] = props.foo;
$[3] = x;
} else {
x = $[3];
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{
@@ -2,8 +2,39 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/repro-reassign-props.js
---
import { c as _c } from "react/compiler-runtime";
import { Stringify, useIdentity } from "shared-runtime";
function Component() {}
function Component(t0, ref) {
const $ = _c(7);
let props;
if ($[0] !== t0) {
let { other, ...t1 } = t0;
props = t1;
$[0] = t0;
$[1] = props;
} else {
props = $[1];
}
let t1;
if ($[2] !== props || $[3] !== ref) {
t1 = [props, ref];
$[2] = props;
$[3] = ref;
$[4] = t1;
} else {
t1 = $[4];
}
[props, ref] = useIdentity(t1);
let t2;
if ($[5] !== props) {
t2 = <Stringify props={props} />;
$[5] = props;
$[6] = t2;
} else {
t2 = $[6];
}
return t2;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{
@@ -2,8 +2,25 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/ssa-renaming-ternary-destruction-with-mutation.js
---
import { c as _c } from "react/compiler-runtime";
import { mutate } from "shared-runtime";
function useFoo() {}
function useFoo(props) {
const $ = _c(4);
let x;
if ($[0] !== props.bar || $[1] !== props.cond || $[2] !== props.foo) {
x = [];
x.push(props.bar);
props.cond ? ([x] = [[]], x.push(props.foo)) : null;
mutate(x);
$[0] = props.bar;
$[1] = props.cond;
$[2] = props.foo;
$[3] = x;
} else {
x = $[3];
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{
@@ -2,7 +2,28 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/ssa-renaming-ternary-destruction.js
---
function useFoo() {}
import { c as _c } from "react/compiler-runtime";
function useFoo(props) {
const $ = _c(5);
let x;
if ($[0] !== props.bar) {
x = [];
x.push(props.bar);
$[0] = props.bar;
$[1] = x;
} else {
x = $[1];
}
if ($[2] !== props.cond || $[3] !== props.foo) {
props.cond ? ([x] = [[]], x.push(props.foo)) : null;
$[2] = props.cond;
$[3] = props.foo;
$[4] = x;
} else {
x = $[4];
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{
@@ -2,8 +2,28 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/ssa-renaming-via-destructuring-with-mutation.js
---
import { c as _c } from "react/compiler-runtime";
import { mutate } from "shared-runtime";
function useFoo() {}
function useFoo(props) {
const $ = _c(4);
let x;
if ($[0] !== props.bar || $[1] !== props.cond || $[2] !== props.foo) {
({x} = { x: [] });
x.push(props.bar);
if (props.cond) {
({x} = { x: [] });
x.push(props.foo);
}
mutate(x);
$[0] = props.bar;
$[1] = props.cond;
$[2] = props.foo;
$[3] = x;
} else {
x = $[3];
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{
@@ -2,7 +2,30 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/ssa-renaming-via-destructuring.js
---
function foo() {}
import { c as _c } from "react/compiler-runtime";
function foo(props) {
const $ = _c(4);
let x;
if ($[0] !== props.bar) {
({x} = { x: [] });
x.push(props.bar);
$[0] = props.bar;
$[1] = x;
} else {
x = $[1];
}
if (props.cond) {
if ($[2] !== props.foo) {
({x} = { x: [] });
x.push(props.foo);
$[2] = props.foo;
$[3] = x;
} else {
x = $[3];
}
}
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: foo,
params: ["TodoAdd"],
@@ -2,8 +2,35 @@
source: crates/oxc_react_compiler/tests/snapshot.rs
input_file: crates/oxc_react_compiler/fixtures/switch-with-only-default.js
---
import { c as _c } from "react/compiler-runtime";
import { Stringify } from "shared-runtime";
function Component() {}
function Component(t0) {
const $ = _c(5);
let kind;
let props;
if ($[0] !== t0) {
({kind, ...props} = t0);
$[0] = t0;
$[1] = kind;
$[2] = props;
} else {
kind = $[1];
props = $[2];
}
switch (kind) {
default: {
let t1;
if ($[3] !== props) {
t1 = <Stringify {...props} />;
$[3] = props;
$[4] = t1;
} else {
t1 = $[4];
}
return t1;
}
}
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{