mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
PropertyDelete/ComputedDelete instructions
This commit is contained in:
@@ -1560,12 +1560,41 @@ function lowerExpression(
|
||||
}
|
||||
case "UnaryExpression": {
|
||||
let expr = exprPath as NodePath<t.UnaryExpression>;
|
||||
return {
|
||||
kind: "UnaryExpression",
|
||||
operator: expr.node.operator,
|
||||
value: lowerExpressionToTemporary(builder, expr.get("argument")),
|
||||
loc: exprLoc,
|
||||
};
|
||||
if (expr.node.operator === "delete") {
|
||||
const argument = expr.get("argument");
|
||||
if (argument.isMemberExpression()) {
|
||||
const { object, property } = lowerMemberExpression(builder, argument);
|
||||
if (typeof property === "string") {
|
||||
return {
|
||||
kind: "PropertyDelete",
|
||||
object,
|
||||
property,
|
||||
loc: exprLoc,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
kind: "ComputedDelete",
|
||||
object,
|
||||
property,
|
||||
loc: exprLoc,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
builder.errors.push({
|
||||
reason: `(BuildHIR::lowerExpression) delete on a non-member expression has no semantic meaning`,
|
||||
severity: ErrorSeverity.InvalidInput,
|
||||
nodePath: expr,
|
||||
});
|
||||
return { kind: "UnsupportedNode", node: expr.node, loc: exprLoc };
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
kind: "UnaryExpression",
|
||||
operator: expr.node.operator,
|
||||
value: lowerExpressionToTemporary(builder, expr.get("argument")),
|
||||
loc: exprLoc,
|
||||
};
|
||||
}
|
||||
}
|
||||
case "TypeCastExpression": {
|
||||
let expr = exprPath as NodePath<t.TypeCastExpression>;
|
||||
|
||||
@@ -544,6 +544,13 @@ export type InstructionValue =
|
||||
optional: boolean;
|
||||
loc: SourceLocation;
|
||||
}
|
||||
// `delete object.property`
|
||||
| {
|
||||
kind: "PropertyDelete";
|
||||
object: Place;
|
||||
property: string;
|
||||
loc: SourceLocation;
|
||||
}
|
||||
|
||||
// store `object[index] = value` - like PropertyStore but with a dynamic property
|
||||
| {
|
||||
@@ -560,6 +567,13 @@ export type InstructionValue =
|
||||
property: Place;
|
||||
loc: SourceLocation;
|
||||
}
|
||||
// `delete object[property]`
|
||||
| {
|
||||
kind: "ComputedDelete";
|
||||
object: Place;
|
||||
property: Place;
|
||||
loc: SourceLocation;
|
||||
}
|
||||
| { kind: "LoadGlobal"; name: string; loc: SourceLocation }
|
||||
| FunctionExpression
|
||||
| {
|
||||
|
||||
@@ -351,6 +351,12 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
|
||||
} = ${printPlace(instrValue.value)}`;
|
||||
break;
|
||||
}
|
||||
case "PropertyDelete": {
|
||||
value = `PropertyDelete ${printPlace(instrValue.object)}.${
|
||||
instrValue.property
|
||||
}`;
|
||||
break;
|
||||
}
|
||||
case "ComputedLoad": {
|
||||
value = `ComputedLoad ${printPlace(instrValue.object)}[${printPlace(
|
||||
instrValue.property
|
||||
@@ -363,6 +369,12 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
|
||||
)}] = ${printPlace(instrValue.value)}`;
|
||||
break;
|
||||
}
|
||||
case "ComputedDelete": {
|
||||
value = `ComputedDelete ${printPlace(instrValue.object)}[${printPlace(
|
||||
instrValue.property
|
||||
)}]`;
|
||||
break;
|
||||
}
|
||||
case "FunctionExpression": {
|
||||
const fn = printFunction(instrValue.loweredFunc)
|
||||
.split("\n")
|
||||
|
||||
@@ -80,6 +80,10 @@ export function* eachInstructionValueOperand(
|
||||
yield instrValue.object;
|
||||
break;
|
||||
}
|
||||
case "PropertyDelete": {
|
||||
yield instrValue.object;
|
||||
break;
|
||||
}
|
||||
case "PropertyStore": {
|
||||
yield instrValue.object;
|
||||
yield instrValue.value;
|
||||
@@ -90,6 +94,11 @@ export function* eachInstructionValueOperand(
|
||||
yield instrValue.property;
|
||||
break;
|
||||
}
|
||||
case "ComputedDelete": {
|
||||
yield instrValue.object;
|
||||
yield instrValue.property;
|
||||
break;
|
||||
}
|
||||
case "ComputedStore": {
|
||||
yield instrValue.object;
|
||||
yield instrValue.property;
|
||||
@@ -254,6 +263,10 @@ export function mapInstructionOperands(
|
||||
instrValue.object = fn(instrValue.object);
|
||||
break;
|
||||
}
|
||||
case "PropertyDelete": {
|
||||
instrValue.object = fn(instrValue.object);
|
||||
break;
|
||||
}
|
||||
case "PropertyStore": {
|
||||
instrValue.object = fn(instrValue.object);
|
||||
instrValue.value = fn(instrValue.value);
|
||||
@@ -264,6 +277,11 @@ export function mapInstructionOperands(
|
||||
instrValue.property = fn(instrValue.property);
|
||||
break;
|
||||
}
|
||||
case "ComputedDelete": {
|
||||
instrValue.object = fn(instrValue.object);
|
||||
instrValue.property = fn(instrValue.property);
|
||||
break;
|
||||
}
|
||||
case "ComputedStore": {
|
||||
instrValue.object = fn(instrValue.object);
|
||||
instrValue.property = fn(instrValue.property);
|
||||
|
||||
@@ -716,6 +716,12 @@ function inferBlock(
|
||||
lvalue.effect = Effect.Store;
|
||||
continue;
|
||||
}
|
||||
case "PropertyDelete": {
|
||||
// `delete` returns a boolean (immutable) and modifies the object
|
||||
valueKind = ValueKind.Immutable;
|
||||
effectKind = Effect.Mutate;
|
||||
break;
|
||||
}
|
||||
case "PropertyLoad": {
|
||||
if (!state.isDefined(instrValue.object)) {
|
||||
// TODO @josephsavona: improve handling of globals
|
||||
@@ -749,6 +755,13 @@ function inferBlock(
|
||||
lvalue.effect = Effect.Store;
|
||||
continue;
|
||||
}
|
||||
case "ComputedDelete": {
|
||||
state.reference(instrValue.object, Effect.Mutate);
|
||||
state.reference(instrValue.property, Effect.Read);
|
||||
state.initialize(instrValue, ValueKind.Immutable);
|
||||
state.reference(instr.lvalue, Effect.Mutate);
|
||||
continue;
|
||||
}
|
||||
case "ComputedLoad": {
|
||||
if (!state.isDefined(instrValue.object)) {
|
||||
// TODO @josephsavona: improve handling of globals
|
||||
|
||||
@@ -175,8 +175,10 @@ function pruneableValue(
|
||||
return true;
|
||||
}
|
||||
case "CallExpression":
|
||||
case "ComputedDelete":
|
||||
case "ComputedCall":
|
||||
case "ComputedStore":
|
||||
case "PropertyDelete":
|
||||
case "PropertyCall":
|
||||
case "PropertyStore": {
|
||||
// Mutating instructions are not safe to prune.
|
||||
|
||||
@@ -711,6 +711,16 @@ function codegenInstructionValue(
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PropertyDelete": {
|
||||
value = t.unaryExpression(
|
||||
"delete",
|
||||
t.memberExpression(
|
||||
codegenPlace(cx, instrValue.object),
|
||||
t.identifier(instrValue.property)
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "ComputedStore": {
|
||||
value = t.assignmentExpression(
|
||||
"=",
|
||||
@@ -731,6 +741,17 @@ function codegenInstructionValue(
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "ComputedDelete": {
|
||||
value = t.unaryExpression(
|
||||
"delete",
|
||||
t.memberExpression(
|
||||
codegenPlace(cx, instrValue.object),
|
||||
codegenPlace(cx, instrValue.property),
|
||||
true
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "LoadLocal": {
|
||||
value = codegenPlace(cx, instrValue.place);
|
||||
break;
|
||||
|
||||
@@ -205,7 +205,9 @@ function mayAllocate(value: InstructionValue): boolean {
|
||||
case "BinaryExpression":
|
||||
case "LoadLocal":
|
||||
case "PropertyLoad":
|
||||
case "PropertyDelete":
|
||||
case "ComputedLoad":
|
||||
case "ComputedDelete":
|
||||
case "JSXText":
|
||||
case "UnaryExpression":
|
||||
case "TemplateLiteral":
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Component(props) {
|
||||
const x = { a: props.a, b: props.b };
|
||||
const key = "b";
|
||||
delete x[key];
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function Component(props) {
|
||||
const $ = React.unstable_useMemoCache(3);
|
||||
const c_0 = $[0] !== props.a;
|
||||
const c_1 = $[1] !== props.b;
|
||||
let x;
|
||||
if (c_0 || c_1) {
|
||||
x = { a: props.a, b: props.b };
|
||||
delete x["b"];
|
||||
$[0] = props.a;
|
||||
$[1] = props.b;
|
||||
$[2] = x;
|
||||
} else {
|
||||
x = $[2];
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
function Component(props) {
|
||||
const x = { a: props.a, b: props.b };
|
||||
const key = "b";
|
||||
delete x[key];
|
||||
return x;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Component(props) {
|
||||
const x = { a: props.a, b: props.b };
|
||||
delete x.b;
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function Component(props) {
|
||||
const $ = React.unstable_useMemoCache(3);
|
||||
const c_0 = $[0] !== props.a;
|
||||
const c_1 = $[1] !== props.b;
|
||||
let x;
|
||||
if (c_0 || c_1) {
|
||||
x = { a: props.a, b: props.b };
|
||||
delete x.b;
|
||||
$[0] = props.a;
|
||||
$[1] = props.b;
|
||||
$[2] = x;
|
||||
} else {
|
||||
x = $[2];
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
function Component(props) {
|
||||
const x = { a: props.a, b: props.b };
|
||||
delete x.b;
|
||||
return x;
|
||||
}
|
||||
@@ -20,44 +20,56 @@ function component(a) {
|
||||
|
||||
```javascript
|
||||
function component(a) {
|
||||
const $ = React.unstable_useMemoCache(10);
|
||||
const $ = React.unstable_useMemoCache(14);
|
||||
const c_0 = $[0] !== a;
|
||||
let t0;
|
||||
let t;
|
||||
let z;
|
||||
let p;
|
||||
let q;
|
||||
if (c_0) {
|
||||
t0 = { t: a };
|
||||
t = { t: a };
|
||||
z = +t.t;
|
||||
q = -t.t;
|
||||
p = void t.t;
|
||||
t0 = delete t.t;
|
||||
$[0] = a;
|
||||
$[1] = t0;
|
||||
$[2] = t;
|
||||
$[3] = z;
|
||||
$[4] = p;
|
||||
$[5] = q;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
t = $[2];
|
||||
z = $[3];
|
||||
p = $[4];
|
||||
q = $[5];
|
||||
}
|
||||
const t = t0;
|
||||
const z = +t.t;
|
||||
const q = -t.t;
|
||||
const p = void t.t;
|
||||
const n = delete t.t;
|
||||
const n = t0;
|
||||
const m = !t.t;
|
||||
const e = ~t.t;
|
||||
const f = typeof t.t;
|
||||
const c_2 = $[2] !== z;
|
||||
const c_3 = $[3] !== p;
|
||||
const c_4 = $[4] !== q;
|
||||
const c_5 = $[5] !== n;
|
||||
const c_6 = $[6] !== m;
|
||||
const c_7 = $[7] !== e;
|
||||
const c_8 = $[8] !== f;
|
||||
const c_6 = $[6] !== z;
|
||||
const c_7 = $[7] !== p;
|
||||
const c_8 = $[8] !== q;
|
||||
const c_9 = $[9] !== n;
|
||||
const c_10 = $[10] !== m;
|
||||
const c_11 = $[11] !== e;
|
||||
const c_12 = $[12] !== f;
|
||||
let t1;
|
||||
if (c_2 || c_3 || c_4 || c_5 || c_6 || c_7 || c_8) {
|
||||
if (c_6 || c_7 || c_8 || c_9 || c_10 || c_11 || c_12) {
|
||||
t1 = { z, p, q, n, m, e, f };
|
||||
$[2] = z;
|
||||
$[3] = p;
|
||||
$[4] = q;
|
||||
$[5] = n;
|
||||
$[6] = m;
|
||||
$[7] = e;
|
||||
$[8] = f;
|
||||
$[9] = t1;
|
||||
$[6] = z;
|
||||
$[7] = p;
|
||||
$[8] = q;
|
||||
$[9] = n;
|
||||
$[10] = m;
|
||||
$[11] = e;
|
||||
$[12] = f;
|
||||
$[13] = t1;
|
||||
} else {
|
||||
t1 = $[9];
|
||||
t1 = $[13];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user