Collect bailouts in BuildHIR::lowerAssignment
Lauren Tan committed
Jan 20, 2023 at 11:47 UTC
44beb3c0238994a61ada2c0386a42107d03dc9ac
3 files changed
+172
-100
compiler/forget/src/HIR/BuildHIR.ts
+67
-26
@@ -7,10 +7,8 @@
7
8
import { NodePath, Scope } from "@babel/traverse";
9
import * as t from "@babel/types";
10
-import invariant from "invariant";
10
import { CompilerError, ErrorSeverity } from "../CompilerError";
11
import { Err, Ok, Result } from "../lib/Result";
13
-import todo, { todoInvariant } from "../Utils/todo";
12
import { assertExhaustive } from "../Utils/utils";
13
import {
14
BlockId,
@@ -1724,7 +1722,14 @@ function lowerAssignment(
1722
});
1723
}
1724
if (!lvalue.node.computed) {
1727
- todoInvariant(property.isIdentifier(), "Support private names");
1725
+ if (!property.isIdentifier()) {
1726
+ builder.pushError({
1727
+ reason: "Support private names",
1728
+ severity: ErrorSeverity.Todo,
1729
+ nodePath: property,
1730
+ });
1731
+ return { kind: "UnsupportedNode", node: lvalueNode, loc };
1732
+ }
1733
return {
1734
kind: "PropertyStore",
1735
object,
@@ -1733,10 +1738,15 @@ function lowerAssignment(
1738
loc,
1739
};
1740
} else {
1736
- invariant(
1737
- property.isExpression(),
1738
- "Expected private name to appear as a non-computed property"
1739
- );
1741
+ if (!property.isExpression()) {
1742
+ builder.pushError({
1743
+ reason:
1744
+ "Expected private name to appear as a non-computed property",
1745
+ severity: ErrorSeverity.InvalidInput,
1746
+ nodePath: property,
1747
+ });
1748
+ return { kind: "UnsupportedNode", node: lvalueNode, loc };
1749
+ }
1750
const propertyPlace = lowerExpressionToPlace(builder, property);
1751
return {
1752
kind: "ComputedStore",
@@ -1757,15 +1767,21 @@ function lowerAssignment(
1767
loc,
1768
});
1769
const elements = lvalue.get("elements");
1770
+ let hasError = false;
1771
for (let i = 0; i < elements.length; i++) {
1772
const element = elements[i];
1773
if (!element.hasNode()) {
1774
continue;
1775
}
1765
- todoInvariant(
1766
- element.node.type !== "RestElement",
1767
- "Rest elements are not supported yet"
1768
- );
1776
+ if (element.node.type === "RestElement") {
1777
+ builder.pushError({
1778
+ reason: "Rest elements are not supported yet",
1779
+ severity: ErrorSeverity.Todo,
1780
+ nodePath: element,
1781
+ });
1782
+ hasError = true;
1783
+ continue;
1784
+ }
1785
const property = buildTemporaryPlace(
1786
builder,
1787
element.node.loc ?? GeneratedSource
@@ -1788,7 +1804,9 @@ function lowerAssignment(
1804
};
1805
lowerAssignment(builder, loc, kind, element, value);
1806
}
1791
- return arrayPlace;
1807
+ return hasError
1808
+ ? { kind: "UnsupportedNode", node: lvalueNode, loc }
1809
+ : arrayPlace;
1810
}
1811
case "ObjectPattern": {
1812
const lvalue = lvaluePath as NodePath<t.ObjectPattern>;
@@ -1800,22 +1818,38 @@ function lowerAssignment(
1818
loc,
1819
});
1820
const properties = lvalue.get("properties");
1821
+ let hasError = false;
1822
for (let i = 0; i < properties.length; i++) {
1823
const property = properties[i];
1805
- invariant(
1806
- property.isObjectProperty(),
1807
- "Rest elements are not supported yet"
1808
- );
1824
+ if (!property.isObjectProperty()) {
1825
+ builder.pushError({
1826
+ reason: "Rest elements are not supported yet",
1827
+ severity: ErrorSeverity.Todo,
1828
+ nodePath: property,
1829
+ });
1830
+ hasError = true;
1831
+ continue;
1832
+ }
1833
const key = property.get("key");
1810
- invariant(
1811
- key.isIdentifier(),
1812
- "TODO: support non-identifier object property keys"
1813
- );
1834
+ if (!key.isIdentifier()) {
1835
+ builder.pushError({
1836
+ reason: "Support non-identifier object property keys",
1837
+ severity: ErrorSeverity.Todo,
1838
+ nodePath: key,
1839
+ });
1840
+ hasError = true;
1841
+ continue;
1842
+ }
1843
const element = property.get("value");
1815
- invariant(
1816
- element.isLVal(),
1817
- "Expected object property value to be an lvalue"
1818
- );
1844
+ if (!element.isLVal()) {
1845
+ builder.pushError({
1846
+ reason: "Expected object property value to be an lvalue",
1847
+ severity: ErrorSeverity.InvalidInput,
1848
+ nodePath: element,
1849
+ });
1850
+ hasError = true;
1851
+ continue;
1852
+ }
1853
const value: InstructionValue = {
1854
kind: "PropertyLoad",
1855
loc,
@@ -1824,10 +1858,17 @@ function lowerAssignment(
1858
};
1859
lowerAssignment(builder, loc, kind, element, value);
1860
}
1827
- return objectPlace;
1861
+ return hasError
1862
+ ? { kind: "UnsupportedNode", node: lvalueNode, loc }
1863
+ : objectPlace;
1864
}
1865
default: {
1830
- todo("Support other lvalue types beyond identifier");
1866
+ builder.pushError({
1867
+ reason: "Support other lvalue types beyond identifier",
1868
+ severity: ErrorSeverity.Todo,
1869
+ nodePath: lvaluePath,
1870
+ });
1871
+ return { kind: "UnsupportedNode", node: lvalueNode, loc };
1872
}
1873
}
1874
}
compiler/forget/src/__tests__/fixtures/hir/error.todo-kitchensink.expect.md
+103
-74
@@ -21,6 +21,8 @@ function foo([a, b], { c, d, e = "e" }, f = "f", ...args) {
21
new c(...args);
22
c(...args);
23
g["e"] += 1;
24
+ const [y, ...yy] = useState(0);
25
+ const { z, aa = "aa", ...zz } = useCustom();
26
27
<Button {...args}></Button>;
28
<Button xlink:href="localhost:3000"></Button>;
@@ -123,7 +125,7 @@ function foo([a, b], { c, d, e = "e" }, f = "f", ...args) {
125
| ^^^^^^^
126
18 | c(...args);
127
19 | g["e"] += 1;
126
- 20 |
128
+ 20 | const [y, ...yy] = useState(0);
129
130
[ReactForget] TodoError: Support non-expression arguments to CallExpression
131
16 | const h = [...b];
@@ -131,122 +133,149 @@ function foo([a, b], { c, d, e = "e" }, f = "f", ...args) {
133
> 18 | c(...args);
134
| ^^^^^^^
135
19 | g["e"] += 1;
134
- 20 |
135
- 21 | <Button {...args}></Button>;
136
+ 20 | const [y, ...yy] = useState(0);
137
+ 21 | const { z, aa = "aa", ...zz } = useCustom();
138
139
[ReactForget] TodoError: Assignment expression to dynamic properties is not yet supported
140
17 | new c(...args);
141
18 | c(...args);
142
> 19 | g["e"] += 1;
143
| ^^^
142
- 20 |
143
- 21 | <Button {...args}></Button>;
144
- 22 | <Button xlink:href="localhost:3000"></Button>;
144
+ 20 | const [y, ...yy] = useState(0);
145
+ 21 | const { z, aa = "aa", ...zz } = useCustom();
146
+ 22 |
147
146
-[ReactForget] TodoError: Handle spread attributes
148
+[ReactForget] TodoError: Rest elements are not supported yet
149
+ 18 | c(...args);
150
+ 19 | g["e"] += 1;
151
+> 20 | const [y, ...yy] = useState(0);
152
+ | ^^^^^
153
+ 21 | const { z, aa = "aa", ...zz } = useCustom();
154
+ 22 |
155
+ 23 | <Button {...args}></Button>;
156
+
157
+[ReactForget] TodoError: Support other lvalue types beyond identifier
158
19 | g["e"] += 1;
148
- 20 |
149
-> 21 | <Button {...args}></Button>;
159
+ 20 | const [y, ...yy] = useState(0);
160
+> 21 | const { z, aa = "aa", ...zz } = useCustom();
161
+ | ^^^^^^^^^
162
+ 22 |
163
+ 23 | <Button {...args}></Button>;
164
+ 24 | <Button xlink:href="localhost:3000"></Button>;
165
+
166
+[ReactForget] TodoError: Rest elements are not supported yet
167
+ 19 | g["e"] += 1;
168
+ 20 | const [y, ...yy] = useState(0);
169
+> 21 | const { z, aa = "aa", ...zz } = useCustom();
170
+ | ^^^^^
171
+ 22 |
172
+ 23 | <Button {...args}></Button>;
173
+ 24 | <Button xlink:href="localhost:3000"></Button>;
174
+
175
+[ReactForget] TodoError: Handle spread attributes
176
+ 21 | const { z, aa = "aa", ...zz } = useCustom();
177
+ 22 |
178
+> 23 | <Button {...args}></Button>;
179
| ^^^^^^^^^
151
- 22 | <Button xlink:href="localhost:3000"></Button>;
152
- 23 | <Button haha={1}></Button>;
153
- 24 | <Button>{/** empty */}</Button>;
180
+ 24 | <Button xlink:href="localhost:3000"></Button>;
181
+ 25 | <Button haha={1}></Button>;
182
+ 26 | <Button>{/** empty */}</Button>;
183
184
[ReactForget] TodoError: Handle non-identifier jsx attribute names
156
- 20 |
157
- 21 | <Button {...args}></Button>;
158
-> 22 | <Button xlink:href="localhost:3000"></Button>;
185
+ 22 |
186
+ 23 | <Button {...args}></Button>;
187
+> 24 | <Button xlink:href="localhost:3000"></Button>;
188
| ^^^^^^^^^^
160
- 23 | <Button haha={1}></Button>;
161
- 24 | <Button>{/** empty */}</Button>;
162
- 25 | <DesignSystem.Button />;
189
+ 25 | <Button haha={1}></Button>;
190
+ 26 | <Button>{/** empty */}</Button>;
191
+ 27 | <DesignSystem.Button />;
192
193
[ReactForget] TodoError: Handle empty expressions
165
- 22 | <Button xlink:href="localhost:3000"></Button>;
166
- 23 | <Button haha={1}></Button>;
167
-> 24 | <Button>{/** empty */}</Button>;
194
+ 24 | <Button xlink:href="localhost:3000"></Button>;
195
+ 25 | <Button haha={1}></Button>;
196
+> 26 | <Button>{/** empty */}</Button>;
197
| ^^^^^^^^^^^^
169
- 25 | <DesignSystem.Button />;
170
- 26 |
171
- 27 | const j = function bar([quz, qux], ...args) {};
198
+ 27 | <DesignSystem.Button />;
199
+ 28 |
200
+ 29 | const j = function bar([quz, qux], ...args) {};
201
202
[ReactForget] TodoError: Handle non-identifier tags
174
- 23 | <Button haha={1}></Button>;
175
- 24 | <Button>{/** empty */}</Button>;
176
-> 25 | <DesignSystem.Button />;
203
+ 25 | <Button haha={1}></Button>;
204
+ 26 | <Button>{/** empty */}</Button>;
205
+> 27 | <DesignSystem.Button />;
206
| ^^^^^^^^^^^^^^^^^^^
178
- 26 |
179
- 27 | const j = function bar([quz, qux], ...args) {};
207
28 |
208
+ 29 | const j = function bar([quz, qux], ...args) {};
209
+ 30 |
210
211
[ReactForget] TodoError: Support non-identifier params: ArrayPattern
183
- 25 | <DesignSystem.Button />;
184
- 26 |
185
-> 27 | const j = function bar([quz, qux], ...args) {};
186
- | ^^^^^^^^^^
212
+ 27 | <DesignSystem.Button />;
213
28 |
188
- 29 | for (; i < 3; i += 1) {
189
- 30 | x.push(i);
214
+> 29 | const j = function bar([quz, qux], ...args) {};
215
+ | ^^^^^^^^^^
216
+ 30 |
217
+ 31 | for (; i < 3; i += 1) {
218
+ 32 | x.push(i);
219
220
[ReactForget] TodoError: Support non-identifier params: RestElement
192
- 25 | <DesignSystem.Button />;
193
- 26 |
194
-> 27 | const j = function bar([quz, qux], ...args) {};
195
- | ^^^^^^^
221
+ 27 | <DesignSystem.Button />;
222
28 |
197
- 29 | for (; i < 3; i += 1) {
198
- 30 | x.push(i);
223
+> 29 | const j = function bar([quz, qux], ...args) {};
224
+ | ^^^^^^^
225
+ 30 |
226
+ 31 | for (; i < 3; i += 1) {
227
+ 32 | x.push(i);
228
229
[ReactForget] TodoError: Support non-variable initialization in for
201
- 27 | const j = function bar([quz, qux], ...args) {};
202
- 28 |
203
-> 29 | for (; i < 3; i += 1) {
230
+ 29 | const j = function bar([quz, qux], ...args) {};
231
+ 30 |
232
+> 31 | for (; i < 3; i += 1) {
233
| ^
205
- 30 | x.push(i);
206
- 31 | }
207
- 32 | for (; i < 3; ) {}
234
+ 32 | x.push(i);
235
+ 33 | }
236
+ 34 | for (; i < 3; ) {}
237
238
[ReactForget] TodoError: Support non-variable initialization in for
210
- 30 | x.push(i);
211
- 31 | }
212
-> 32 | for (; i < 3; ) {}
239
+ 32 | x.push(i);
240
+ 33 | }
241
+> 34 | for (; i < 3; ) {}
242
| ^^^^^^^^^^^^^^^^^^
214
- 33 | for (;;) {}
215
- 34 | }
216
- 35 |
243
+ 35 | for (;;) {}
244
+ 36 | }
245
+ 37 |
246
247
[ReactForget] TodoError: Handle empty for updater
219
- 30 | x.push(i);
220
- 31 | }
221
-> 32 | for (; i < 3; ) {}
248
+ 32 | x.push(i);
249
+ 33 | }
250
+> 34 | for (; i < 3; ) {}
251
| ^^^^^^^^^^^^^^^^^^
223
- 33 | for (;;) {}
224
- 34 | }
225
- 35 |
252
+ 35 | for (;;) {}
253
+ 36 | }
254
+ 37 |
255
256
[ReactForget] TodoError: Support non-variable initialization in for
228
- 31 | }
229
- 32 | for (; i < 3; ) {}
230
-> 33 | for (;;) {}
257
+ 33 | }
258
+ 34 | for (; i < 3; ) {}
259
+> 35 | for (;;) {}
260
| ^^^^^^^^^^^
232
- 34 | }
233
- 35 |
261
+ 36 | }
262
+ 37 |
263
264
[ReactForget] TodoError: Handle empty for updater
236
- 31 | }
237
- 32 | for (; i < 3; ) {}
238
-> 33 | for (;;) {}
265
+ 33 | }
266
+ 34 | for (; i < 3; ) {}
267
+> 35 | for (;;) {}
268
| ^^^^^^^^^^^
240
- 34 | }
241
- 35 |
269
+ 36 | }
270
+ 37 |
271
272
[ReactForget] TodoError: ForStatement without test
244
- 31 | }
245
- 32 | for (; i < 3; ) {}
246
-> 33 | for (;;) {}
273
+ 33 | }
274
+ 34 | for (; i < 3; ) {}
275
+> 35 | for (;;) {}
276
| ^^^^^^^^^^^
248
- 34 | }
249
- 35 |
277
+ 36 | }
278
+ 37 |
279
```
280
281
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/error.todo-kitchensink.js
+2
@@ -17,6 +17,8 @@ function foo([a, b], { c, d, e = "e" }, f = "f", ...args) {
17
new c(...args);
18
c(...args);
19
g["e"] += 1;
20
+ const [y, ...yy] = useState(0);
21
+ const { z, aa = "aa", ...zz } = useCustom();
22
23
<Button {...args}></Button>;
24
<Button xlink:href="localhost:3000"></Button>;