diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts index 8ed71b5e62a7e..945a265f487c9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts @@ -2396,6 +2396,57 @@ function lowerExpression( case 'UpdateExpression': { let expr = exprPath as NodePath; const argument = expr.get('argument'); + if (argument.isMemberExpression()) { + const binaryOperator = expr.node.operator === '++' ? '+' : '-'; + const leftExpr = argument as NodePath; + const {object, property, value} = lowerMemberExpression( + builder, + leftExpr, + ); + + // Store the previous value to a temporary + const previousValuePlace = lowerValueToTemporary(builder, value); + // Store the new value to a temporary + const updatedValue = lowerValueToTemporary(builder, { + kind: 'BinaryExpression', + operator: binaryOperator, + left: {...previousValuePlace}, + right: lowerValueToTemporary(builder, { + kind: 'Primitive', + value: 1, + loc: GeneratedSource, + }), + loc: leftExpr.node.loc ?? GeneratedSource, + }); + + // Save the result back to the property + let newValuePlace; + if (typeof property === 'string') { + newValuePlace = lowerValueToTemporary(builder, { + kind: 'PropertyStore', + object: {...object}, + property, + value: {...updatedValue}, + loc: leftExpr.node.loc ?? GeneratedSource, + }); + } else { + newValuePlace = lowerValueToTemporary(builder, { + kind: 'ComputedStore', + object: {...object}, + property: {...property}, + value: {...updatedValue}, + loc: leftExpr.node.loc ?? GeneratedSource, + }); + } + + return { + kind: 'LoadLocal', + place: expr.node.prefix + ? {...newValuePlace} + : {...previousValuePlace}, + loc: exprLoc, + }; + } if (!argument.isIdentifier()) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle UpdateExpression with ${argument.type} argument`, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md index ba32831cbb884..d8360455bb303 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md @@ -104,10 +104,6 @@ Todo: (BuildHIR::lowerStatement) Handle ArrayPattern inits in ForOfStatement (38 Todo: (BuildHIR::lowerStatement) Handle ObjectPattern inits in ForOfStatement (40:40) -Todo: (BuildHIR::lowerExpression) Handle UpdateExpression with MemberExpression argument (49:49) - -Todo: (BuildHIR::lowerExpression) Handle UpdateExpression with MemberExpression argument (50:50) - Todo: (BuildHIR::node.lowerReorderableExpression) Expression type `MemberExpression` cannot be safely reordered (57:57) Todo: (BuildHIR::node.lowerReorderableExpression) Expression type `BinaryExpression` cannot be safely reordered (53:53) diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/member-inc.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/member-inc.expect.md new file mode 100644 index 0000000000000..6588b336b0ee4 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/member-inc.expect.md @@ -0,0 +1,63 @@ + +## Input + +```javascript +//@flow + +component Foo() { + let x = {a: 1}; + x.a++; + x.a--; + console.log(++x.a); + console.log(x.a++); + + console.log(x.a); + let y = x.a++; + console.log(y); + console.log(x.a); + + console.log((++x.a).toString(), (x.a++).toString(), x.a); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [], +}; + +``` + +## Code + +```javascript +function Foo() { + const x = { a: 1 }; + x.a = x.a + 1; + x.a = x.a - 1; + console.log((x.a = x.a + 1)); + const t0 = x.a; + x.a = t0 + 1; + console.log(t0); + + console.log(x.a); + const t1 = x.a; + x.a = t1 + 1; + const y = t1; + console.log(y); + console.log(x.a); + + const t2 = (x.a = x.a + 1).toString(); + const t3 = x.a; + x.a = t3 + 1; + console.log(t2, t3.toString(), x.a); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [], +}; + +``` + +### Eval output +(kind: ok) +logs: [2,2,3,3,4,'5','5',6] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/member-inc.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/member-inc.js new file mode 100644 index 0000000000000..1a662a39ac0f5 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/member-inc.js @@ -0,0 +1,21 @@ +//@flow + +component Foo() { + let x = {a: 1}; + x.a++; + x.a--; + console.log(++x.a); + console.log(x.a++); + + console.log(x.a); + let y = x.a++; + console.log(y); + console.log(x.a); + + console.log((++x.a).toString(), (x.a++).toString(), x.a); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [], +};