Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2396,6 +2396,57 @@ function lowerExpression(
case 'UpdateExpression': {
let expr = exprPath as NodePath<t.UpdateExpression>;
const argument = expr.get('argument');
if (argument.isMemberExpression()) {
const binaryOperator = expr.node.operator === '++' ? '+' : '-';
const leftExpr = argument as NodePath<t.MemberExpression>;
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,
};
Comment on lines +2442 to +2448
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fine, but we try to avoid using lvalues more than once. The main exception is for method calls, where we evaluate the receiver to an lvalue, then use that lvalue to load the property for the method and again as the receiver of the method call instruction.

To test, can you add some fixtures where the increment/decrement is used as an rvalue? let x = obj.x++ and (obj.x++).toString()

}
if (!argument.isIdentifier()) {
builder.errors.push({
reason: `(BuildHIR::lowerExpression) Handle UpdateExpression with ${argument.type} argument`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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]
Original file line number Diff line number Diff line change
@@ -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: [],
};