mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[hir] Add support for string literal property keys
Mostly reuses existing analysis of an identifier property key. Adds a new type field to ObjectProperty to propogate the type of the key. This is used in codegen to correctly emit a string literal or an identifier.
This commit is contained in:
@@ -967,6 +967,33 @@ function lowerStatement(
|
||||
}
|
||||
}
|
||||
|
||||
function lowerObjectPropertyKey(
|
||||
builder: HIRBuilder,
|
||||
key: t.PrivateName | t.Expression
|
||||
): { name: string; type: "string" | "identifier" } | null {
|
||||
if (key.type === "Identifier") {
|
||||
return {
|
||||
name: key.name,
|
||||
type: "identifier",
|
||||
};
|
||||
}
|
||||
|
||||
if (key.type === "StringLiteral") {
|
||||
return {
|
||||
name: key.value,
|
||||
type: "string",
|
||||
};
|
||||
}
|
||||
|
||||
builder.errors.push({
|
||||
reason: `(BuildHIR::lowerExpression) Expected Identifier, got ${key.type} key in ObjectExpression`,
|
||||
severity: ErrorSeverity.Todo,
|
||||
loc: key.loc ?? null,
|
||||
suggestions: null,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
function lowerExpression(
|
||||
builder: HIRBuilder,
|
||||
exprPath: NodePath<t.Expression>
|
||||
@@ -1009,19 +1036,11 @@ function lowerExpression(
|
||||
const properties: Array<ObjectProperty | SpreadPattern> = [];
|
||||
for (const propertyPath of propertyPaths) {
|
||||
if (propertyPath.isObjectProperty()) {
|
||||
const key = propertyPath.node.key;
|
||||
let keyName: string;
|
||||
if (key.type === "Identifier") {
|
||||
keyName = key.name;
|
||||
} else if (key.type === "StringLiteral") {
|
||||
keyName = key.value;
|
||||
} else {
|
||||
builder.errors.push({
|
||||
reason: `(BuildHIR::lowerExpression) Expected Identifier, got ${key.type} key in ObjectExpression`,
|
||||
severity: ErrorSeverity.Todo,
|
||||
loc: propertyPath.node.loc ?? null,
|
||||
suggestions: null,
|
||||
});
|
||||
const loweredKey = lowerObjectPropertyKey(
|
||||
builder,
|
||||
propertyPath.node.key
|
||||
);
|
||||
if (!loweredKey) {
|
||||
continue;
|
||||
}
|
||||
const valuePath = propertyPath.get("value");
|
||||
@@ -1037,8 +1056,8 @@ function lowerExpression(
|
||||
const value = lowerExpressionToTemporary(builder, valuePath);
|
||||
properties.push({
|
||||
kind: "ObjectProperty",
|
||||
name: keyName,
|
||||
place: value,
|
||||
...loweredKey,
|
||||
});
|
||||
} else if (propertyPath.isSpreadElement()) {
|
||||
const place = lowerExpressionToTemporary(
|
||||
@@ -2800,14 +2819,8 @@ function lowerAssignment(
|
||||
});
|
||||
continue;
|
||||
}
|
||||
const key = property.get("key");
|
||||
if (!key.isIdentifier()) {
|
||||
builder.errors.push({
|
||||
reason: `(BuildHIR::lowerAssignment) Handle ${key.type} keys in ObjectPattern`,
|
||||
severity: ErrorSeverity.Todo,
|
||||
loc: key.node.loc ?? null,
|
||||
suggestions: null,
|
||||
});
|
||||
const loweredKey = lowerObjectPropertyKey(builder, property.node.key);
|
||||
if (!loweredKey) {
|
||||
continue;
|
||||
}
|
||||
const element = property.get("value");
|
||||
@@ -2832,8 +2845,8 @@ function lowerAssignment(
|
||||
}
|
||||
properties.push({
|
||||
kind: "ObjectProperty",
|
||||
name: key.node.name,
|
||||
place: identifier,
|
||||
...loweredKey,
|
||||
});
|
||||
} else {
|
||||
const temp = buildTemporaryPlace(
|
||||
@@ -2842,8 +2855,8 @@ function lowerAssignment(
|
||||
);
|
||||
properties.push({
|
||||
kind: "ObjectProperty",
|
||||
name: key.node.name,
|
||||
place: { ...temp },
|
||||
...loweredKey,
|
||||
});
|
||||
followups.push({ place: temp, path: element as NodePath<t.LVal> }); // TODO remove type cast
|
||||
}
|
||||
|
||||
@@ -501,6 +501,7 @@ export type ObjectPattern = {
|
||||
|
||||
export type ObjectProperty = {
|
||||
kind: "ObjectProperty";
|
||||
type: "string" | "identifier";
|
||||
name: string; // TODO: make a Place
|
||||
place: Place;
|
||||
};
|
||||
|
||||
+16
-4
@@ -16,6 +16,7 @@ import {
|
||||
IdentifierId,
|
||||
InstructionKind,
|
||||
JsxAttribute,
|
||||
ObjectProperty,
|
||||
Pattern,
|
||||
Place,
|
||||
ReactiveBlock,
|
||||
@@ -898,14 +899,14 @@ function codegenInstructionValue(
|
||||
const properties = [];
|
||||
for (const property of instrValue.properties) {
|
||||
if (property.kind === "ObjectProperty") {
|
||||
const key = t.identifier(property.name);
|
||||
const key = codegenObjectPropertyKey(property);
|
||||
const value = codegenPlace(cx, property.place);
|
||||
properties.push(
|
||||
t.objectProperty(
|
||||
key,
|
||||
value,
|
||||
false,
|
||||
value.type === "Identifier" && value.name === key.name
|
||||
value.type === "Identifier" && value.name === property.name
|
||||
)
|
||||
);
|
||||
} else {
|
||||
@@ -1310,6 +1311,17 @@ function convertMemberExpressionToJsx(
|
||||
}
|
||||
}
|
||||
|
||||
function codegenObjectPropertyKey(
|
||||
property: ObjectProperty
|
||||
): t.StringLiteral | t.Identifier {
|
||||
switch (property.type) {
|
||||
case "identifier":
|
||||
return t.identifier(property.name);
|
||||
case "string":
|
||||
return t.stringLiteral(property.name);
|
||||
}
|
||||
}
|
||||
|
||||
function codegenLValue(
|
||||
pattern: Pattern | Place | SpreadPattern
|
||||
): t.ArrayPattern | t.ObjectPattern | t.RestElement | t.Identifier {
|
||||
@@ -1328,13 +1340,13 @@ function codegenLValue(
|
||||
return t.objectPattern(
|
||||
pattern.properties.map((property) => {
|
||||
if (property.kind === "ObjectProperty") {
|
||||
const key = t.identifier(property.name);
|
||||
const key = codegenObjectPropertyKey(property);
|
||||
const value = codegenLValue(property.place);
|
||||
return t.objectProperty(
|
||||
key,
|
||||
value,
|
||||
false,
|
||||
value.type === "Identifier" && value.name === key.name
|
||||
value.type === "Identifier" && value.name === property.name
|
||||
);
|
||||
} else {
|
||||
return t.restElement(codegenLValue(property.place));
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
const {
|
||||
"data-foo-bar": x,
|
||||
a: y,
|
||||
data: z,
|
||||
} = { "data-foo-bar": 1, a: 2, data: 3 };
|
||||
return [x, y, z];
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: foo,
|
||||
params: [],
|
||||
isComponent: false,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react";
|
||||
function foo() {
|
||||
const $ = useMemoCache(2);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = { "data-foo-bar": 1, a: 2, data: 3 };
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
const { "data-foo-bar": x, a: y, data: z } = t0;
|
||||
let t1;
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = [x, y, z];
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: foo,
|
||||
params: [],
|
||||
isComponent: false,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
function foo() {
|
||||
const {
|
||||
"data-foo-bar": x,
|
||||
a: y,
|
||||
data: z,
|
||||
} = { "data-foo-bar": 1, a: 2, data: 3 };
|
||||
return [x, y, z];
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: foo,
|
||||
params: [],
|
||||
isComponent: false,
|
||||
};
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo({ "data-foo-bar": dataTestID }) {
|
||||
return dataTestID;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: foo,
|
||||
params: [{ "data-foo-bar": {} }],
|
||||
isComponent: false,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function foo(t5) {
|
||||
const { "data-foo-bar": dataTestID } = t5;
|
||||
return dataTestID;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: foo,
|
||||
params: [{ "data-foo-bar": {} }],
|
||||
isComponent: false,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
function foo({ "data-foo-bar": dataTestID }) {
|
||||
return dataTestID;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: foo,
|
||||
params: [{ "data-foo-bar": {} }],
|
||||
isComponent: false,
|
||||
};
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo({ data: dataTestID }) {
|
||||
return dataTestID;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: foo,
|
||||
params: [{ data: {} }],
|
||||
isComponent: false,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function foo(t5) {
|
||||
const { data: dataTestID } = t5;
|
||||
return dataTestID;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: foo,
|
||||
params: [{ data: {} }],
|
||||
isComponent: false,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
function foo({ data: dataTestID }) {
|
||||
return dataTestID;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: foo,
|
||||
params: [{ data: {} }],
|
||||
isComponent: false,
|
||||
};
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
const { "data-foo-bar": t } = { "data-foo-bar": 1 };
|
||||
return t;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: foo,
|
||||
params: [],
|
||||
isComponent: false,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react";
|
||||
function foo() {
|
||||
const $ = useMemoCache(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = { "data-foo-bar": 1 };
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
const { "data-foo-bar": t } = t0;
|
||||
return t;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: foo,
|
||||
params: [],
|
||||
isComponent: false,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
function foo() {
|
||||
const { "data-foo-bar": t } = { "data-foo-bar": 1 };
|
||||
return t;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: foo,
|
||||
params: [],
|
||||
isComponent: false,
|
||||
};
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
const { data: t } = { data: 1 };
|
||||
return t;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: foo,
|
||||
params: [],
|
||||
isComponent: false,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react";
|
||||
function foo() {
|
||||
const $ = useMemoCache(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = { data: 1 };
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
const { data: t } = t0;
|
||||
return t;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: foo,
|
||||
params: [],
|
||||
isComponent: false,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
function foo() {
|
||||
const { data: t } = { data: 1 };
|
||||
return t;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: foo,
|
||||
params: [],
|
||||
isComponent: false,
|
||||
};
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Foo() {
|
||||
return {
|
||||
"a.b": 1,
|
||||
"a\b": 2,
|
||||
"a/b": 3,
|
||||
"a+b": 4,
|
||||
"a b": 5,
|
||||
};
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [],
|
||||
isComponent: false,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
Unexpected token, expected "," (2:13)
|
||||
1 | import { unstable_useMemoCache as useMemoCache } from "react";function Foo() {const $ = useMemoCache(1);let t0;if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
> 2 | t0 = { a.b: 1, a: 2, a/b: 3, a+b: 4, a b: 5 };$[0] = t0;} else {t0 = $[0];}return t0;}
|
||||
| ^
|
||||
3 |
|
||||
4 |
|
||||
5 |
|
||||
```
|
||||
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Foo() {
|
||||
return {
|
||||
"a.b": 1,
|
||||
"a\b": 2,
|
||||
"a/b": 3,
|
||||
"a+b": 4,
|
||||
"a b": 5,
|
||||
};
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [],
|
||||
isComponent: false,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react";
|
||||
function Foo() {
|
||||
const $ = useMemoCache(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = { "a.b": 1, "a\b": 2, "a/b": 3, "a+b": 4, "a b": 5 };
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [],
|
||||
isComponent: false,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user