[hir] Allow reorderable exprs in optional computed load

This commit is contained in:
Mofei Zhang
2023-03-31 10:58:28 -04:00
parent c77c1b1644
commit 8dfe06ddba
8 changed files with 65 additions and 23 deletions
+21 -12
View File
@@ -1680,9 +1680,11 @@ function lowerExpression(
}
/**
* There are a few places where we do not preserve original evaluation ordering, such as switch case test values
* and default values in destructuring (assignment patterns). In these cases we allow simple expressions whose
* evaluation cannot be observed: primitives and arrays/objects whose values are also safely reorderable.
* There are a few places where we do not preserve original evaluation ordering and/or control flow, such as
* switch case test values and default values in destructuring (assignment patterns). In these cases we allow
* simple expressions whose evaluation cannot be observed:
* - primitives
* - arrays/objects whose values are also safely reorderable.
*/
function lowerReorderableExpression(
builder: HIRBuilder,
@@ -1864,21 +1866,28 @@ function lowerMemberExpression(
},
};
}
if (t.isOptionalMemberExpression(expr)) {
builder.errors.push({
reason: `(BuildHIR::lowerMemberExpression) Handle computed OptionalMemberExpression`,
severity: ErrorSeverity.Todo,
nodePath: expr,
});
let optional;
let property: Place;
// See "PropertyLoad" for the difference between optionalMemberExpr()
// and node.optional here
if (expr.isOptionalMemberExpression()) {
// if expr is in an optional chain, evaluation of `property` is
// conditional on whether expr is nullish
property = lowerReorderableExpression(builder, propertyNode);
optional = expr.node.optional ?? false;
} else {
property = lowerExpressionToTemporary(builder, propertyNode);
optional = false;
}
const propertyPlace = lowerExpressionToTemporary(builder, propertyNode);
const value: InstructionValue = {
kind: "ComputedLoad",
object: { ...object },
property: { ...propertyPlace },
property: { ...property },
loc: exprLoc,
optional,
};
return { object, property: propertyPlace, value };
return { object, property, value };
}
}
+1
View File
@@ -609,6 +609,7 @@ export type InstructionValue =
kind: "ComputedLoad";
object: Place;
property: Place;
optional: boolean;
loc: SourceLocation;
}
// `delete object[property]`
+3 -3
View File
@@ -367,9 +367,9 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
break;
}
case "ComputedLoad": {
value = `ComputedLoad ${printPlace(instrValue.object)}[${printPlace(
instrValue.property
)}]`;
value = `ComputedLoad ${printPlace(instrValue.object)}${
instrValue.optional ? "?" : ""
}[${printPlace(instrValue.property)}]`;
break;
}
case "ComputedStore": {
@@ -160,7 +160,7 @@ function evaluateInstruction(
loc: value.loc,
property: property.value,
object: value.object,
optional: false,
optional: value.optional,
};
// Future-proofing: when we add support for optional computed properties,
// we'll need to copy the value here
@@ -795,11 +795,18 @@ function codegenInstructionValue(
break;
}
case "ComputedLoad": {
value = t.memberExpression(
codegenPlace(cx, instrValue.object),
codegenPlace(cx, instrValue.property),
true
);
const object = codegenPlace(cx, instrValue.object);
const property = codegenPlace(cx, instrValue.property);
if (t.isOptionalMemberExpression(object) || instrValue.optional) {
value = t.optionalMemberExpression(
object,
property,
true,
instrValue.optional
);
} else {
value = t.memberExpression(object, property, true, instrValue.optional);
}
break;
}
case "ComputedDelete": {
@@ -13,11 +13,11 @@ function Component(props) {
## Error
```
[ReactForget] TodoError: (BuildHIR::lowerMemberExpression) Handle computed OptionalMemberExpression
[ReactForget] TodoError: (BuildHIR::node.lowerReorderableExpression) Expression type 'MemberExpression' cannot be safely reordered
1 | function Component(props) {
2 | const object = makeObject(props);
> 3 | return object?.[props.key];
| ^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^
4 | }
5 |
```
@@ -0,0 +1,21 @@
## Input
```javascript
function Component(props) {
let x = a?.b.c[0];
return x;
}
```
## Code
```javascript
function Component(props) {
const x = a?.b.c[0];
return x;
}
```
@@ -0,0 +1,4 @@
function Component(props) {
let x = a?.b.c[0];
return x;
}