@samitouri / QOS-React-2 / commits / 3158146989

POC of new expression-oriented inference model for memoization within control-flow (#589)

* [hir] Core data types and lowering for new model * Handle more expressions, including using babel for binding resolution * test setup with pretty printing of ir * Basic codegen and improved pretty printing * avoid else block when if has no fallthrough * emit function declarations with mapped name/params * start of scope analysis * saving state pre-run * add slightly more complex example and flush out lowering/printing (jsx, new, variables) * Various improvements: * Convert logical expressions (|| and &&) to control flow, accounting for lazy evaluation semantics. * Handle expression statements * Improve printing of HIR for unsupported node kinds * Handle more cases of JSX by falling by to OtherStatement to wrap subtrees at coarse granularity. * improve HIR printing, lowering of expression statements * handle object expression printing * improve IR model for values/places along w codegen * more test cases * start of mutability inference * passable but still incorrect mutability inference * improved mutability inference, should cover most cases now * visualization of reference graph * correctly flow mutability backwards (have to actually set the capability) * separate visualization in output * consolidate on frozen/readonly/mutable capabilities * cleanup * conditional reassignment test (not quite working) * hack to output svg files for debugging * handle conditional reassignment * improve capture analysis * treat jsx as (interior) mutable; handle memberexpression lvalues * lots of comments; hook return is frozen * update main comment * inference for switch, which reveals a bug * fix yarn.lock

Joseph Savona committed Sep 30, 2022 at 14:11 UTC 3158146989de57b085ff84c0bb6ba7aaee2df61c
58 files changed +8895 -6
compiler/forget/package.json
+3
@@ -26,12 +26,15 @@
26 "devDependencies": {
27 "@babel/core": "^7.19.1",
28 "@babel/generator": "^7.19.0",
29 + "@babel/parser": "^7.19.1",
30 "@babel/plugin-syntax-typescript": "^7.18.6",
31 "@babel/plugin-transform-block-scoping": "^7.18.9",
32 "@babel/plugin-transform-modules-commonjs": "^7.18.6",
33 "@babel/preset-react": "^7.18.6",
34 "@babel/preset-typescript": "^7.18.6",
35 + "@babel/traverse": "^7.19.1",
36 "@babel/types": "^7.19.0",
37 + "@hpcc-js/wasm": "^1.15.0",
38 "@testing-library/react": "^13.4.0",
39 "@tsconfig/node16-strictest": "^1.0.3",
40 "@types/invariant": "^2.2.35",
compiler/forget/src/HIR/BuildHIR.ts new
+1096
@@ -0,0 +1,1096 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +import { NodePath } from "@babel/traverse";
9 +import * as t from "@babel/types";
10 +import { assertExhaustive } from "../Common/utils";
11 +import { invariant } from "../CompilerError";
12 +import {
13 + Capability,
14 + HIRFunction,
15 + Identifier,
16 + IfTerminal,
17 + InstructionValue,
18 + Place,
19 + ReturnTerminal,
20 + Terminal,
21 + ThrowTerminal,
22 +} from "./HIR";
23 +import HIRBuilder from "./HIRBuilder";
24 +import todo, { todoInvariant } from "./todo";
25 +
26 +// *******************************************************************************************
27 +// *******************************************************************************************
28 +// ************************************* Lowering to HIR *************************************
29 +// *******************************************************************************************
30 +// *******************************************************************************************
31 +
32 +const GLOBALS: Map<string, t.Identifier> = new Map([
33 + ["Map", t.identifier("Map")],
34 + ["Set", t.identifier("Set")],
35 + ["Math", t.identifier("Math")],
36 +]);
37 +
38 +/**
39 + * Lower a function declaration into a control flow graph that models aspects of
40 + * control flow that are necessary for memoization. Notably, only control flow
41 + * that occurs at statement granularity is modeled (eg `if`, `for`, `return`
42 + * statements), not control flow at the expression level (ternaries or boolean
43 + * short-circuiting). Throw semantics are also not modeled: in general exceptions
44 + * are treated as exceptional conditions that invalidate memoization.
45 + *
46 + * TODO: consider modeling control-flow at expression level for even more fine-
47 + * grained reactivity.
48 + */
49 +export function lower(func: NodePath<t.Function>): HIRFunction {
50 + const builder = new HIRBuilder();
51 +
52 + const id =
53 + func.isFunctionDeclaration() && func.node.id != null
54 + ? builder.resolveIdentifier(func.node.id)
55 + : null;
56 +
57 + const params: Array<Identifier> = [];
58 + func.node.params.forEach((param) => {
59 + todoInvariant(t.isIdentifier(param), "todo: support non-identifier params");
60 + params.push(builder.resolveIdentifier(param));
61 + });
62 +
63 + const body = func.get("body");
64 + if (body.isExpression()) {
65 + todoInvariant(false, "TODO handle arrow functions");
66 + } else if (body.isBlockStatement()) {
67 + lowerStatement(builder, body);
68 + } else {
69 + invariant(false, "Unexpected function body kind");
70 + }
71 +
72 + return {
73 + path: func,
74 + id,
75 + params,
76 + body: builder.build(),
77 + };
78 +}
79 +
80 +/**
81 + * Helper to lower a statement
82 + */
83 +function lowerStatement(
84 + builder: HIRBuilder,
85 + stmtPath: NodePath<t.Statement>,
86 + label: string | null = null
87 +): undefined {
88 + const stmtNode = stmtPath.node;
89 + switch (stmtNode.type) {
90 + case "ThrowStatement": {
91 + const stmt = stmtPath as NodePath<t.ThrowStatement>;
92 + const value = lowerExpressionToPlace(builder, stmt.get("argument"));
93 + const terminal: ThrowTerminal = { kind: "throw", value };
94 + builder.terminate(terminal);
95 + return;
96 + }
97 + case "ReturnStatement": {
98 + const stmt = stmtPath as NodePath<t.ReturnStatement>;
99 + const argument = stmt.get("argument");
100 + const value = argument.hasNode()
101 + ? lowerExpressionToPlace(builder, argument)
102 + : null;
103 + const fallthrough = builder.reserve();
104 + const terminal: ReturnTerminal = {
105 + kind: "return",
106 + value,
107 + };
108 + builder.terminateWithContinuation(terminal, fallthrough);
109 + return;
110 + }
111 + case "IfStatement": {
112 + const stmt = stmtPath as NodePath<t.IfStatement>;
113 + // Block for code following the if
114 + const continuationBlock = builder.reserve();
115 + // Block for the consequent (if the test is truthy)
116 + const consequentBlock = builder.enter((blockId) => {
117 + lowerStatement(builder, stmt.get("consequent"));
118 + return {
119 + kind: "goto",
120 + block: continuationBlock.id,
121 + };
122 + });
123 + // Block for the alternate (if the test is not truthy)
124 + let alternateBlock = null;
125 + const alternate = stmt.get("alternate");
126 + if (alternate.hasNode()) {
127 + alternateBlock = builder.enter((blockId) => {
128 + lowerStatement(builder, alternate);
129 + return {
130 + kind: "goto",
131 + block: continuationBlock.id,
132 + };
133 + });
134 + } else {
135 + // If there is no else clause, use the continuation directly
136 + alternateBlock = continuationBlock.id;
137 + }
138 + const test = lowerExpressionToPlace(builder, stmt.get("test"));
139 + const terminal: IfTerminal = {
140 + kind: "if",
141 + test,
142 + consequent: consequentBlock,
143 + alternate: alternateBlock,
144 + fallthrough:
145 + alternateBlock !== continuationBlock.id ? continuationBlock.id : null,
146 + };
147 + builder.terminateWithContinuation(terminal, continuationBlock);
148 + return;
149 + }
150 + case "BlockStatement": {
151 + const stmt = stmtPath as NodePath<t.BlockStatement>;
152 + stmt.get("body").forEach((s) => lowerStatement(builder, s));
153 + return;
154 + }
155 + case "BreakStatement": {
156 + const stmt = stmtPath as NodePath<t.BreakStatement>;
157 + const block = builder.lookupBreak(stmt.node.label?.name ?? null);
158 + builder.terminate({
159 + kind: "goto",
160 + block,
161 + });
162 + return;
163 + }
164 + case "ContinueStatement": {
165 + const stmt = stmtPath as NodePath<t.ContinueStatement>;
166 + const block = builder.lookupContinue(stmt.node.label?.name ?? null);
167 + builder.terminate({
168 + kind: "goto",
169 + block,
170 + });
171 + return;
172 + }
173 + case "ForInStatement": {
174 + const stmt = stmtPath as NodePath<t.ForInStatement>;
175 + // Block used to evaluate whether to (re)enter or exit the loop
176 + const conditionalBlock = builder.reserve();
177 + // Block for code following the loop
178 + const continuationBlock = builder.reserve();
179 + const loopBlock = builder.enter((blockId) => {
180 + return builder.loop(
181 + label,
182 + conditionalBlock.id,
183 + continuationBlock.id,
184 + () => {
185 + lowerStatement(builder, stmt.get("body"));
186 + return {
187 + kind: "goto",
188 + block: conditionalBlock.id,
189 + fallthrough: null,
190 + tests: null,
191 + };
192 + }
193 + );
194 + });
195 + // End the block leading up to the loop and jump to the conditional block
196 + builder.terminateWithContinuation(
197 + {
198 + kind: "goto",
199 + block: conditionalBlock.id,
200 + },
201 + conditionalBlock
202 + );
203 + /**
204 + * Terminate the conditional block using the <right> value as the test condition:
205 + * this conceptually represents that the value of <right> influences which branch
206 + * is taken (if it has properties enter the loop, if no properties exit to the continuation)
207 + */
208 + const test = lowerExpressionToPlace(builder, stmt.get("right"));
209 + const terminal: IfTerminal = {
210 + kind: "if",
211 + test,
212 + consequent: loopBlock,
213 + alternate: continuationBlock.id,
214 + fallthrough: continuationBlock.id, // TODO: improve loop handling
215 + };
216 + builder.terminateWithContinuation(terminal, continuationBlock);
217 + return;
218 + }
219 + case "ForOfStatement": {
220 + const stmt = stmtPath as NodePath<t.ForOfStatement>;
221 + // Block used to evaluate whether to (re)enter or exit the loop
222 + const conditionalBlock = builder.reserve();
223 + // Block for code following the loop
224 + const continuationBlock = builder.reserve();
225 + /**
226 + * Build the loop body, each iteration loops back to the conditional block
227 + * to check whether to continue or exit
228 + */
229 + const loopBlock = builder.enter((blockId) => {
230 + return builder.loop(
231 + label,
232 + conditionalBlock.id,
233 + continuationBlock.id,
234 + () => {
235 + lowerStatement(builder, stmt.get("body"));
236 + return {
237 + kind: "goto",
238 + block: conditionalBlock.id,
239 + fallthrough: null,
240 + tests: null,
241 + };
242 + }
243 + );
244 + });
245 + // End the block leading up to the loop and jump to the conditional block
246 + builder.terminateWithContinuation(
247 + {
248 + kind: "goto",
249 + block: conditionalBlock.id,
250 + },
251 + conditionalBlock
252 + );
253 + /**
254 + * Terminate the conditional block using the <right> value as the test condition:
255 + * this conceptually represents that the value of <right> influences which branch
256 + * is taken (even though it isn't actually a boolean check in practice)
257 + */
258 + const test = lowerExpressionToPlace(builder, stmt.get("right"));
259 + const terminal: IfTerminal = {
260 + kind: "if",
261 + test,
262 + consequent: loopBlock,
263 + alternate: continuationBlock.id,
264 + fallthrough: continuationBlock.id, // TODO: improve loop handling
265 + };
266 + builder.terminateWithContinuation(terminal, continuationBlock);
267 + return;
268 + }
269 + case "ForStatement": {
270 + const stmt = stmtPath as NodePath<t.ForStatement>;
271 + /**
272 + * The initializer is evaluated once prior to entering the loop.
273 + * here we are not concerned about scoping, so we can push the
274 + * initializer to the end of of the block leading up to the loop
275 + */
276 + const init = stmt.get("init");
277 + if (init.hasNode()) {
278 + // builder.push(init);
279 + throw new Error("todo: lower initializer in ForStatement");
280 + }
281 + // Block used to evaluate whether to (re)enter or exit the loop
282 + const conditionalBlock = builder.reserve();
283 + // Block for code following the loop
284 + const continuationBlock = builder.reserve();
285 + /**
286 + * Block for the updater, which runs after each iteration (including upon `continue`)
287 + * Generally this would increment or decrement the loop index variable
288 + */
289 + const updateBlock = builder.reserve();
290 + const update = stmt.get("update");
291 + if (update.hasNode()) {
292 + // updateBlock[1].push(stmt.get("update") as any as NodePath<t.Statement>);
293 + throw new Error("todo: lower updater for ForStatement");
294 + }
295 + builder.complete(updateBlock, {
296 + kind: "goto",
297 + block: conditionalBlock.id,
298 + });
299 + /**
300 + * Construct the loop itself: the loop body wraps around to the update block
301 + * and the update block is also set as the `continue` target
302 + */
303 + const loopBlock = builder.enter((blockId) => {
304 + return builder.loop(label, updateBlock.id, continuationBlock.id, () => {
305 + lowerStatement(builder, stmt.get("body"));
306 + return {
307 + kind: "goto",
308 + block: updateBlock.id,
309 + fallthrough: null,
310 + };
311 + });
312 + });
313 + // End the block leading up to the loop, jumping to the conditional block
314 + builder.terminateWithContinuation(
315 + {
316 + kind: "goto",
317 + block: conditionalBlock.id,
318 + },
319 + conditionalBlock
320 + );
321 +
322 + let terminal: Terminal;
323 + const test = stmt.get("test");
324 + if (test.hasNode()) {
325 + /**
326 + * Terminate the conditional block with the test conditional of the for statement:
327 + * if the condition is true enter the loop block, else exit to the continuation
328 + */
329 + terminal = {
330 + kind: "if",
331 + test: lowerExpressionToPlace(builder, test),
332 + consequent: loopBlock,
333 + alternate: continuationBlock.id,
334 + fallthrough: continuationBlock.id, // TODO: improve loop handling
335 + };
336 + } else {
337 + /**
338 + * If there is no test, then the "conditional" block unconditionally re-enters the loop.
339 + * this will create an indirection, but `shrink()` will eliminate this in post-processing.
340 + */
341 + terminal = {
342 + kind: "goto",
343 + block: loopBlock,
344 + };
345 + }
346 + builder.terminateWithContinuation(terminal, continuationBlock);
347 + return;
348 + }
349 + case "DoWhileStatement": {
350 + const stmt = stmtPath as NodePath<t.DoWhileStatement>;
351 + // Block for code following the loop
352 + const continuationBlock = builder.reserve();
353 + // Loop body
354 + const loopBlock = builder.enter((loopBlock) => {
355 + return builder.loop(label, loopBlock, continuationBlock.id, () => {
356 + lowerStatement(builder, stmt.get("body"));
357 + /**
358 + * the loop terminates with the while condition, either looping
359 + * around (consequent) or exiting to the continuation (alternate)
360 + */
361 + const test = lowerExpressionToPlace(builder, stmt.get("test"));
362 + const terminal: IfTerminal = {
363 + kind: "if",
364 + test,
365 + consequent: loopBlock,
366 + alternate: continuationBlock.id,
367 + fallthrough: continuationBlock.id, // TODO: improve loop handling
368 + };
369 + return terminal;
370 + });
371 + });
372 + // do-while unconditionally enters the loop
373 + builder.terminateWithContinuation(
374 + { kind: "goto", block: loopBlock },
375 + continuationBlock
376 + );
377 + return;
378 + }
379 + case "WhileStatement": {
380 + const stmt = stmtPath as NodePath<t.WhileStatement>;
381 + // Block used to evaluate whether to (re)enter or exit the loop
382 + const conditionalBlock = builder.reserve();
383 + // Block for code following the loop
384 + const continuationBlock = builder.reserve();
385 + // Loop body
386 + const loopBlock = builder.enter((blockId) => {
387 + return builder.loop(
388 + label,
389 + conditionalBlock.id,
390 + continuationBlock.id,
391 + () => {
392 + lowerStatement(builder, stmt.get("body"));
393 + return {
394 + kind: "goto",
395 + block: conditionalBlock.id,
396 + };
397 + }
398 + );
399 + });
400 + /**
401 + * The code leading up to the loop must jump to the conditional block,
402 + * to evaluate whether to enter the loop or bypass to the continuation.
403 + */
404 + builder.terminateWithContinuation(
405 + {
406 + kind: "goto",
407 + block: conditionalBlock.id,
408 + },
409 + conditionalBlock
410 + );
411 + /**
412 + * The conditional block is empty and exists solely as conditional for
413 + * (re)entering or exiting the loop
414 + */
415 + const test = lowerExpressionToPlace(builder, stmt.get("test"));
416 + const terminal: IfTerminal = {
417 + kind: "if",
418 + test,
419 + consequent: loopBlock,
420 + alternate: continuationBlock.id,
421 + fallthrough: continuationBlock.id, // TODO: improve loop handling
422 + };
423 + // Complete the conditional and continue with code after the loop
424 + builder.terminateWithContinuation(terminal, continuationBlock);
425 + return;
426 + }
427 + case "LabeledStatement": {
428 + const stmt = stmtPath as NodePath<t.LabeledStatement>;
429 + const label = stmt.node.label.name;
430 + const body = stmt.get("body");
431 + switch (body.node.type) {
432 + case "ForInStatement":
433 + case "ForOfStatement":
434 + case "ForStatement":
435 + case "WhileStatement":
436 + case "DoWhileStatement": {
437 + // labeled loops are special because of continue, so push the label
438 + // down
439 + lowerStatement(builder, stmt.get("body"), label);
440 + break;
441 + }
442 + default: {
443 + // All other statements create a continuation block to allow `break`,
444 + // explicitly *don't* pass the label down
445 + const continuationBlock = builder.reserve();
446 + builder.label(label, continuationBlock.id, () => {
447 + lowerStatement(builder, stmt.get("body"));
448 + });
449 + builder.terminateWithContinuation(
450 + {
451 + kind: "goto",
452 + block: continuationBlock.id,
453 + },
454 + continuationBlock
455 + );
456 + }
457 + }
458 + return;
459 + }
460 + case "SwitchStatement": {
461 + const stmt = stmtPath as NodePath<t.SwitchStatement>;
462 + // Block following the switch
463 + const continuationBlock = builder.reserve();
464 + /**
465 + * The goto target for any cases that fallthrough, which initially starts
466 + * as the continuation block and is then updated as we iterate through cases
467 + * in reverse order.
468 + */
469 + let fallthrough = continuationBlock.id;
470 + /**
471 + * Iterate through cases in reverse order, so that previous blocks can fallthrough
472 + * to successors
473 + */
474 + const cases = [];
475 + let hasDefault = false;
476 + for (let ii = stmt.get("cases").length - 1; ii >= 0; ii--) {
477 + const case_: NodePath<t.SwitchCase> = stmt.get("cases")[ii];
478 + const test = case_.get("test");
479 + if (!test.hasNode()) {
480 + invariant(
481 + !hasDefault,
482 + "Expected at most one `default` branch, this code should have failed to parse"
483 + );
484 + hasDefault = true;
485 + }
486 + const block = builder.enter((_blockId) => {
487 + return builder.switch(label, continuationBlock.id, () => {
488 + case_
489 + .get("consequent")
490 + .forEach((consequent) => lowerStatement(builder, consequent));
491 + /**
492 + * always generate a fallthrough, this may be dead code if there was
493 + * an explicit break
494 + */
495 + return {
496 + kind: "goto",
497 + block: fallthrough,
498 + };
499 + });
500 + });
501 + cases.push({
502 + test: test.hasNode() ? lowerExpressionToPlace(builder, test) : null,
503 + block,
504 + });
505 + fallthrough = block;
506 + }
507 + /**
508 + * it doesn't matter for our analysis purposes, but reverse the order of the cases
509 + * back to the original to make it match the original code/intent.
510 + */
511 + cases.reverse();
512 + /**
513 + * If there wasn't an explicit default case, generate one to model the fact that execution
514 + * could bypass any of the other cases and jump directly to the continuation.
515 + */
516 + if (!hasDefault) {
517 + cases.push({ test: null, block: continuationBlock.id });
518 + }
519 +
520 + const test = lowerExpressionToPlace(builder, stmt.get("discriminant"));
521 + builder.terminateWithContinuation(
522 + { kind: "switch", test, cases, fallthrough: continuationBlock.id },
523 + continuationBlock
524 + );
525 + return;
526 + }
527 + case "TryStatement": {
528 + const stmt = stmtPath as NodePath<t.TryStatement>;
529 + /**
530 + * NOTE: Accurately modeling control flow within a try statement would require treating
531 + * effectively every expression as a possible branch point (since almost any expression can throw).
532 + * Instead, we model the try statement as an atomic unit from a control-flow perspective,
533 + * and rely on other passes to handle codegen for try statements
534 + */
535 + lowerStatement(builder, stmt.get("block"));
536 + const handler = stmt.get("handler");
537 + if (handler.hasNode()) {
538 + // TODO: consider whether we need to track the param
539 + lowerStatement(builder, handler.get("body"));
540 + }
541 + const finalizer = stmt.get("finalizer");
542 + if (finalizer.hasNode()) {
543 + lowerStatement(builder, finalizer);
544 + }
545 + return;
546 + }
547 + case "VariableDeclaration": {
548 + const stmt = stmtPath as NodePath<t.VariableDeclaration>;
549 + const kind: string = stmt.node.kind;
550 + invariant(
551 + kind === "let" || kind === "const",
552 + "`var` declarations are not supported, use let or const"
553 + );
554 + for (const declaration of stmt.get("declarations")) {
555 + const id = lowerLVal(builder, declaration.get("id"));
556 + const init = declaration.get("init");
557 + let value: InstructionValue;
558 + if (init.hasNode()) {
559 + value = lowerExpression(builder, init);
560 + } else {
561 + value = {
562 + kind: "Primitive",
563 + value: undefined,
564 + path: init as any, // TODO
565 + };
566 + }
567 + builder.push({
568 + place: id,
569 + value,
570 + path: stmt,
571 + });
572 + }
573 + return;
574 + }
575 + case "ExpressionStatement": {
576 + const stmt = stmtPath as NodePath<t.ExpressionStatement>;
577 + const expression = stmt.get("expression");
578 + const value = lowerExpression(builder, expression);
579 + if (expression.isAssignmentExpression()) {
580 + // instruction already emitted via lowerExpression()
581 + return;
582 + }
583 + builder.push({
584 + place: null,
585 + value,
586 + path: stmt,
587 + });
588 + return;
589 + }
590 + case "ClassDeclaration":
591 + case "DebuggerStatement":
592 + case "DeclareClass":
593 + case "DeclareExportAllDeclaration":
594 + case "DeclareExportDeclaration":
595 + case "DeclareFunction":
596 + case "DeclareInterface":
597 + case "DeclareModule":
598 + case "DeclareModuleExports":
599 + case "DeclareOpaqueType":
600 + case "DeclareTypeAlias":
601 + case "DeclareVariable":
602 + case "EmptyStatement":
603 + case "EnumDeclaration":
604 + case "ExportAllDeclaration":
605 + case "ExportDefaultDeclaration":
606 + case "ExportNamedDeclaration":
607 + case "FunctionDeclaration":
608 + case "ImportDeclaration":
609 + case "InterfaceDeclaration":
610 + case "OpaqueType":
611 + case "TypeAlias":
612 + case "TSDeclareFunction":
613 + case "TSEnumDeclaration":
614 + case "TSExportAssignment":
615 + case "TSImportEqualsDeclaration":
616 + case "TSInterfaceDeclaration":
617 + case "TSModuleDeclaration":
618 + case "TSNamespaceExportDeclaration":
619 + case "TSTypeAliasDeclaration":
620 + case "WithStatement": {
621 + builder.push({
622 + path: stmtPath,
623 + place: null,
624 + value: { kind: "OtherStatement", path: stmtPath },
625 + });
626 + return;
627 + }
628 + default: {
629 + return assertExhaustive(
630 + stmtNode,
631 + `Unsupported statement kind '${
632 + (stmtNode as any as NodePath<t.Statement>).type
633 + }'`
634 + );
635 + }
636 + }
637 +}
638 +
639 +function lowerExpression(
640 + builder: HIRBuilder,
641 + exprPath: NodePath<t.Expression>
642 +): InstructionValue {
643 + const exprNode = exprPath.node;
644 + switch (exprNode.type) {
645 + case "Identifier": {
646 + const expr = exprPath as NodePath<t.Identifier>;
647 + return lowerLVal(builder, expr);
648 + }
649 + case "NullLiteral": {
650 + return {
651 + kind: "Primitive",
652 + value: null,
653 + path: exprPath,
654 + };
655 + }
656 + case "BooleanLiteral":
657 + case "NumericLiteral":
658 + case "StringLiteral": {
659 + const expr = exprPath as NodePath<
660 + t.StringLiteral | t.BooleanLiteral | t.NumericLiteral
661 + >;
662 + const value = expr.node.value;
663 + return {
664 + kind: "Primitive",
665 + value,
666 + path: exprPath,
667 + };
668 + }
669 + case "ObjectExpression": {
670 + const expr = exprPath as NodePath<t.ObjectExpression>;
671 + const propertyPaths = expr.get("properties");
672 + const properties: { [name: string]: Place } = {};
673 + for (const propertyPath of propertyPaths) {
674 + todoInvariant(
675 + propertyPath.isObjectProperty(),
676 + "Handle object property spread"
677 + );
678 + const key = propertyPath.node.key;
679 + invariant(key.type === "Identifier", "Unexpected private name");
680 + const valuePath = propertyPath.get("value");
681 + todoInvariant(
682 + valuePath.isExpression(),
683 + "Handle non-expression object values"
684 + );
685 + const value = lowerExpressionToPlace(builder, valuePath);
686 + properties[key.name] = value;
687 + }
688 + return {
689 + kind: "ObjectExpression",
690 + properties,
691 + path: exprPath,
692 + };
693 + }
694 + case "ArrayExpression": {
695 + const expr = exprPath as NodePath<t.ArrayExpression>;
696 + const elements = expr.get("elements").map((element) => {
697 + todoInvariant(
698 + element.hasNode() && element.isExpression(),
699 + "todo: handle non-expression array elements"
700 + );
701 + return lowerExpressionToPlace(builder, element);
702 + });
703 + return {
704 + kind: "ArrayExpression",
705 + elements,
706 + path: exprPath,
707 + };
708 + }
709 + case "NewExpression": {
710 + const expr = exprPath as NodePath<t.NewExpression>;
711 + const calleePath = expr.get("callee");
712 + invariant(
713 + calleePath.isExpression(),
714 + "Call expressions only support callees that are expressions (v8 intrinsics not supported)"
715 + );
716 + const callee = lowerExpressionToPlace(builder, calleePath);
717 + const argPaths = expr.get("arguments");
718 + const args = argPaths.map((arg) => {
719 + todoInvariant(
720 + arg.isExpression(),
721 + "todo: support non-expression call arguments"
722 + );
723 + return lowerExpressionToPlace(builder, arg);
724 + });
725 + return {
726 + kind: "NewExpression",
727 + callee,
728 + args,
729 + path: exprPath,
730 + };
731 + }
732 + case "CallExpression": {
733 + const expr = exprPath as NodePath<t.CallExpression>;
734 + const calleePath = expr.get("callee");
735 + invariant(
736 + calleePath.isExpression(),
737 + "Call expressions only support callees that are expressions (v8 intrinsics not supported)"
738 + );
739 + const callee = lowerExpressionToPlace(builder, calleePath);
740 + const argPaths = expr.get("arguments");
741 + const args = argPaths.map((arg) => {
742 + todoInvariant(
743 + arg.isExpression(),
744 + "todo: support non-expression call arguments"
745 + );
746 + return lowerExpressionToPlace(builder, arg);
747 + });
748 + return {
749 + kind: "CallExpression",
750 + callee,
751 + args,
752 + path: exprPath,
753 + };
754 + }
755 + case "BinaryExpression": {
756 + const expr = exprPath as NodePath<t.BinaryExpression>;
757 + const leftPath = expr.get("left");
758 + invariant(
759 + leftPath.isExpression(),
760 + "Private names may not appear as the left hand side of a binary expression"
761 + );
762 + const left = lowerExpressionToPlace(builder, leftPath);
763 + const right = lowerExpressionToPlace(builder, expr.get("right"));
764 + const operator = expr.node.operator;
765 + return {
766 + kind: "BinaryExpression",
767 + operator,
768 + left,
769 + right,
770 + path: exprPath,
771 + };
772 + }
773 + case "LogicalExpression": {
774 + const expr = exprPath as NodePath<t.LogicalExpression>;
775 + const leftPath = expr.get("left");
776 + invariant(
777 + leftPath.isExpression(),
778 + "Private names may not appear as the left hand side of a binary expression"
779 + );
780 + const operator = expr.node.operator;
781 + switch (operator) {
782 + case "||": {
783 + const left = lowerExpressionToPlace(builder, leftPath);
784 + return lowerConditional(
785 + builder,
786 + left,
787 + () => left,
788 + () => lowerExpression(builder, expr.get("right"))
789 + );
790 + }
791 + case "&&": {
792 + const left = lowerExpressionToPlace(builder, leftPath);
793 + return lowerConditional(
794 + builder,
795 + left,
796 + () => lowerExpression(builder, expr.get("right")),
797 + () => left
798 + );
799 + }
800 + case "??": {
801 + // test should be roughly the equivalent of `<left> != null`
802 + todo("Handle logical ??");
803 + }
804 + default: {
805 + assertExhaustive(
806 + operator,
807 + `Unexpected logical operator '${operator as any}'`
808 + );
809 + }
810 + }
811 + }
812 + case "AssignmentExpression": {
813 + const expr = exprPath as NodePath<t.AssignmentExpression>;
814 + const left = lowerLVal(builder, expr.get("left"));
815 + const right = lowerExpression(builder, expr.get("right"));
816 + const operator = expr.node.operator;
817 + todoInvariant(operator === "=", "todo: support non-simple assignment");
818 + builder.push({
819 + path: exprPath,
820 + value: right,
821 + place: left,
822 + });
823 + return left;
824 + }
825 + case "MemberExpression": {
826 + const expr = exprPath as NodePath<t.MemberExpression>;
827 + const object = lowerExpressionToPlace(builder, expr.get("object"));
828 + invariant(object.kind === "Identifier", "scope cannot appear here");
829 + const property = expr.get("property");
830 + todoInvariant(
831 + property.isIdentifier(),
832 + "Handle non-identifier properties"
833 + );
834 + const place: Place = {
835 + kind: "Identifier",
836 + value: object.value,
837 + memberPath: [...(object.memberPath ?? []), property.node.name],
838 + capability: Capability.Unknown,
839 + path: exprPath,
840 + };
841 + return place;
842 + }
843 + case "JSXElement": {
844 + const expr = exprPath as NodePath<t.JSXElement>;
845 + const opening = expr.get("openingElement");
846 + const tag = lowerJsxElementName(builder, opening.get("name"));
847 + const children = expr
848 + .get("children")
849 + .map((child) => lowerJsxElement(builder, child));
850 + const props: { [prop: string]: Place } = {};
851 + opening.get("attributes").forEach((attribute) => {
852 + todoInvariant(attribute.isJSXAttribute(), "handle spread attributes");
853 + const name = attribute.get("name");
854 + todoInvariant(
855 + name.isJSXIdentifier(),
856 + "handle non-identifier jsx attribute names"
857 + );
858 + const valueExpr = attribute.get("value");
859 + let value;
860 + if (valueExpr.isJSXElement() || valueExpr.isStringLiteral()) {
861 + value = lowerExpressionToPlace(builder, valueExpr);
862 + } else {
863 + todoInvariant(
864 + valueExpr.isJSXExpressionContainer(),
865 + "handle other non expr containers"
866 + );
867 + const expression = valueExpr.get("expression");
868 + todoInvariant(expression.isExpression(), "handle empty expressions");
869 + value = lowerExpressionToPlace(builder, expression);
870 + }
871 + const prop: string = name.node.name;
872 + props[prop] = value;
873 + });
874 + return {
875 + kind: "JsxExpression",
876 + path: exprPath,
877 + tag,
878 + props,
879 + children,
880 + };
881 + }
882 + default: {
883 + todo(`lowerExpression(${exprNode.type})`);
884 + // assertExhaustive(
885 + // exprNode,
886 + // `Unexpected expression kind '${exprNode.type}'`
887 + // );
888 + }
889 + }
890 +}
891 +
892 +function lowerConditional(
893 + builder: HIRBuilder,
894 + test: Place,
895 + consequent: () => InstructionValue,
896 + alternate: () => InstructionValue
897 +): Place {
898 + const place: Place = {
899 + kind: "Identifier",
900 + value: builder.makeTemporary(),
901 + memberPath: null,
902 + capability: Capability.Readonly,
903 + path: null as any, // TODO
904 + };
905 + // Block for code following the if
906 + const continuationBlock = builder.reserve();
907 + // Block for the consequent (if the test is truthy)
908 + const consequentBlock = builder.enter((blockId) => {
909 + let value = consequent();
910 + builder.push({ value, place: { ...place }, path: value.path });
911 + return {
912 + kind: "goto",
913 + block: continuationBlock.id,
914 + };
915 + });
916 + // Block for the alternate (if the test is not truthy)
917 + const alternateBlock = builder.enter((blockId) => {
918 + let value = alternate();
919 + builder.push({ value, place: { ...place }, path: value.path });
920 + return {
921 + kind: "goto",
922 + block: continuationBlock.id,
923 + };
924 + });
925 + const terminal: IfTerminal = {
926 + kind: "if",
927 + test,
928 + consequent: consequentBlock,
929 + alternate: alternateBlock,
930 + fallthrough: continuationBlock.id,
931 + };
932 + builder.terminateWithContinuation(terminal, continuationBlock);
933 + return place;
934 +}
935 +
936 +function lowerJsxElementName(
937 + builder: HIRBuilder,
938 + exprPath: NodePath<
939 + t.JSXIdentifier | t.JSXMemberExpression | t.JSXNamespacedName
940 + >
941 +): Place {
942 + todoInvariant(exprPath.isJSXIdentifier(), "handle non-identifier tags");
943 + const tag: string = exprPath.node.name;
944 + if (tag.match(/^[A-Z]/)) {
945 + const binding =
946 + exprPath.scope.getBindingIdentifier(tag) ?? GLOBALS.get(tag);
947 + invariant(
948 + binding != null,
949 + `Expected to find a binding for variable '%s'`,
950 + tag
951 + );
952 + const identifier = builder.resolveIdentifier(binding);
953 + const place: Place = {
954 + kind: "Identifier",
955 + value: identifier,
956 + memberPath: null,
957 + capability: Capability.Unknown,
958 + path: exprPath,
959 + };
960 + return place;
961 + } else {
962 + const place: Place = {
963 + kind: "Identifier",
964 + value: builder.makeTemporary(),
965 + memberPath: null,
966 + capability: Capability.Unknown,
967 + path: exprPath,
968 + };
969 + builder.push({
970 + value: { kind: "Primitive", value: tag, path: exprPath },
971 + path: exprPath,
972 + place,
973 + });
974 + return { ...place };
975 + }
976 +}
977 +
978 +function lowerJsxElement(
979 + builder: HIRBuilder,
980 + exprPath: NodePath<
981 + | t.JSXText
982 + | t.JSXExpressionContainer
983 + | t.JSXSpreadChild
984 + | t.JSXElement
985 + | t.JSXFragment
986 + >
987 +): Place {
988 + if (exprPath.isJSXElement()) {
989 + return lowerExpressionToPlace(builder, exprPath);
990 + } else if (exprPath.isJSXExpressionContainer()) {
991 + const expression = exprPath.get("expression");
992 + todoInvariant(expression.isExpression(), "handle empty expressions");
993 + return lowerExpressionToPlace(builder, expression);
994 + } else if (exprPath.isJSXText()) {
995 + const place: Place = {
996 + kind: "Identifier",
997 + value: builder.makeTemporary(),
998 + memberPath: null,
999 + capability: Capability.Unknown,
1000 + path: exprPath,
1001 + };
1002 + builder.push({
1003 + value: { kind: "JSXText", value: exprPath.node.value, path: exprPath },
1004 + path: exprPath,
1005 + place: { ...place },
1006 + });
1007 + return place;
1008 + } else {
1009 + const place: Place = {
1010 + kind: "Identifier",
1011 + value: builder.makeTemporary(),
1012 + memberPath: null,
1013 + capability: Capability.Unknown,
1014 + path: exprPath,
1015 + };
1016 + builder.push({
1017 + value: { kind: "OtherStatement", path: exprPath },
1018 + path: exprPath,
1019 + place: { ...place },
1020 + });
1021 + return place;
1022 + }
1023 +}
1024 +
1025 +function lowerExpressionToPlace(
1026 + builder: HIRBuilder,
1027 + exprPath: NodePath<t.Expression>
1028 +): Place {
1029 + const instr = lowerExpression(builder, exprPath);
1030 + if (instr.kind === "Identifier") {
1031 + return instr;
1032 + }
1033 + const place: Place = {
1034 + kind: "Identifier",
1035 + value: builder.makeTemporary(),
1036 + memberPath: null,
1037 + capability: Capability.Unknown,
1038 + path: exprPath,
1039 + };
1040 + builder.push({
1041 + value: instr,
1042 + path: exprPath,
1043 + place: { ...place },
1044 + });
1045 + return place;
1046 +}
1047 +
1048 +function lowerLVal(builder: HIRBuilder, exprPath: NodePath<t.LVal>): Place {
1049 + const exprNode = exprPath.node;
1050 + switch (exprNode.type) {
1051 + case "Identifier": {
1052 + // const expr = exprPath as NodePath<t.Identifier>;
1053 + // const name: string = expr.get("name");
1054 + const binding =
1055 + exprPath.scope.getBindingIdentifier(exprNode.name) ??
1056 + GLOBALS.get(exprNode.name);
1057 + invariant(
1058 + binding != null,
1059 + `Expected to find a binding for variable '%s'`,
1060 + exprNode.name
1061 + );
1062 + const identifier = builder.resolveIdentifier(binding);
1063 + const place: Place = {
1064 + kind: "Identifier",
1065 + value: identifier,
1066 + memberPath: null,
1067 + capability: Capability.Unknown,
1068 + path: exprPath,
1069 + };
1070 + return place;
1071 + }
1072 + case "MemberExpression": {
1073 + const expr = exprPath as NodePath<t.MemberExpression>;
1074 + const objectPath = expr.get("object");
1075 + todoInvariant(objectPath.isLVal(), "Support complex object assignment");
1076 + const object = lowerLVal(builder, objectPath);
1077 + const propertyPath = expr.get("property");
1078 + todoInvariant(
1079 + propertyPath.isIdentifier(),
1080 + "Support non-identifier properties"
1081 + );
1082 + const place: Place = {
1083 + kind: "Identifier",
1084 + value: object.value,
1085 + memberPath: [...(object.memberPath ?? []), propertyPath.node.name],
1086 + capability: Capability.Unknown,
1087 + path: exprPath,
1088 + };
1089 + return place;
1090 + }
1091 + default: {
1092 + todo(`lowerLVal(${exprNode.type})`);
1093 + // assertExhaustive(exprNode, "Unexpected lval kind");
1094 + }
1095 + }
1096 +}
compiler/forget/src/HIR/Codegen.ts new
+343
@@ -0,0 +1,343 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +import * as t from "@babel/types";
9 +import { assertExhaustive } from "../Common/utils";
10 +import { invariant } from "../CompilerError";
11 +import {
12 + BasicBlock,
13 + HIR,
14 + HIRFunction,
15 + Identifier,
16 + IdentifierId,
17 + Instruction,
18 + Place,
19 +} from "./HIR";
20 +import { todoInvariant } from "./todo";
21 +
22 +/**
23 + * Converts HIR into Babel nodes, which can then be printed into source text.
24 + * Note that converting source to HIR and back is not guaranteed to produce
25 + * identicl source text: instead, it is guaranteed to produce semantically
26 + * equivalent JavaScript. Where possible the original shape of the source
27 + * code is preserved. Notably, temporary variables are only introduced
28 + * where strictly necessary such that in general the only variable declarations
29 + * that appear in the output are those that appeared in the input.
30 + *
31 + * However, it is expected that minor changes may occur, such as splitting
32 + * multiple variable declarations into one, converting `else` branches
33 + * into fallthrough branches, etc.
34 + *
35 + * Also, the *semantics* of variable resolution are preserved, but the exact
36 + * original block structure is *not* guaranteed to be preserved. As such,
37 + * variable names in the output may have a suffix attached to distinguish them.
38 + * It is expected that the output will be passed through a minifier which can
39 + * rename variables to reduce code size. In theory minification could be
40 + * performed as an HIR optimization pass, that is left todo for the time being.
41 + */
42 +export default function codegen(fn: HIRFunction): t.Function {
43 + const entry = fn.body.blocks.get(fn.body.entry)!;
44 + const cx: Context = { ir: fn.body, temp: new Map() };
45 + const body = codegenBlock(cx, entry);
46 + const node = fn.path.node;
47 + todoInvariant(
48 + t.isFunctionDeclaration(node),
49 + "todo: handle other than function declaration"
50 + );
51 + const params = fn.params.map((param) => convertIdentifier(param));
52 + return t.functionDeclaration(
53 + fn.id !== null ? convertIdentifier(fn.id) : null,
54 + params,
55 + body,
56 + node.generator,
57 + node.async
58 + );
59 +}
60 +
61 +type Context = {
62 + ir: HIR;
63 + temp: Map<IdentifierId, t.Expression>;
64 +};
65 +
66 +function codegenBlock(cx: Context, block: BasicBlock): t.BlockStatement {
67 + const body: Array<t.Statement> = [];
68 + writeBlock(cx, block, body);
69 + return t.blockStatement(body);
70 +}
71 +
72 +function writeBlock(cx: Context, block: BasicBlock, body: Array<t.Statement>) {
73 + for (const instr of block.instructions) {
74 + writeInstr(cx, instr, body);
75 + }
76 + switch (block.terminal.kind) {
77 + case "return": {
78 + const value =
79 + block.terminal.value != null
80 + ? codegenPlace(cx, block.terminal.value)
81 + : null;
82 + body.push(t.returnStatement(value));
83 + break;
84 + }
85 + case "throw": {
86 + const value = codegenPlace(cx, block.terminal.value);
87 + body.push(t.throwStatement(value));
88 + break;
89 + }
90 + case "if": {
91 + const test = codegenPlace(cx, block.terminal.test);
92 + const consequent = codegenBlock(
93 + cx,
94 + cx.ir.blocks.get(block.terminal.consequent)!
95 + );
96 + const fallthrough =
97 + block.terminal.fallthrough !== null &&
98 + block.terminal.fallthrough !== block.terminal.alternate
99 + ? block.terminal.fallthrough
100 + : null;
101 + if (fallthrough !== null) {
102 + const alternate = codegenBlock(
103 + cx,
104 + cx.ir.blocks.get(block.terminal.alternate)!
105 + );
106 + body.push(t.ifStatement(test, consequent, alternate));
107 + const fallthroughBlock = cx.ir.blocks.get(fallthrough)!;
108 + writeBlock(cx, fallthroughBlock, body);
109 + } else {
110 + body.push(t.ifStatement(test, consequent));
111 + writeBlock(cx, cx.ir.blocks.get(block.terminal.alternate)!, body);
112 + }
113 + break;
114 + }
115 + case "goto": {
116 + body.push(
117 + t.expressionStatement(
118 + t.stringLiteral("<<TODO: handle complex control flow in codegen>>")
119 + )
120 + );
121 + break;
122 + }
123 + case "switch": {
124 + body.push(
125 + t.expressionStatement(
126 + t.stringLiteral("<<TODO: handle switch in codegen>>")
127 + )
128 + );
129 + break;
130 + }
131 + default: {
132 + assertExhaustive(block.terminal, "Unexpected terminal");
133 + }
134 + }
135 +}
136 +
137 +function writeInstr(cx: Context, instr: Instruction, body: Array<t.Statement>) {
138 + let value;
139 + const instrValue = instr.value;
140 + switch (instrValue.kind) {
141 + case "ArrayExpression": {
142 + const elements = instrValue.elements.map((element) =>
143 + codegenPlace(cx, element)
144 + );
145 + value = t.arrayExpression(elements);
146 + break;
147 + }
148 + case "BinaryExpression": {
149 + const left = codegenPlace(cx, instrValue.left);
150 + const right = codegenPlace(cx, instrValue.right);
151 + value = t.binaryExpression(instrValue.operator, left, right);
152 + break;
153 + }
154 + case "UnaryExpression": {
155 + value = t.unaryExpression(
156 + instrValue.operator as "throw", // todo
157 + codegenPlace(cx, instrValue.value)
158 + );
159 + break;
160 + }
161 + case "Primitive": {
162 + value = codegenValue(cx, instrValue.value);
163 + break;
164 + }
165 + case "CallExpression": {
166 + const callee = codegenPlace(cx, instrValue.callee);
167 + const args = instrValue.args.map((arg) => codegenPlace(cx, arg));
168 + value = t.callExpression(callee, args);
169 + break;
170 + }
171 + case "NewExpression": {
172 + const callee = codegenPlace(cx, instrValue.callee);
173 + const args = instrValue.args.map((arg) => codegenPlace(cx, arg));
174 + value = t.newExpression(callee, args);
175 + break;
176 + }
177 + case "ObjectExpression": {
178 + const properties = [];
179 + if (instrValue.properties !== null) {
180 + for (const [property, value] of Object.entries(instrValue.properties)) {
181 + properties.push(
182 + t.objectProperty(t.stringLiteral(property), codegenPlace(cx, value))
183 + );
184 + }
185 + }
186 + value = t.objectExpression(properties);
187 + break;
188 + }
189 + case "JSXText": {
190 + value = t.stringLiteral(instrValue.value);
191 + break;
192 + }
193 + case "JsxExpression": {
194 + const attributes: Array<t.JSXAttribute> = [];
195 + for (const [prop, value] of Object.entries(instrValue.props)) {
196 + attributes.push(
197 + t.jsxAttribute(
198 + t.jsxIdentifier(prop),
199 + t.jsxExpressionContainer(codegenPlace(cx, value))
200 + )
201 + );
202 + }
203 + let tagValue = codegenPlace(cx, instrValue.tag);
204 + let tag: string;
205 + if (tagValue.type === "Identifier") {
206 + tag = tagValue.name;
207 + } else {
208 + invariant(
209 + tagValue.type === "StringLiteral",
210 + "Expected JSX tag to be an identifier or string"
211 + );
212 + tag = tagValue.value;
213 + }
214 + const children =
215 + instrValue.children !== null
216 + ? instrValue.children.map((child) => codegenJsxElement(cx, child))
217 + : [];
218 + value = t.jsxElement(
219 + t.jsxOpeningElement(
220 + t.jsxIdentifier(tag),
221 + attributes,
222 + instrValue.children === null
223 + ),
224 + instrValue.children !== null
225 + ? t.jsxClosingElement(t.jsxIdentifier(tag))
226 + : null,
227 + children,
228 + instrValue.children === null
229 + );
230 + break;
231 + }
232 + case "OtherStatement": {
233 + const node = instrValue.path.node;
234 + if (node != null) {
235 + invariant(
236 + t.isStatement(node),
237 + "Expected node to be a statement if present"
238 + );
239 + body.push(node);
240 + }
241 + return;
242 + }
243 + case "Identifier": {
244 + value = codegenPlace(cx, instrValue);
245 + break;
246 + }
247 + default: {
248 + assertExhaustive(instrValue, "Unexpected instruction kind");
249 + }
250 + }
251 + if (instr.place !== null) {
252 + if (
253 + instr.place.kind === "Identifier" &&
254 + instr.place.value.name === null &&
255 + instr.place.memberPath === null
256 + ) {
257 + // Temporary value: don't immediately emit, instead save the value to refer to later
258 + cx.temp.set(instr.place.value.id, value);
259 + } else {
260 + body.push(
261 + t.expressionStatement(
262 + t.assignmentExpression("=", codegenLVal(instr.place), value)
263 + )
264 + );
265 + }
266 + } else {
267 + body.push(t.expressionStatement(value));
268 + }
269 +}
270 +
271 +function codegenJsxElement(
272 + cx: Context,
273 + place: Place
274 +):
275 + | t.JSXText
276 + | t.JSXExpressionContainer
277 + | t.JSXSpreadChild
278 + | t.JSXElement
279 + | t.JSXFragment {
280 + const value = codegenPlace(cx, place);
281 + switch (value.type) {
282 + case "StringLiteral": {
283 + return t.jsxText(value.value);
284 + }
285 + default: {
286 + return t.jsxExpressionContainer(value);
287 + }
288 + }
289 +}
290 +
291 +function codegenLVal(place: Place): t.LVal {
292 + switch (place.kind) {
293 + case "Identifier": {
294 + return convertIdentifier(place.value);
295 + }
296 + default: {
297 + throw new Error("todo other lval kinds");
298 + }
299 + }
300 +}
301 +
302 +function codegenValue(
303 + cx: Context,
304 + value: boolean | number | string | null | undefined
305 +): t.Expression {
306 + if (typeof value === "number") {
307 + return t.numericLiteral(value);
308 + } else if (typeof value === "boolean") {
309 + return t.booleanLiteral(value);
310 + } else if (typeof value === "string") {
311 + return t.stringLiteral(value);
312 + } else if (value === null) {
313 + return t.nullLiteral();
314 + } else if (value === undefined) {
315 + return t.identifier("undefined");
316 + } else {
317 + assertExhaustive(value, "Unexpected primitive value kind");
318 + }
319 +}
320 +
321 +function codegenPlace(cx: Context, place: Place): t.Expression {
322 + todoInvariant(place.kind === "Identifier", "support scope values");
323 + if (place.memberPath === null) {
324 + let tmp = cx.temp.get(place.value.id);
325 + if (tmp != null) {
326 + return tmp;
327 + }
328 + return convertIdentifier(place.value);
329 + } else {
330 + let object: t.Expression = convertIdentifier(place.value);
331 + for (const path of place.memberPath) {
332 + object = t.memberExpression(object, t.identifier(path));
333 + }
334 + return object;
335 + }
336 +}
337 +
338 +function convertIdentifier(identifier: Identifier): t.Identifier {
339 + if (identifier.name !== null) {
340 + return t.identifier(`${identifier.name}$${identifier.id}`);
341 + }
342 + return t.identifier(`t${identifier.id}`);
343 +}
compiler/forget/src/HIR/DisjointSet.ts new
+86
@@ -0,0 +1,86 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +import { invariant } from "../CompilerError";
9 +
10 +/**
11 + * Represents items which form disjoint sets.
12 + */
13 +export default class DisjointSet<T> {
14 + #entries: Map<T, T> = new Map();
15 +
16 + /**
17 + * Updates the graph to reflect that the given @param items form a set,
18 + * linking any previous sets that the items were part of into a single
19 + * set.
20 + */
21 + union(items: Array<T>) {
22 + const first = items.shift();
23 + invariant(first != null, "Expected set to be non-empty");
24 + // determine an arbitrary "root" for this set: if the first
25 + // item already has a root use that, otherwise the first item
26 + // will be the new root.
27 + let root = this.#entries.get(first);
28 + if (root == null) {
29 + root = first;
30 + this.#entries.set(first, first);
31 + }
32 + // update remaining items (which may already be part of other sets)
33 + for (const item of items) {
34 + let parent = this.#entries.get(item);
35 + if (parent == null) {
36 + // new item, no existing set to update
37 + this.#entries.set(item, root);
38 + continue;
39 + } else if (parent === root) {
40 + continue;
41 + } else {
42 + let current = item;
43 + while (parent !== root && parent !== current) {
44 + this.#entries.set(current, root);
45 + current = parent;
46 + parent = this.#entries.get(current)!;
47 + }
48 + }
49 + }
50 + }
51 +
52 + /**
53 + * Finds the set to which the given @param item is associated, if @param item
54 + * is present in this set. If item is not present, returns null.
55 + *
56 + * Note that the returned value may be any item in the set to which the input
57 + * belongs: the only guarantee is that all items in a set will return the same
58 + * value in between calls to `union()`.
59 + */
60 + find(item: T): T | null {
61 + if (!this.#entries.has(item)) {
62 + return null;
63 + }
64 + let current = item;
65 + let parent = this.#entries.get(current)!;
66 + while (current !== parent) {
67 + current = parent;
68 + parent = this.#entries.get(current)!;
69 + }
70 + if (item !== current) {
71 + this.#entries.set(item, current);
72 + }
73 + return current;
74 + }
75 +
76 + /**
77 + * Calls the provided callback once for each item in the disjoint set,
78 + * passing the @param item and the @param group to which it belongs.
79 + */
80 + forEach(fn: (item: T, group: T) => void) {
81 + for (const item of this.#entries.keys()) {
82 + const group = this.find(item)!;
83 + fn(item, group);
84 + }
85 + }
86 +}
compiler/forget/src/HIR/HIR.ts new
+265
@@ -0,0 +1,265 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +import { NodePath } from "@babel/core";
9 +import * as t from "@babel/types";
10 +import { invariant } from "../CompilerError";
11 +
12 +// *******************************************************************************************
13 +// *******************************************************************************************
14 +// ************************************* Core Data Model *************************************
15 +// *******************************************************************************************
16 +// *******************************************************************************************
17 +
18 +// option 1: control dependencies using CFG (done in Joe's PR)
19 +// option 2: reachability (did execution reach this point last time, if not calculate)
20 +// option 3: push change variable calculation to point of use (more allocations)
21 +// option 4: compute intermediates
22 +
23 +// AST -> (lowering) -> HIR -> (dep analysis) -> Reactive Scopes -> (scheduling?) -> HIR -> (codegen) -> AST
24 +
25 +/**
26 + * A React function defines a computation that takes some set of reactive
27 + * inputs (eg props, hook arguments) and returns a result (JSX, hook return
28 + * value). It is composed of one or more Reactive Scopes, where each
29 + * Reactive Scope takes a set of reactive inputs and produces one *or more*
30 + * result values. The idea is that each Reactive Scope is responsible for
31 + * producing its result values whenever its inputs change: scopes contain
32 + * instructions to produce the result values, deriving from the inputs
33 + * as well as from the results of other scopes.
34 + *
35 + * A React function comprises a Reactive Scope responsible for producing the
36 + * return value of the function, plus additional scopes that the return scopes
37 + * may depend upon (transitively).
38 + */
39 +export type ReactFunction = {
40 + path: NodePath<t.Function>;
41 + id: Identifier | null;
42 + params: Array<Identifier>;
43 + returnScope: ScopeId;
44 + scopes: Map<ScopeId, ReactiveScope>;
45 +};
46 +
47 +/**
48 + * Each scope has a set of inputs (which is loosely defined as stages of analysis
49 + * may refine the set of inputs), a set of outputs (values it will produce), and
50 + * a set of instructions to produce the outputs from the inputs.
51 + */
52 +export type ReactiveScope = {
53 + inputs: Set<Place>;
54 + outputs: Set<Place>;
55 + instructions: HIR;
56 +};
57 +
58 +/**
59 + * A function declaration including its path
60 + */
61 +export type HIRFunction = {
62 + path: NodePath<t.Function>;
63 + id: Identifier | null;
64 + params: Array<Identifier>;
65 + body: HIR;
66 +};
67 +
68 +/**
69 + * Each reactive scope may have its own control-flow, so the instructions form
70 + * a control-flow graph. The graph comprises a set of basic blocks which reference
71 + * each other via terminal statements, as well as a reference to the entry block.
72 + */
73 +export type HIR = {
74 + entry: BlockId;
75 + blocks: Map<BlockId, BasicBlock>;
76 +};
77 +
78 +/**
79 + * Each basic block within an instruction graph contains zero or more instructions
80 + * followed by a terminal node. Note that basic blocks always execute consecutively,
81 + * there can be no branching within a block other than for an exception. Exceptions
82 + * can occur pervasively and React runtime is responsible for resetting state when
83 + * an exception occurs, therefore the block model only represents explicit throw
84 + * statements and not implicit exceptions which may occur.
85 + */
86 +export type BasicBlock = {
87 + instructions: Array<Instruction>;
88 + terminal: Terminal;
89 +};
90 +
91 +/**
92 + * Terminal nodes generally represent statements that affect control flow, such as
93 + * for-of, if-else, return, etc.
94 + */
95 +export type Terminal =
96 + | ThrowTerminal
97 + | ReturnTerminal
98 + | GotoTerminal
99 + | IfTerminal
100 + | SwitchTerminal;
101 +
102 +export type ThrowTerminal = { kind: "throw"; value: Place };
103 +export type ReturnTerminal = { kind: "return"; value: Place | null };
104 +export type GotoTerminal = { kind: "goto"; block: BlockId };
105 +export type IfTerminal = {
106 + kind: "if";
107 + test: Place;
108 + consequent: BlockId;
109 + alternate: BlockId;
110 + fallthrough: BlockId | null;
111 +};
112 +export type SwitchTerminal = {
113 + kind: "switch";
114 + test: Place;
115 + cases: Array<{ test: Place | null; block: BlockId }>;
116 + fallthrough: BlockId | null;
117 +};
118 +
119 +/**
120 + * Instructions generally represent expressions but with all nesting flattened away,
121 + * such that all operands to each instruction are either primitive values OR are
122 + * references to a place, which may be a temporary that holds the results of a
123 + * previous instruction. So `foo(bar(a))` would decompose into two instructions,
124 + * one to store `tmp0 = bar(a)`, one for `foo(tmp0)`.
125 + *
126 + * Instructions generally store their value into a Place, though some instructions
127 + * may not produce a value that is necessary to track (for example, class definitions)
128 + * or may occur only for side-effects (many expression statements).
129 + */
130 +export type Instruction = {
131 + place: Place | null;
132 + value: InstructionValue;
133 + path: NodePath;
134 +};
135 +
136 +/**
137 + * A value that may be assigned to a place. Similar to instructions, values
138 + * are not recursive: complex values such as objects or arrays are always
139 + * defined by Instructions to construct a temporary Place, and then referring
140 + * to that Place.
141 + *
142 + * Values are therefore only a Place or a primitive value.
143 + */
144 +export type InstructionValue = (InstructionData & { path: NodePath }) | Place;
145 +
146 +export type InstructionData =
147 + | { kind: "Primitive"; value: number | boolean | string | null | undefined }
148 + | { kind: "JSXText"; value: string }
149 + | {
150 + kind: "BinaryExpression";
151 + operator: t.BinaryExpression["operator"];
152 + left: Place;
153 + right: Place;
154 + }
155 + | { kind: "NewExpression"; callee: Place; args: Array<Place> }
156 + | { kind: "CallExpression"; callee: Place; args: Array<Place> }
157 + | { kind: "UnaryExpression"; operator: string; value: Place }
158 + | {
159 + kind: "JsxExpression";
160 + tag: Place;
161 + props: { [prop: string]: Place };
162 + children: Array<Place> | null; // null === no children
163 + }
164 + | {
165 + kind: "ObjectExpression";
166 + properties: { [property: string]: Place } | null; // null === empty object
167 + }
168 + | { kind: "ArrayExpression"; elements: Array<Place> }
169 +
170 + /**
171 + * Catch-all for statements such as type imports, nested class declarations, etc
172 + * which are not directly represented, but included for completeness and to allow
173 + * passing through in codegen.
174 + */
175 + | { kind: "OtherStatement" };
176 +
177 +/**
178 + * A place where data may be read from / written to:
179 + * - a variable (identifier)
180 + * - a path into an identifier
181 + */
182 +export type Place = {
183 + kind: "Identifier";
184 + value: Identifier;
185 + memberPath: Array<string> | null;
186 + capability: Capability;
187 + path: NodePath;
188 +};
189 +
190 +/**
191 + * A primitive value with a specific (constant) value.
192 + */
193 +export type Primitive = {
194 + kind: "Primitive";
195 + value: number | boolean | string | null | undefined;
196 + path: NodePath<t.Node | null | undefined>;
197 +};
198 +
199 +/**
200 + * Represents a user-defined variable (has a name) or a temporary variable (no name).
201 + */
202 +export type Identifier = {
203 + id: IdentifierId; // unique value to distinguish different instances of the same name in different scopes
204 + name: string | null; // null for temporaries. name is primarily used for debugging.
205 +};
206 +
207 +/**
208 + * The capability with which a value is modified.
209 + */
210 +export enum Capability {
211 + // Default value: not allowed after lifetime inference
212 + Unknown = "<unknown>",
213 + // The value is known to be deeply, permanently mutable at this point.
214 + Frozen = "frozen",
215 + // The value is not modified at this point or thereafter, but is not guaranteed to be
216 + // frozen. It would be safe to freeze the value at this point.
217 + Readonly = "readonly",
218 + // The value is mutated at this point or at some later point.
219 + Mutable = "mutable",
220 +}
221 +
222 +/**
223 + * Simulated opaque type for BlockIds to prevent using normal numbers as block ids
224 + * accidentally.
225 + */
226 +const opaqueBlockId = Symbol();
227 +export type BlockId = number & { [opaqueBlockId]: "BlockId" };
228 +
229 +export function makeBlockId(id: number): BlockId {
230 + invariant(
231 + id >= 0 && Number.isInteger(id),
232 + "Expected block id to be a non-negative integer"
233 + );
234 + return id as BlockId;
235 +}
236 +
237 +/**
238 + * Simulated opaque type for ScopeIds to prevent using normal numbers as scope ids
239 + * accidentally.
240 + */
241 +const opaqueScopeId = Symbol();
242 +export type ScopeId = number & { [opaqueScopeId]: "ScopeId" };
243 +
244 +export function makeScopeId(id: number): ScopeId {
245 + invariant(
246 + id >= 0 && Number.isInteger(id),
247 + "Expected block id to be a non-negative integer"
248 + );
249 + return id as ScopeId;
250 +}
251 +
252 +/**
253 + * Simulated opaque type for IdentifierId to prevent using normal numbers as ids
254 + * accidentally.
255 + */
256 +const opaqueIdentifierId = Symbol();
257 +export type IdentifierId = number & { [opaqueIdentifierId]: "IdentifierId" };
258 +
259 +export function makeIdentifierId(id: number): IdentifierId {
260 + invariant(
261 + id >= 0 && Number.isInteger(id),
262 + "Expected identifier id to be a non-negative integer"
263 + );
264 + return id as IdentifierId;
265 +}
compiler/forget/src/HIR/HIRBuilder.ts new
+430
@@ -0,0 +1,430 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +import * as t from "@babel/types";
9 +import { assertExhaustive } from "../Common/utils";
10 +import { invariant } from "../CompilerError";
11 +import {
12 + BasicBlock,
13 + BlockId,
14 + HIR,
15 + Identifier,
16 + IdentifierId,
17 + Instruction,
18 + makeBlockId,
19 + makeIdentifierId,
20 + Terminal,
21 +} from "./HIR";
22 +
23 +// *******************************************************************************************
24 +// *******************************************************************************************
25 +// ************************************* Lowering to HIR *************************************
26 +// *******************************************************************************************
27 +// *******************************************************************************************
28 +
29 +/**
30 + * A work-in-progress block that does not yet have a terminator
31 + */
32 +export type WipBlock = { id: BlockId; instructions: Array<Instruction> };
33 +
34 +type Scope = LoopScope | LabelScope | SwitchScope;
35 +
36 +type LoopScope = {
37 + kind: "loop";
38 + label: string | null;
39 + continueBlock: BlockId;
40 + breakBlock: BlockId;
41 +};
42 +
43 +type SwitchScope = {
44 + kind: "switch";
45 + breakBlock: BlockId;
46 + label: string | null;
47 +};
48 +
49 +type LabelScope = {
50 + kind: "label";
51 + label: string;
52 + breakBlock: BlockId;
53 +};
54 +
55 +function newBlock(id: BlockId): WipBlock {
56 + return { id, instructions: [] };
57 +}
58 +
59 +/**
60 + * Helper class for constructing a CFG
61 + */
62 +export default class HIRBuilder {
63 + #completed: Map<BlockId, BasicBlock> = new Map();
64 + #nextId: BlockId = makeBlockId(1);
65 + #current: WipBlock = newBlock(makeBlockId(0));
66 + #entry: BlockId = makeBlockId(0);
67 + #scopes: Array<Scope> = [];
68 + #nextIdentifier: IdentifierId = makeIdentifierId(0);
69 + #bindings: Map<t.Identifier, Identifier> = new Map();
70 +
71 + debug(): string {
72 + return JSON.stringify(
73 + {
74 + completed: this.#completed,
75 + current: this.#current,
76 + nextId: this.#nextId,
77 + },
78 + null,
79 + 2
80 + );
81 + }
82 +
83 + /**
84 + * Push a statement or expression onto the current block
85 + */
86 + push(instruction: Instruction) {
87 + this.#current.instructions.push(instruction);
88 + }
89 +
90 + makeTemporary(): Identifier {
91 + const id = makeIdentifierId(this.#nextIdentifier++);
92 + return {
93 + id,
94 + name: null,
95 + };
96 + }
97 +
98 + resolveIdentifier(node: t.Identifier): Identifier {
99 + let identifier = this.#bindings.get(node);
100 + if (identifier == null) {
101 + const id = makeIdentifierId(this.#nextIdentifier++);
102 + identifier = { id, name: node.name };
103 + this.#bindings.set(node, identifier);
104 + }
105 + return identifier;
106 + }
107 +
108 + /**
109 + * Construct a final CFG from this context
110 + */
111 + build(): HIR {
112 + const { id: blockId, instructions } = this.#current;
113 + this.#completed.set(blockId, {
114 + instructions,
115 + terminal: { kind: "return", value: null },
116 + });
117 + return shrink({
118 + blocks: this.#completed,
119 + entry: this.#entry,
120 + });
121 + }
122 +
123 + /**
124 + * Terminate the current block w the given terminal, and start a new block
125 + */
126 + terminate(terminal: Terminal) {
127 + const { id: blockId, instructions } = this.#current;
128 + this.#completed.set(blockId, {
129 + instructions,
130 + terminal,
131 + });
132 + const nextId = makeBlockId(this.#nextId++);
133 + this.#current = newBlock(nextId);
134 + }
135 +
136 + /**
137 + * Terminate the current block w the given terminal, and set the previously
138 + * reserved block as the new current block
139 + */
140 + terminateWithContinuation(terminal: Terminal, continuation: WipBlock) {
141 + const { id: blockId, instructions } = this.#current;
142 + this.#completed.set(blockId, {
143 + instructions,
144 + terminal,
145 + });
146 + this.#current = continuation;
147 + }
148 +
149 + /**
150 + * Reserve a block so that it can be referenced prior to construction.
151 + * Make this the current block with `terminateWithContinuation()` or
152 + * call `complete()` to save it without setting it as the current block.
153 + */
154 + reserve(): WipBlock {
155 + return newBlock(makeBlockId(this.#nextId++));
156 + }
157 +
158 + /**
159 + * Save a previously reserved block as completed
160 + */
161 + complete(block: WipBlock, terminal: Terminal) {
162 + const { id: blockId, instructions } = block;
163 + this.#completed.set(blockId, { instructions, terminal });
164 + }
165 +
166 + /**
167 + * Create a new block and execute the provided callback with the new block
168 + * set as the current, resetting to the previously active block upon exit.
169 + * The lambda must return a terminal node, which is used to terminate the
170 + * newly constructed block.
171 + */
172 + enter(fn: (blockId: BlockId) => Terminal): BlockId {
173 + const current = this.#current;
174 + const nextId = makeBlockId(this.#nextId++);
175 + this.#current = newBlock(nextId);
176 + const terminal = fn(nextId);
177 + const { id: blockId, instructions } = this.#current;
178 + this.#completed.set(blockId, { instructions, terminal });
179 + this.#current = current;
180 + return nextId;
181 + }
182 +
183 + label<T>(label: string, breakBlock: BlockId, fn: () => T): T {
184 + this.#scopes.push({
185 + kind: "label",
186 + breakBlock,
187 + label,
188 + });
189 + const value = fn();
190 + const last = this.#scopes.pop();
191 + invariant(
192 + last != null &&
193 + last.kind === "label" &&
194 + last.label === label &&
195 + last.breakBlock === breakBlock,
196 + "Mismatched label"
197 + );
198 + return value;
199 + }
200 +
201 + switch<T>(label: string | null, breakBlock: BlockId, fn: () => T): T {
202 + this.#scopes.push({
203 + kind: "switch",
204 + breakBlock,
205 + label,
206 + });
207 + const value = fn();
208 + const last = this.#scopes.pop();
209 + invariant(
210 + last != null &&
211 + last.kind === "switch" &&
212 + last.label === label &&
213 + last.breakBlock === breakBlock,
214 + "Mismatched label"
215 + );
216 + return value;
217 + }
218 +
219 + /**
220 + * Executes the provided lambda inside a scope in which the provided loop
221 + * information is cached for lookup with `lookupBreak()` and `lookupContinue()`
222 + */
223 + loop<T>(
224 + label: string | null,
225 + /**
226 + * block of the loop body. "continue" jumps here.
227 + */
228 + continueBlock: BlockId,
229 + /**
230 + * block following the loop. "break" jumps here.
231 + */
232 + breakBlock: BlockId,
233 + fn: () => T
234 + ): T {
235 + this.#scopes.push({
236 + kind: "loop",
237 + label,
238 + continueBlock,
239 + breakBlock,
240 + });
241 + const value = fn();
242 + const last = this.#scopes.pop();
243 + invariant(
244 + last != null &&
245 + last.kind === "loop" &&
246 + last.label === label &&
247 + last.continueBlock === continueBlock &&
248 + last.breakBlock === breakBlock,
249 + "Mismatched loops"
250 + );
251 + return value;
252 + }
253 +
254 + /**
255 + * Lookup the block target for a break statement, based on loops and switch statements
256 + * in scope. Throws if there is no available location to break.
257 + */
258 + lookupBreak(label: string | null): BlockId {
259 + for (let ii = this.#scopes.length - 1; ii >= 0; ii--) {
260 + const scope = this.#scopes[ii];
261 + if (label === null || label === scope.label) {
262 + return scope.breakBlock;
263 + }
264 + }
265 + invariant(false, "Expected a loop or switch to be in scope");
266 + }
267 +
268 + /**
269 + * Lookup the block target for a continue statement, based on loops
270 + * in scope. Throws if there is no available location to continue, or if the given
271 + * label does not correspond to a loop (this should also be validated at parse time).
272 + */
273 + lookupContinue(label: string | null): BlockId {
274 + for (let ii = this.#scopes.length - 1; ii >= 0; ii--) {
275 + const scope = this.#scopes[ii];
276 + if (scope.kind === "loop") {
277 + if (label === null || label === scope.label) {
278 + return scope.continueBlock;
279 + }
280 + } else if (label !== null && scope.label === label) {
281 + invariant(false, "Continue may only refer to a labeled loop");
282 + }
283 + }
284 + invariant(false, "Expected a loop to be in scope");
285 + }
286 +}
287 +
288 +/**
289 + * Helper to shrink a CFG to eliminate unreachable node and eliminate jump-only blocks.
290 + */
291 +function shrink(func: HIR): HIR {
292 + const gotos = new Map();
293 + /**
294 + * Given a target block for some terminator, resolves the ideal block that should be
295 + * targeted instead. This transitively resolves any blocks that are simple indirections
296 + * (empty blocks that terminate in a goto).
297 + */
298 + function resolveBlockTarget(blockId: BlockId): BlockId {
299 + let target = gotos.get(blockId) ?? null;
300 + if (target !== null) {
301 + return target;
302 + }
303 + const block = func.blocks.get(blockId)!;
304 + target = getTargetIfIndirection(block);
305 + if (target !== null) {
306 + // the target might also be a simple goto, recurse
307 + target = resolveBlockTarget(target) ?? target;
308 + gotos.set(blockId, target);
309 + return target;
310 + } else {
311 + // If the block wasn't an indirection, return the original input.
312 + return blockId;
313 + }
314 + }
315 +
316 + /**
317 + * Fixpoint iteration to explore all blocks reachable from the entry block,
318 + * and to resolve their terminator targets to avoid indirections.
319 + * This implicitly prunes unreachable blocks since they are never visited and
320 + * therefore not added to the output.
321 + */
322 + const queue = [func.entry];
323 + // new set of output blocks
324 + const blocks: Map<BlockId, BasicBlock> = new Map();
325 + while (queue.length !== 0) {
326 + const blockId = queue.shift()!;
327 + if (blocks.has(blockId)) {
328 + continue;
329 + }
330 + const { instructions, terminal: prevTerminal } = func.blocks.get(blockId)!;
331 + const terminal = mapTerminalSuccessors(prevTerminal, (prevTarget) => {
332 + const target = resolveBlockTarget(prevTarget);
333 + queue.push(target);
334 + return target;
335 + });
336 + blocks.set(blockId, {
337 + instructions,
338 + terminal,
339 + });
340 + }
341 +
342 + for (const block of blocks.values()) {
343 + if (block.terminal.kind === "if" || block.terminal.kind === "switch") {
344 + if (
345 + block.terminal.fallthrough !== null &&
346 + !blocks.has(block.terminal.fallthrough)
347 + ) {
348 + block.terminal.fallthrough = null;
349 + }
350 + }
351 + }
352 +
353 + return {
354 + blocks,
355 + entry: func.entry,
356 + };
357 +}
358 +
359 +/**
360 + * If the given block is a simple indirection (empty terminated with a goto),
361 + * returns the block being pointed to. Otherwise returns null
362 + */
363 +function getTargetIfIndirection(block: BasicBlock): number | null {
364 + return block.instructions.length === 0 && block.terminal.kind === "goto"
365 + ? block.terminal.block
366 + : null;
367 +}
368 +
369 +/**
370 + * Maps a terminal node's block assignments using the provided function.
371 + */
372 +function mapTerminalSuccessors(
373 + terminal: Terminal,
374 + fn: (block: BlockId, isFallthrough: boolean) => BlockId
375 +): Terminal {
376 + switch (terminal.kind) {
377 + case "goto": {
378 + const target = fn(terminal.block, false);
379 + return {
380 + kind: "goto",
381 + block: target,
382 + };
383 + }
384 + case "if": {
385 + const consequent = fn(terminal.consequent, false);
386 + const alternate = fn(terminal.alternate, false);
387 + const fallthrough =
388 + terminal.fallthrough !== null ? fn(terminal.fallthrough, true) : null;
389 + return {
390 + kind: "if",
391 + test: terminal.test,
392 + consequent,
393 + alternate,
394 + fallthrough,
395 + };
396 + }
397 + case "switch": {
398 + const cases = terminal.cases.map((case_) => {
399 + const target = fn(case_.block, false);
400 + return {
401 + test: case_.test,
402 + block: target,
403 + };
404 + });
405 + const fallthrough =
406 + terminal.fallthrough !== null ? fn(terminal.fallthrough, true) : null;
407 + return {
408 + kind: "switch",
409 + test: terminal.test,
410 + cases,
411 + fallthrough,
412 + };
413 + }
414 + case "return": {
415 + return {
416 + kind: "return",
417 + value: terminal.value,
418 + };
419 + }
420 + case "throw": {
421 + return terminal;
422 + }
423 + default: {
424 + assertExhaustive(
425 + terminal,
426 + `Unexpected terminal kind '${(terminal as any as Terminal).kind}'`
427 + );
428 + }
429 + }
430 +}
compiler/forget/src/HIR/InferMutability.ts new
+676
@@ -0,0 +1,676 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +import invariant from "invariant";
9 +import { assertExhaustive } from "../Common/utils";
10 +import {
11 + BasicBlock,
12 + BlockId,
13 + Capability,
14 + HIRFunction,
15 + IdentifierId,
16 + Instruction,
17 + InstructionValue,
18 + Place,
19 + Terminal,
20 +} from "./HIR";
21 +import { printMixedHIR, printPlace } from "./PrintHIR";
22 +
23 +const HOOKS: Map<string, Hook> = new Map([
24 + ["useState", { kind: "State", capability: Capability.Frozen }],
25 + ["useRef", { kind: "Ref", capability: Capability.Frozen }],
26 +]);
27 +
28 +type HookKind = { kind: "State" } | { kind: "Ref" } | { kind: "Custom" };
29 +type Hook = HookKind & { capability: Capability };
30 +
31 +/**
32 + * For every usage of a value, infers whether the value is accessed as frozen, mutable,
33 + * or readonly:
34 + * - Frozen: the value is known to be deeply immutable. This usage cannot alter the value,
35 + * and the value cannot change after this usage. The usage can therefore safely memoize
36 + * based on the value.
37 + * - Mutable: the value may be modified by this or a subsequent usage.
38 + * - Readonly: the value is not modified by this or any subsequent usage, but was previously
39 + * mutable. Thus the first usage of a value as readonly (after a previous mutable usage)
40 + * is a point at which the value could safely frozen.
41 + *
42 + * In general usages default to be inferred as readonly (for operations that read) or mutable
43 + * (for operations that may write). Usages can only be inferred as frozen when:
44 + * - The value is derived from a reactive input: props, a hook argument. Derived here means
45 + * that the value is itself a reactive input (`props`) or statically known to be extracted
46 + * purely from a reactive input (`props.a`, `props.a[1]` etc).
47 + * - The value is "moved" into a reactive ouput, ie is captured into a component/hook return
48 + * value.
49 + * - The value is known to be a primitive (boolean, number, string, null, or undefined). This
50 + * is only the case when the value is a constant primitive *or* is the result of an
51 + * operation that, under JS semantics, must produce a primitive. Examples are binary
52 + * expressions.
53 + *
54 + * ## Algorithm
55 + * Fixpoint iteration of the CFG to construct use-use chains (graphs) in which nodes
56 + * are usages of a particular value and the required capability (frozen/read/write),
57 + * and each "usage" node points to predecessor node(s). Iteration stops once no new
58 + * edges/nodes need to be added to the graph.
59 + *
60 + * After construction, walk the graph to propagate frozenness forward and mutability
61 + * backward:
62 + * - If a usage of a value is frozen, then any subsequent usage of that value must be
63 + * frozen as well. Flow the frozenness forward through the graph, following only
64 + * use chains (outoing edges, but not captures).
65 + * - If a usage of a vale is mutable, then any prior readonly references of that value
66 + * must be marked as mutable as well (since there is a subsequent mutation). Again,
67 + * usages only remain readonly if there is no subsequent mutation.
68 + * - Finally, any value that is *initialized* as readonly and never modified (ie, that is
69 + * still readonly in the graph) can be marked frozen (and all of its usages as frozen),
70 + * since it is never ever modified.
71 + */
72 +export default function inferLifetimes(fn: HIRFunction): Map<Place, Vertex> {
73 + const graph = UseGraph.empty();
74 + for (const param of fn.params) {
75 + const place: Place = {
76 + kind: "Identifier",
77 + memberPath: null,
78 + value: param,
79 + path: null as any, // TODO
80 + capability: Capability.Frozen,
81 + };
82 + graph.init(place, null);
83 + }
84 +
85 + const queue: Array<QueueEntry> = [{ block: fn.body.entry, graph }];
86 + const blockMemory: Map<BlockId, UseGraph> = new Map();
87 + while (queue.length !== 0) {
88 + const { block: blockId, graph: inputGraph } = queue.shift()!;
89 + const prevGraph = blockMemory.get(blockId);
90 + let nextGraph = null;
91 + if (prevGraph == null) {
92 + blockMemory.set(blockId, inputGraph);
93 + nextGraph = inputGraph.snapshot();
94 + } else {
95 + const merged = prevGraph.snapshot();
96 + const hasChanges = merged.merge(inputGraph);
97 + if (!hasChanges) {
98 + continue;
99 + }
100 + blockMemory.set(blockId, merged);
101 + nextGraph = prevGraph.snapshot();
102 + }
103 +
104 + const block = fn.body.blocks.get(blockId)!;
105 + inferBlock(nextGraph, block);
106 +
107 + const terminal = block.terminal;
108 + switch (terminal.kind) {
109 + case "throw": {
110 + nextGraph.reference(terminal.value, terminal, Capability.Frozen);
111 + break;
112 + }
113 + case "return": {
114 + if (terminal.value !== null) {
115 + nextGraph.reference(terminal.value, terminal, Capability.Frozen);
116 + }
117 + break;
118 + }
119 + case "goto": {
120 + queue.push({ block: terminal.block, graph: nextGraph });
121 + break;
122 + }
123 + case "if": {
124 + nextGraph.reference(terminal.test, terminal, Capability.Readonly);
125 + queue.push({ block: terminal.consequent, graph: nextGraph });
126 + queue.push({ block: terminal.alternate, graph: nextGraph });
127 + break;
128 + }
129 + case "switch": {
130 + nextGraph.reference(terminal.test, terminal, Capability.Readonly);
131 + for (const case_ of terminal.cases) {
132 + if (case_.test !== null) {
133 + nextGraph.reference(case_.test, terminal, Capability.Readonly);
134 + }
135 + queue.push({ block: case_.block, graph: nextGraph.snapshot() });
136 + }
137 + break;
138 + }
139 + default: {
140 + assertExhaustive(terminal, "Unexpected terminal kind");
141 + }
142 + }
143 + }
144 +
145 + // perform inference over the constructed graph and return it
146 + return analyzeGraph(graph);
147 +}
148 +
149 +type QueueEntry = {
150 + block: BlockId;
151 + graph: UseGraph;
152 +};
153 +
154 +function analyzeGraph(graph: UseGraph): Map<Place, Vertex> {
155 + const vertices = graph.build();
156 + let epoch = 0;
157 +
158 + // First flow frozen values forward through the graph
159 + for (const vertex of vertices.values()) {
160 + if (vertex.place.capability === Capability.Frozen) {
161 + flowFrozennessForwards(vertex, epoch++);
162 + }
163 + }
164 + // Then flow mutability backward through the graph
165 + for (const vertex of vertices.values()) {
166 + if (vertex.place.capability === Capability.Mutable) {
167 + flowMutabilityBackwards(vertex, epoch++);
168 + }
169 + }
170 + // Finally, any *entry* nodes that are readonly are now known to never be mutated,
171 + // so convert them to frozen (and flow that frozenness forward)
172 + for (const vertex of vertices.values()) {
173 + invariant(
174 + vertex.place.capability !== Capability.Unknown,
175 + "Expected capability to have been inferred as frozen, readonly, or mutable"
176 + );
177 + if (
178 + vertex.place.capability === Capability.Readonly &&
179 + vertex.incoming.size === 0
180 + ) {
181 + flowFrozennessForwards(vertex, epoch);
182 + }
183 + }
184 + return vertices;
185 +}
186 +
187 +/**
188 + * Once a value is known to be frozen, all usages forward of that point must be frozen too.
189 + */
190 +function flowFrozennessForwards(vertex: Vertex, epoch: number) {
191 + if (vertex.epoch === epoch) {
192 + return;
193 + }
194 + vertex.epoch = epoch;
195 + vertex.place.capability = Capability.Frozen;
196 + for (const outgoing of vertex.outgoing) {
197 + flowFrozennessForwards(outgoing, epoch);
198 + }
199 +}
200 +
201 +/**
202 + * If a value is known to be mutable, any previous readonly references must be mutable too.
203 + */
204 +function flowMutabilityBackwards(vertex: Vertex, epoch: number) {
205 + if (vertex.epoch === epoch) {
206 + return;
207 + }
208 + vertex.epoch = epoch;
209 + if (vertex.place.capability === Capability.Frozen) {
210 + return;
211 + }
212 + vertex.place.capability = Capability.Mutable;
213 + for (const incoming of vertex.incoming) {
214 + flowMutabilityBackwards(incoming, epoch);
215 + }
216 + for (const [id, capture] of vertex.captures) {
217 + flowMutabilityBackwards(capture, epoch);
218 + }
219 +}
220 +
221 +function inferBlock(graph: UseGraph, block: BasicBlock) {
222 + for (const instr of block.instructions) {
223 + if (instr.place !== null) {
224 + if (instr.place.memberPath == null) {
225 + graph.init(instr.place, instr);
226 + } else {
227 + graph.reference(instr.place, instr, Capability.Mutable);
228 + }
229 + }
230 + const instrValue = instr.value;
231 + let valueCapability = Capability.Readonly;
232 + switch (instrValue.kind) {
233 + case "BinaryExpression": {
234 + valueCapability = Capability.Frozen;
235 + graph.reference(instrValue.left, instrValue, Capability.Readonly);
236 + graph.reference(instrValue.right, instrValue, Capability.Readonly);
237 + break;
238 + }
239 + case "ArrayExpression": {
240 + for (const element of instrValue.elements) {
241 + graph.reference(element, instrValue, Capability.Readonly);
242 + if (instr.place !== null) {
243 + graph.capture(instr.place, instr, element);
244 + }
245 + }
246 + break;
247 + }
248 + case "NewExpression": {
249 + graph.reference(instrValue.callee, instrValue, Capability.Mutable);
250 + let prevArg: Place | null = null;
251 + for (const arg of instrValue.args) {
252 + graph.reference(arg, instrValue, Capability.Mutable);
253 + if (instr.place !== null) {
254 + graph.capture(instr.place, instr, arg);
255 + }
256 + if (prevArg !== null) {
257 + graph.capture(prevArg, instr, arg);
258 + }
259 + prevArg = arg;
260 + }
261 + break;
262 + }
263 + case "CallExpression": {
264 + let capability = Capability.Mutable;
265 + const hook = parseHookCall(instrValue.callee);
266 + if (hook !== null) {
267 + capability = hook.capability;
268 + valueCapability = hook.capability;
269 + }
270 + graph.reference(instrValue.callee, instrValue, capability);
271 + let prevArg: Place | null = null;
272 + for (const arg of instrValue.args) {
273 + graph.reference(arg, instrValue, capability);
274 + if (instr.place !== null) {
275 + graph.capture(instr.place, instr, arg);
276 + }
277 + if (prevArg !== null) {
278 + graph.capture(prevArg, instr, arg);
279 + }
280 + prevArg = arg;
281 + }
282 + break;
283 + }
284 + case "ObjectExpression": {
285 + // Object construction captures but does not modify the key/property values
286 + if (instrValue.properties !== null) {
287 + for (const [_key, value] of Object.entries(instrValue.properties)) {
288 + graph.reference(value, instrValue, Capability.Readonly);
289 + if (instr.place !== null) {
290 + graph.capture(instr.place, instr, value);
291 + }
292 + }
293 + }
294 + break;
295 + }
296 + case "UnaryExpression": {
297 + valueCapability = Capability.Frozen; // TODO check that value must be a primitive, or make conditional based on the operator
298 + graph.reference(instrValue.value, instrValue, Capability.Readonly);
299 + break;
300 + }
301 + case "OtherStatement": {
302 + // TODO: handle other statement kinds
303 + break;
304 + }
305 + case "JsxExpression": {
306 + graph.reference(instrValue.tag, instrValue, Capability.Readonly);
307 + for (const [_prop, value] of Object.entries(instrValue.props)) {
308 + graph.reference(value, instrValue, Capability.Readonly);
309 + if (instr.place !== null) {
310 + graph.capture(instr.place, instr, value);
311 + }
312 + }
313 + if (instrValue.children !== null) {
314 + for (const child of instrValue.children) {
315 + graph.reference(child, instrValue, Capability.Readonly);
316 + if (instr.place !== null) {
317 + graph.capture(instr.place, instr, child);
318 + }
319 + }
320 + }
321 + break;
322 + }
323 + case "JSXText":
324 + case "Primitive": {
325 + valueCapability = Capability.Frozen;
326 + break;
327 + }
328 + case "Identifier": {
329 + graph.reference(instrValue, instrValue, Capability.Readonly);
330 + if (instr.place !== null) {
331 + graph.assign(instr.place, instr, instrValue);
332 + }
333 + valueCapability = instrValue.capability;
334 + break;
335 + }
336 + default: {
337 + assertExhaustive(instrValue, "Unexpected instruction kind");
338 + }
339 + }
340 + if (instr.place !== null) {
341 + instr.place.capability = valueCapability;
342 + }
343 + }
344 +}
345 +
346 +function parseHookCall(place: Place): Hook | null {
347 + if (place.memberPath !== null) {
348 + // Hook calls must be statically resolved
349 + return null;
350 + }
351 + const name = place.value.name;
352 + if (name === null || !name.match(/^_?use/)) {
353 + return null;
354 + }
355 + const hook = HOOKS.get(name);
356 + if (hook != null) {
357 + return hook;
358 + }
359 + return { kind: "Custom", capability: Capability.Frozen };
360 +}
361 +
362 +/**
363 + * A graph of usages of references within a program.
364 + */
365 +class UseGraph {
366 + /**
367 + * Represents the last usage for each top-level identifier (by IdentifierId)
368 + * in the program. So after `let x = []`, there will be an entry mapping
369 + * `x` to a vertex. A subsequent `x.y` reference will update the mapping
370 + * for `x` to point to a new vertex, with the previous `let x = []` as
371 + * an incoming edge. Note again that vertices are always created based
372 + * on the top-level identifier id and ignore member paths.
373 + */
374 + #nodes: Map<IdentifierId, Vertex>;
375 +
376 + /**
377 + * A mapping of places to vertices, allowing repeated operations against
378 + * the same place (eg referencing, assigning, etc) to update the single
379 + * vertex for that place.
380 + *
381 + * NOTE: this algorithm and data structure relies on `Place` instances
382 + * being unique, hence BuildHIR is careful to clone Place instances rather
383 + * than use structural sharing.
384 + */
385 + #vertices: Map<Place, Vertex>;
386 +
387 + static empty(): UseGraph {
388 + return new UseGraph(new Map(), new Map());
389 + }
390 +
391 + constructor(nodes: Map<IdentifierId, Vertex>, vertices: Map<Place, Vertex>) {
392 + this.#nodes = nodes;
393 + this.#vertices = vertices;
394 + }
395 +
396 + /**
397 + * Lookup the current vertex for a given identifier.
398 + */
399 + lookup(id: IdentifierId): Vertex | null {
400 + return this.#nodes.get(id) ?? null;
401 + }
402 +
403 + /**
404 + * Represents assignment of a value to a Place. Unlike with `reference()`,
405 + * this does *not* establish an edge between this usage of the place and
406 + * previous usages, because the value is not the same.
407 + */
408 + init(place: Place, instr: Instruction | null) {
409 + let vertex = this.#vertices.get(place);
410 + if (vertex == null) {
411 + vertex = new Vertex(place, instr);
412 + this.#vertices.set(place, vertex);
413 + }
414 + this.#nodes.set(place.value.id, vertex);
415 + }
416 +
417 + /**
418 + * Represents assigning a (new) value to @param target via the given @param instr,
419 + * with @param value as the value being assigned.
420 + *
421 + * This breaks the use chain, such that this and subsequent usages of @param target
422 + * are not associated to previous usages. This replicates SSA semantics, conceptually
423 + * @param target is a new place now.
424 + */
425 + assign(target: Place, instr: Instruction, value: Place) {
426 + this.init(target, instr);
427 + if (value.capability === Capability.Frozen) {
428 + target.capability = Capability.Frozen;
429 + }
430 + this.capture(target, instr, value);
431 + }
432 +
433 + /**
434 + * Represents data flow in which two places capture references to each other,
435 + * such that a mutation of one place may affect data accessible via the other
436 + * place or vice versa. This includes assignment (`x = y`) but also things like
437 + * array or object construction, where `x = [y]` means that modifying either
438 + * `x` or `y` _could_ be visible through either refernece (eg `x[0].foo = ...`)
439 + * would modify `y`.
440 + */
441 + capture(target: Place, instr: Instruction, value: Place) {
442 + const targetVertex = this.#vertices.get(target)!;
443 + const valueVertex = this.#vertices.get(value)!;
444 +
445 + if (
446 + targetVertex.place.capability === Capability.Frozen ||
447 + valueVertex.place.capability === Capability.Frozen
448 + ) {
449 + return;
450 + }
451 +
452 + targetVertex.captures.set(value.value.id, valueVertex);
453 + valueVertex.captures.set(target.value.id, targetVertex);
454 + }
455 +
456 + /**
457 + * Represents a reference (usage of) a Place. This establishes an edge
458 + * with this usage and the previous usage
459 + */
460 + reference(
461 + place: Place,
462 + instr: Instruction | InstructionValue | Terminal,
463 + capability: Capability
464 + ) {
465 + place.capability = capability;
466 + let vertex = this.#vertices.get(place);
467 + if (vertex == null) {
468 + vertex = new Vertex(place, instr);
469 + this.#vertices.set(place, vertex);
470 + }
471 +
472 + let prev = this.#nodes.get(place.value.id);
473 + if (prev != null) {
474 + vertex.incoming.add(prev);
475 + prev.outgoing.add(vertex);
476 +
477 + for (const [id, _vertex] of prev.captures) {
478 + const capture = this.#nodes.get(id)!;
479 + if (capture.captures.has(place.value.id)) {
480 + vertex.captures.set(id, capture);
481 + }
482 + }
483 +
484 + if (prev.place.capability === Capability.Frozen) {
485 + vertex.place.capability = Capability.Frozen;
486 + }
487 + }
488 + this.#nodes.set(place.value.id, vertex);
489 + }
490 +
491 + /**
492 + * Returns a snapshot of the graph that can be used to represent different
493 + * control flows paths, and which later may merge together (see `merge()`).
494 + *
495 + * The snapshot contains a distinct mapping of the most recent vertex per
496 + * identifier, but *shares* the mapping of places to vertices (vertices are
497 + * stable across different control flow paths).
498 + *
499 + * The intent is that fixpoint iteration relies on updating the `#nodes`
500 + * mapping of identifiers to most recent vertex, but the underlying graph
501 + * of vertices is intended to be shared across control flow paths.
502 + */
503 + snapshot(): UseGraph {
504 + const nodes = new Map(this.#nodes);
505 + return new UseGraph(nodes, this.#vertices);
506 + }
507 +
508 + /**
509 + * Giver some @param other use graph that shares an ancestor with @param this,
510 + * merges the graphs together and returns whether there were any changes to
511 + * the underlying edges (if any new edges were added).
512 + *
513 + * Note that @param this and @param other must share an ancestor, ie one must
514 + * be derived from a `snapshot()` of the other, or they must both be derived
515 + * from a `snapshot()` of the same instance.
516 + */
517 + merge(other: UseGraph): boolean {
518 + let hasChange = false;
519 + for (const [id, newIncoming] of other.#nodes) {
520 + const prevIncoming = this.#nodes.get(id);
521 + if (prevIncoming == null || newIncoming === prevIncoming) {
522 + continue;
523 + }
524 + for (const prevOutgoing of prevIncoming.outgoing) {
525 + hasChange =
526 + hasChange ||
527 + !prevOutgoing.incoming.has(newIncoming) ||
528 + !newIncoming.outgoing.has(prevOutgoing);
529 + prevOutgoing.incoming.add(newIncoming);
530 + newIncoming.outgoing.add(prevOutgoing);
531 + }
532 + }
533 + return hasChange;
534 + }
535 +
536 + /**
537 + * Returns the mapping of places to vertices.
538 + */
539 + build(): Map<Place, Vertex> {
540 + return this.#vertices;
541 + }
542 +}
543 +
544 +/**
545 + * Represents a distinct usage of a `Place` within a program. Note that
546 + * vertices are only created for top-level identifiers, not for points
547 + * within an object. So both `x` and `x.y` create vertices for `x`,
548 + * though this is enforced by the _construction_ of vertices in UseGraph,
549 + * not the implementation of Vertex itself.
550 + */
551 +class Vertex {
552 + /**
553 + * A set of vertices whose values are captured into this vertex, keyed
554 + * by the identifier of the captured value. This represents any form
555 + * of capturing, including:
556 + * - direct assignment: `x = y`, `x.y = y`, `x[0] = y` all captures
557 + * x into y and vice-versa.
558 + * - composition of objects into arrays, object, jsx: `<foo>{x}{y}</div>`,
559 + * `{k1: x, k2: y}`, and `[x, y]` all capture x and y into the outer
560 + * value (jsx, object, array, respectively).
561 + * - Mutation that could cause values to take references into each other:
562 + * `foo(x, y)` could modify x and/or y in a way that they are assigned
563 + * into each other (eg it could internally do `x.y = y`, `y.x = x` etc).
564 + *
565 + * Note that the representation only stores *one* vertex for each identifier,
566 + * so eg `y.x = x` the `y` vertex can only store a capture of *one* vertex
567 + * for `x`. If there are multiple potentially prior usages of x when this
568 + * occurs, we have to take care that they are both represnted as captured:
569 + *
570 + * ```javascript
571 + * let x;
572 + * if (cond) {
573 + * x = [1];
574 + * } else {
575 + * x = [2]
576 + * }
577 + * y = x;
578 + * ```
579 + * The final line must reflect that y captures *either* of the two possible
580 + * values of `x`. This is achieved by *first* using `x`, *then* capturing.
581 + * The usage will create a single new `x` vertex in the final scope, to which
582 + * there are two incoming edges. Then the capture of `x` into `y` references
583 + * that single x vertex with two incoming edges. Thus the data model can capture
584 + * this case, but the order of construction is important.
585 + *
586 + * The result is a graph such as:
587 + *
588 + * [x @ let x] -> [ x @ x = [1] ] -> [ x @ y = x]
589 + * └--> [ x @ x = [2] ] ---┘ ↑
590 + * | capture
591 + * ↓
592 + * [ y @ y - x]
593 + *
594 + * Note that it's possible to walk from `y` to both of the possible x values.
595 + */
596 + captures: Map<IdentifierId, Vertex> = new Map();
597 +
598 + /**
599 + * the set of vertices where *this* place was previously referenced
600 + */
601 + incoming: Set<Vertex> = new Set();
602 +
603 + /**
604 + * the set of vertices where *this* place is subseqently referenced
605 + */
606 + outgoing: Set<Vertex> = new Set();
607 +
608 + /**
609 + * The place that is using the value.
610 + */
611 + place: Place;
612 +
613 + /**
614 + * The instruction where the reference occurs (for debugging)
615 + */
616 + instr: Instruction | InstructionValue | Terminal | null;
617 +
618 + /**
619 + * The last epoch in which this vertex was visited. This is used during
620 + * data-flow analysis post construction of the graph to ensure termination
621 + * by avoiding revisiting the same nodes in a given pass.
622 + */
623 + epoch: number | null = null;
624 +
625 + constructor(
626 + place: Place,
627 + instr: Instruction | InstructionValue | Terminal | null
628 + ) {
629 + this.place = place;
630 + this.instr = instr;
631 + }
632 +}
633 +
634 +/**
635 + * Prints the graph into GraphViz DOT format.
636 + * https://graphviz.org/doc/info/lang.html
637 + */
638 +export function printGraph(vertices: Map<Place, Vertex>): string {
639 + const output = [];
640 +
641 + // Maps vertices to short string names. Note that multiple vertex instances
642 + // can share the same Place, so we can't use the place (identifier/path etc).
643 + // Instead we create an auto-incrementing index.
644 + const indices: Map<Vertex, string> = new Map();
645 + function identify(vertex: Vertex): string {
646 + let id = indices.get(vertex);
647 + if (id == null) {
648 + id = `v${indices.size}`;
649 + indices.set(vertex, id);
650 + }
651 + return id;
652 + }
653 +
654 + for (const [place, vertex] of vertices) {
655 + const vertexId = identify(vertex);
656 + output.push(
657 + `${vertexId} [ label="${vertexId} (${printPlace(vertex.place)} @ ${
658 + vertex.instr
659 + ? printMixedHIR(vertex.instr).replaceAll('"', '\\"')
660 + : "<no-instr>"
661 + })", shape="box" ]`
662 + );
663 + for (const outgoing of vertex.outgoing) {
664 + const outgoingId = identify(outgoing);
665 + output.push(`${vertexId} -> ${outgoingId}`);
666 + }
667 + for (const [id, capture] of vertex.captures) {
668 + const captureId = identify(capture);
669 + output.push(`${captureId} -> ${vertexId} [ label="capture" ]`);
670 + }
671 + }
672 + const lines = output.map((line) => " " + line);
673 + lines.unshift("digraph InferMutability {");
674 + lines.push("}");
675 + return lines.join("\n");
676 +}
compiler/forget/src/HIR/PrintHIR.ts new
+216
@@ -0,0 +1,216 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +import { assertExhaustive } from "../Common/utils";
9 +import { HIR, Instruction, InstructionValue, Place, Terminal } from "./HIR";
10 +
11 +export type Options = {
12 + indent: number;
13 +};
14 +
15 +export default function printHIR(
16 + ir: HIR,
17 + options: Options | null = null
18 +): string {
19 + let output = [];
20 + let indent = " ".repeat(options?.indent ?? 0);
21 + const push = (text: string, indent: string = " ") => {
22 + output.push(`${indent}${text}`);
23 + };
24 + for (const [blockId, block] of ir.blocks) {
25 + output.push(`bb${blockId}:`);
26 + for (const instr of block.instructions) {
27 + push(printInstruction(instr));
28 + }
29 + const terminal = printTerminal(block.terminal);
30 + if (Array.isArray(terminal)) {
31 + terminal.forEach((line) => push(line));
32 + } else {
33 + push(terminal);
34 + }
35 + }
36 + return output.map((line) => indent + line).join("\n");
37 +}
38 +
39 +export function printMixedHIR(
40 + value: Instruction | InstructionValue | Terminal
41 +): string {
42 + if (!("kind" in value)) {
43 + return printInstruction(value);
44 + }
45 + switch (value.kind) {
46 + case "if":
47 + case "return":
48 + case "switch":
49 + case "throw":
50 + case "goto": {
51 + const terminal = printTerminal(value);
52 + if (Array.isArray(terminal)) {
53 + return terminal.join("; ");
54 + }
55 + return terminal;
56 + }
57 + default: {
58 + return printInstructionValue(value);
59 + }
60 + }
61 +}
62 +
63 +function printInstruction(instr: Instruction): string {
64 + const value = printInstructionValue(instr.value);
65 +
66 + if (instr.place !== null) {
67 + return `${printPlace(instr.place)} = ${value}`;
68 + } else {
69 + return value;
70 + }
71 +}
72 +
73 +function printTerminal(terminal: Terminal): Array<string> | string {
74 + let value;
75 + switch (terminal.kind) {
76 + case "if": {
77 + value = `If (${printPlace(terminal.test)}) then:bb${
78 + terminal.consequent
79 + } else:bb${terminal.alternate}`;
80 + break;
81 + }
82 + case "throw": {
83 + value = `Throw ${printPlace(terminal.value)}`;
84 + break;
85 + }
86 + case "return": {
87 + value = `Return${
88 + terminal.value != null ? " " + printPlace(terminal.value) : ""
89 + }`;
90 + break;
91 + }
92 + case "goto": {
93 + value = `Goto bb${terminal.block}`;
94 + break;
95 + }
96 + case "switch": {
97 + const output = [];
98 + output.push(`Switch (${printPlace(terminal.test)})`);
99 + terminal.cases.forEach((case_) => {
100 + if (case_.test !== null) {
101 + output.push(` Case ${printPlace(case_.test)}: bb${case_.block}`);
102 + } else {
103 + output.push(` Default: bb${case_.block}`);
104 + }
105 + });
106 + value = output;
107 + break;
108 + }
109 + default: {
110 + assertExhaustive(
111 + terminal,
112 + `Unexpected terminal kind '${terminal as any as Terminal}'`
113 + );
114 + }
115 + }
116 + return value;
117 +}
118 +
119 +function printInstructionValue(instrValue: InstructionValue): string {
120 + let value = "";
121 + switch (instrValue.kind) {
122 + case "ArrayExpression": {
123 + value = `Array [${instrValue.elements
124 + .map((element) => printPlace(element))
125 + .join(", ")}]`;
126 + break;
127 + }
128 + case "ObjectExpression": {
129 + const properties = [];
130 + if (instrValue.properties !== null) {
131 + for (const [key, value] of Object.entries(instrValue.properties)) {
132 + properties.push(`${key}: ${printPlace(value)}`);
133 + }
134 + }
135 + value = `Object { ${properties.join(", ")} }`;
136 + break;
137 + }
138 + case "UnaryExpression": {
139 + value = `Unary ${printPlace(instrValue.value)}`;
140 + break;
141 + }
142 + case "BinaryExpression": {
143 + value = `Binary ${printPlace(instrValue.left)} ${
144 + instrValue.operator
145 + } ${printPlace(instrValue.right)}`;
146 + break;
147 + }
148 + case "CallExpression": {
149 + value = `Call ${printPlace(instrValue.callee)}(${instrValue.args
150 + .map((arg) => printPlace(arg))
151 + .join(", ")})`;
152 + break;
153 + }
154 + case "JSXText":
155 + case "Primitive": {
156 + value = JSON.stringify(instrValue.value);
157 + break;
158 + }
159 + case "JsxExpression": {
160 + const propItems = [];
161 + for (const [prop, value] of Object.entries(instrValue.props)) {
162 + propItems.push(`${prop}={${printPlace(value)}}`);
163 + }
164 + const props = propItems.length !== 0 ? " " + propItems.join(" ") : "";
165 + if (instrValue.children !== null) {
166 + const children = instrValue.children.map((child) => {
167 + return `{${printPlace(child)}}`;
168 + });
169 + value = `JSX <${printPlace(instrValue.tag)}${props}${
170 + props.length > 0 ? " " : ""
171 + }>${children.join("")}</${printPlace(instrValue.tag)}>`;
172 + } else {
173 + value = `JSX <${printPlace(instrValue.tag)}${props}${
174 + props.length > 0 ? " " : ""
175 + }/>`;
176 + }
177 + break;
178 + }
179 + case "NewExpression": {
180 + value = `New ${printPlace(instrValue.callee)}(${instrValue.args
181 + .map((arg) => printPlace(arg))
182 + .join(", ")})`;
183 + break;
184 + }
185 + case "OtherStatement": {
186 + value = `Other(${instrValue.path?.node?.type}): \`${String(
187 + instrValue.path
188 + )}\``;
189 + break;
190 + }
191 + case "Identifier": {
192 + value = printPlace(instrValue);
193 + break;
194 + }
195 + default: {
196 + assertExhaustive(
197 + instrValue,
198 + `Unexpected instruction kind '${
199 + (instrValue as any as InstructionValue).kind
200 + }'`
201 + );
202 + }
203 + }
204 + return value;
205 +}
206 +
207 +export function printPlace(place: Place): string {
208 + const items = [place.capability, " ", place.value.name, "$", place.value.id];
209 + if (place.memberPath != null) {
210 + for (const path of place.memberPath) {
211 + items.push(".");
212 + items.push(path);
213 + }
214 + }
215 + return items.filter((x) => x != null).join("");
216 +}
compiler/forget/src/HIR/ScopeAnalysis.ts new
+430
@@ -0,0 +1,430 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +import { assertExhaustive } from "../Common/utils";
9 +import { invariant } from "../CompilerError";
10 +import DisjointSet from "./DisjointSet";
11 +import {
12 + BasicBlock,
13 + BlockId,
14 + Capability,
15 + HIR,
16 + HIRFunction,
17 + IdentifierId,
18 + Instruction,
19 + InstructionValue,
20 + makeScopeId,
21 + Place,
22 + ReactFunction,
23 + ReactiveScope,
24 + ScopeId,
25 + Terminal,
26 +} from "./HIR";
27 +import todo from "./todo";
28 +
29 +// import * as t from "@babel/types";
30 +
31 +/**
32 + * Converts a function in standard HIR form into a reactive function, breaking down
33 + * the function's body to determine a set of minimal scopes which define computation
34 + * of sub-expressions in the input. A separate phase can then reconstruct an HIR
35 + * function given the reactive function using various heuristics for codegen.
36 + *
37 + * ## algorithm
38 + * We want to find minimal sets of instructions which build up values. This
39 + * involves determining which values "construct together". Values that construct
40 + * together derive from:
41 + * * mutable accesses that may capture one value into another:
42 + * `x = y`, `foo(x, y)`
43 + * The intuition is that because a mutable reference can be captured, we have
44 + * to assume that further modifications of one value may affect the other and
45 + * vice versa, so their construction must be grouped together.
46 + *
47 + * * constructing independent values across the same control flow path:
48 + * `let x = ..., y = ...; if (cond) {x.a = ...; y.b = ...; }`
49 + * The intuition here is that we don't want to repeat control-flow constructs,
50 + * (esp loops) so values that are constructed across multiple basic blocks
51 + * get grouped together.
52 + *
53 + * Once we've grouped values that "construct together", we can then create one
54 + * scope per group. we iterate back over the CFG, and for each instruction/terminal
55 + * we figure out which group that belongs to, based on the set of values its creating,
56 + * and push it onto the appropriate group's CFG.
57 + *
58 + * as an extra optimization to avoid creating scopes for primitives, we can try to
59 + * infer that instructions that produce primitives don't get their own scope.
60 + * so in `tmp1 = a * b; tmp2 = tmp1 * 3; tmp3 = tmp2 > 10`, we can say that tmp1/2/3
61 + * are all primitives, so they should be grouped together even though they don't
62 + * mutate together, and even though there's no control flow.
63 + *
64 + * we'll also need use-def analysis (or similar) to avoid reassignment of variables
65 + * causing overly large grouping of scopes. we really care about the *values* that
66 + * are being constructed together, not the variables. so `foo(x, y)` conjoins x and y,
67 + * but if we later `x = {}; x.a = 5`, that later assignment and modification should *not*
68 + * conjoin with `y`. for now, we accept that these cases will be treated as conjoined and
69 + * grouped together.
70 + */
71 +export default function analyzeScopes(fn: HIRFunction): ReactFunction {
72 + // naive but trivially correct version
73 + const returnScopeId = makeScopeId(0);
74 + const scopes: Map<ScopeId, ReactiveScope> = new Map();
75 + scopes.set(returnScopeId, {
76 + inputs: new Set(
77 + fn.params.map((param) => ({
78 + kind: "Identifier",
79 + value: param,
80 + memberPath: null,
81 + capability: Capability.Frozen,
82 + path: null as any,
83 + }))
84 + ),
85 + outputs: new Set(),
86 + instructions: fn.body,
87 + });
88 + return {
89 + path: fn.path,
90 + id: fn.id,
91 + params: fn.params,
92 + returnScope: returnScopeId,
93 + scopes,
94 + };
95 +}
96 +
97 +/**
98 + * ```javascript
99 + * function Component({items}) {
100 + * const renderedItems = [];
101 + * const seen = new Set();
102 + * for (const item of items) {
103 + * renderedItems.push(<div>{item}</div>);
104 + * seen.add(item);
105 + * }
106 + * return <Child items={renderedItems} seen={seen} />;
107 + * }
108 + * ```
109 + * Iterate over the IR in tree order (similar to codegen) - single pass with recursion.
110 + * Build a stack of control points and mutable values, associate mutable values with
111 + * control points that occur between each other. control points also naturally group
112 + * together, ie for a continue within a loop.
113 + *
114 + *
115 + * Ideas toward an algorithm:
116 + * - Track the lifetime for which each variable (value, really) is mutable.
117 + * - Values with overlapping mutable lifetimes are conjoined ("memoize together").
118 + * - Keep a stack of mutated values which we can walk. But *also* store block terminals in this stack.
119 + * When you walk back up the stack to find previous mutations of a value, add all the terminals
120 + * along the way until finding it as dependencies. eg set.union(mutValue, terminal).
121 + * Two values that mutate across the same control points will union with the same terminal,
122 + * and get conjoined.
123 + *
124 + * Eg in the following, `renderedItems` and `seen` have overlapping mutable lifetimes:
125 + *
126 + * ```javascript
127 + * function Component({items, maxItems}) {
128 + * const renderedItems = []; // new-mutable renderedItems
129 + * const seen = new Set(); // new-mutable seen
130 + * const max = Math.max(0, maxItems); // new-mutable max; read-frozen maxItems
131 + * for (const item of items) { // read-frozen items; control point
132 + * if (item == null || seen.has(item)) { // mutable seen; read-frozen item; control point
133 + * continue; // control point
134 + * }
135 + *
136 + * seen.add(item); // mutable seen; read-frozen item
137 + * // finding prev `mut seen` hops the above control points
138 + * renderedItems.push(<div>{item}</div>); // mutable renderedItems; read-frozen item
139 + * // finding prev `mut renderedItems` hops the above control points
140 + * if (renderedItems.length >= max) { // read-frozen max; read-mutable renderedItems
141 + * break;
142 + * }
143 + * }
144 + * const count = renderedItems.length; // read-frozen renderedItems
145 + * return <div><h1>{count} Items</h1>{renderedItems}</div>; // read-frozen renderedItems
146 + * }
147 + *
148 + * function Component({items, maxItems}) {
149 + * // scope 0 (inputs: maxItems, outputs: max)
150 + * const c_maxItems = ...;
151 + * let max = c_max_items ? Math.max(0, maxItems) : ...;
152 + * const c_max = ...;
153 + *
154 + * // scope 1 (inputs: items, max, ouputs: renderedItems, seen, count)
155 + * const c_items = ...;
156 + * let renderedItems;
157 + * let seen;
158 + * let count;
159 + * if (c_max || c_items) {
160 + * renderedItems = ....;
161 + * seen = ...;
162 + * for (const item of items) {
163 + * if (item == null || seen.has(item)) { // read-mutable seen; read-frozen item; control point
164 + * continue; // control point
165 + * }
166 + * seen.add(item); // mut-mutable seen; read-frozen item
167 + * renderedItems.push(<div>{item}</div>); // mut-mutable renderedItems; read-frozen item
168 + * if (renderedItems.length >= max) { // read-frozen max; read-mutable renderedItems
169 + * break;
170 + * }
171 + * }
172 + * count = renderedItems.length;
173 + * } else {
174 + * // populate from cache
175 + * }
176 + *
177 + * // scope 2 (inputs: count, ouputs: div)
178 + * const c_count = ...;
179 + * let h1;
180 + * if (c_count) {
181 + * h1 = <h1>{count}</h1>
182 + * } // else from cache
183 + *
184 + * // scope 3 (inputs: h1, renderedItems, outputs: outer div)
185 + * const c_h1 = ...;
186 + * const c_renderedItems = ...;
187 + * let ret;
188 + * if (c_h1 || c_renderedItems) {
189 + * ret = <div>{h1}{renderedItems}</div>; // read-frozen renderedItems
190 + * } // else from cache
191 + * return ret;
192 + * }
193 + * ```
194 + */
195 +
196 +function analyze(fn: HIRFunction): ReactFunction {
197 + const returnScopeId = makeScopeId(0);
198 + const scopes: Map<ScopeId, ReactiveScope> = new Map();
199 +
200 + const block = fn.body.blocks.get(fn.body.entry)!;
201 + const context = new Context(fn.body);
202 + analyzeBlock(context, fn.body.entry, block);
203 + context.analyzeControls();
204 +
205 + return {
206 + path: fn.path,
207 + id: fn.id,
208 + params: fn.params,
209 + returnScope: returnScopeId,
210 + scopes,
211 + };
212 +}
213 +
214 +class Context {
215 + #blocks: Map<IdentifierId, Set<BasicBlock>> = new Map();
216 + #groups: DisjointSet<IdentifierId | Instruction | BasicBlock> =
217 + new DisjointSet();
218 + body: HIR;
219 +
220 + constructor(body: HIR) {
221 + this.body = body;
222 + }
223 +
224 + union(items: Array<IdentifierId | Instruction>, block: BasicBlock) {
225 + this.#groups.union(items);
226 + for (const item of items) {
227 + if (typeof item === "number") {
228 + // IdentifierId
229 + let set = this.#blocks.get(item);
230 + if (set == null) {
231 + set = new Set();
232 + this.#blocks.set(item, set);
233 + }
234 + set.add(block);
235 + }
236 + }
237 + }
238 +
239 + /**
240 + * Find items that participate in control flow together
241 + */
242 + analyzeControls() {
243 + const mergeSets: Array<Array<BasicBlock>> = [];
244 + const blocks: Map<BlockId, BasicBlock> = new Map();
245 + this.#groups.forEach((prevItem, prevGroup) => {
246 + this.#groups.forEach((nextItem, nextGroup) => {
247 + if (
248 + prevGroup === nextGroup ||
249 + typeof prevItem !== "number" ||
250 + typeof nextItem !== "number"
251 + ) {
252 + // Already part of the same group, by definition this includes item === nextItem
253 + return;
254 + }
255 + const prevBlocks = this.#blocks.get(prevItem)!;
256 + const nextBlocks = this.#blocks.get(nextItem)!;
257 +
258 + const overlap = [];
259 + for (const block of prevBlocks) {
260 + if (nextBlocks.has(block)) {
261 + overlap.push(block);
262 + }
263 + }
264 + if (overlap.length > 1) {
265 + mergeSets.push(overlap);
266 + }
267 + });
268 + });
269 + for (const set of mergeSets) {
270 + this.#groups.union(set);
271 + }
272 + }
273 +}
274 +
275 +function analyzeBlock(cx: Context, id: BlockId, block: BasicBlock) {
276 + for (const instr of block.instructions) {
277 + const instrValue = instr.value;
278 + let mutables: Array<IdentifierId | Instruction> = [];
279 + switch (instrValue.kind) {
280 + case "JSXText":
281 + case "Primitive": {
282 + // no mutable values
283 + break;
284 + }
285 + case "Identifier": {
286 + const value = getMutable(instrValue);
287 + if (value !== null) {
288 + mutables.push(value);
289 + }
290 + break;
291 + }
292 + case "UnaryExpression": {
293 + const value = getMutable(instrValue.value);
294 + if (value !== null) {
295 + mutables.push(value);
296 + }
297 + break;
298 + }
299 + case "BinaryExpression": {
300 + const left = getMutable(instrValue.left);
301 + const right = getMutable(instrValue.right);
302 + if (left !== null) {
303 + mutables.push(left);
304 + }
305 + if (right !== null) {
306 + mutables.push(right);
307 + }
308 + break;
309 + }
310 + case "ArrayExpression": {
311 + for (const _element of instrValue.elements) {
312 + const element = getMutable(_element);
313 + if (element !== null) {
314 + mutables.push(element);
315 + }
316 + }
317 + break;
318 + }
319 + case "ObjectExpression": {
320 + if (instrValue.properties !== null) {
321 + for (const _value of Object.values(instrValue.properties)) {
322 + const value = getMutable(_value);
323 + if (value !== null) {
324 + mutables.push(value);
325 + }
326 + }
327 + }
328 + break;
329 + }
330 + case "JsxExpression": {
331 + const tag = getMutable(instrValue.tag);
332 + if (tag !== null) {
333 + mutables.push(tag);
334 + }
335 + for (const _prop of Object.values(instrValue.props)) {
336 + const prop = getMutable(_prop);
337 + if (prop !== null) {
338 + mutables.push(prop);
339 + }
340 + }
341 + if (instrValue.children !== null) {
342 + for (const _child of instrValue.children) {
343 + const child = getMutable(_child);
344 + if (child !== null) {
345 + mutables.push(child);
346 + }
347 + }
348 + }
349 + break;
350 + }
351 + case "NewExpression":
352 + case "CallExpression": {
353 + const callee = getMutable(instrValue.callee);
354 + if (callee !== null) {
355 + mutables.push(callee);
356 + }
357 + for (const _arg of instrValue.args) {
358 + const arg = getMutable(_arg);
359 + if (arg !== null) {
360 + mutables.push(arg);
361 + }
362 + }
363 + break;
364 + }
365 + case "OtherStatement": {
366 + // no-op for the value itself
367 + break;
368 + }
369 + default: {
370 + assertExhaustive(
371 + instrValue,
372 + `Unexpected instruction kind '${
373 + (instrValue as any as InstructionValue).kind
374 + }'`
375 + );
376 + }
377 + }
378 + const place = instr.place !== null ? getMutable(instr.place) : null;
379 + invariant(
380 + instr.place === null ||
381 + instr.place.kind !== "Identifier" ||
382 + place !== null,
383 + "Expected instruction assignment target to be inferred as mutable if present."
384 + );
385 + if (place !== null) {
386 + mutables.push(place);
387 + }
388 + if (mutables.length !== 0) {
389 + mutables.push(instr);
390 + cx.union(mutables, block);
391 + }
392 + }
393 + switch (block.terminal.kind) {
394 + case "if": {
395 + const consequent = cx.body.blocks.get(block.terminal.consequent)!;
396 + analyzeBlock(cx, block.terminal.consequent, consequent);
397 + const alternate = cx.body.blocks.get(block.terminal.alternate)!;
398 + analyzeBlock(cx, block.terminal.alternate, alternate);
399 + if (
400 + block.terminal.fallthrough !== null &&
401 + block.terminal.fallthrough !== block.terminal.alternate
402 + ) {
403 + const fallthrough = cx.body.blocks.get(block.terminal.fallthrough)!;
404 + analyzeBlock(cx, block.terminal.fallthrough, fallthrough);
405 + }
406 + break;
407 + }
408 + case "switch": {
409 + todo("implement scope analysis for switch statements");
410 + }
411 + case "throw":
412 + case "return":
413 + case "goto": {
414 + // no-op
415 + break;
416 + }
417 + default: {
418 + assertExhaustive(
419 + block.terminal,
420 + `Unexpected terminal kind '${(block.terminal as any as Terminal).kind}'`
421 + );
422 + }
423 + }
424 +}
425 +
426 +function getMutable(place: Place): IdentifierId | null {
427 + return place.kind === "Identifier" && place.capability === Capability.Mutable
428 + ? place.value.id
429 + : null;
430 +}
compiler/forget/src/HIR/todo.ts new
+19
@@ -0,0 +1,19 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +export default function todo(message: string): never {
9 + throw new Error("TODO: " + message);
10 +}
11 +
12 +export function todoInvariant(
13 + condition: unknown,
14 + message: string
15 +): asserts condition {
16 + if (!condition) {
17 + throw new Error("TODO: " + message);
18 + }
19 +}
compiler/forget/src/__tests__/fixtures/hir-svg/call.svg new
+286
@@ -0,0 +1,286 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4 +<!-- Generated by graphviz version 6.0.1 (20220924.0800)
5 + -->
6 +<!-- Title: InferMutability Pages: 1 -->
7 +<svg width="2349pt" height="723pt"
8 + viewBox="0.00 0.00 2349.17 722.80" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9 +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 718.8)">
10 +<title>InferMutability</title>
11 +<polygon fill="white" stroke="none" points="-4,4 -4,-718.8 2345.17,-718.8 2345.17,4 -4,4"/>
12 +<!-- v0 -->
13 +<g id="node1" class="node">
14 +<title>v0</title>
15 +<polygon fill="none" stroke="black" points="414.41,-714.8 207.57,-714.8 207.57,-678.8 414.41,-678.8 414.41,-714.8"/>
16 +<text text-anchor="middle" x="310.99" y="-692.6" font-family="Times,serif" font-size="14.00">v0 (frozen props$1 @ &lt;no&#45;instr&gt;)</text>
17 +</g>
18 +<!-- v1 -->
19 +<g id="node2" class="node">
20 +<title>v1</title>
21 +<polygon fill="none" stroke="black" points="693.2,-714.8 432.79,-714.8 432.79,-678.8 693.2,-678.8 693.2,-714.8"/>
22 +<text text-anchor="middle" x="562.99" y="-692.6" font-family="Times,serif" font-size="14.00">v1 (mutable a$2 @ mutable a$2 = Array [])</text>
23 +</g>
24 +<!-- v2 -->
25 +<g id="node3" class="node">
26 +<title>v2</title>
27 +<polygon fill="none" stroke="black" points="760.34,-641.8 365.64,-641.8 365.64,-605.8 760.34,-605.8 760.34,-641.8"/>
28 +<text text-anchor="middle" x="562.99" y="-619.6" font-family="Times,serif" font-size="14.00">v2 (mutable a$2 @ Call mutable foo$4(mutable a$2, mutable b$3))</text>
29 +</g>
30 +<!-- v1&#45;&gt;v2 -->
31 +<g id="edge1" class="edge">
32 +<title>v1&#45;&gt;v2</title>
33 +<path fill="none" stroke="black" d="M562.99,-678.61C562.99,-670.59 562.99,-660.85 562.99,-651.87"/>
34 +<polygon fill="black" stroke="black" points="566.49,-651.83 562.99,-641.83 559.49,-651.83 566.49,-651.83"/>
35 +</g>
36 +<!-- v4 -->
37 +<g id="node5" class="node">
38 +<title>v4</title>
39 +<polygon fill="none" stroke="black" points="905.63,-553 510.36,-553 510.36,-517 905.63,-517 905.63,-553"/>
40 +<text text-anchor="middle" x="707.99" y="-530.8" font-family="Times,serif" font-size="14.00">v4 (mutable b$3 @ Call mutable foo$4(mutable a$2, mutable b$3))</text>
41 +</g>
42 +<!-- v2&#45;&gt;v4 -->
43 +<g id="edge7" class="edge">
44 +<title>v2&#45;&gt;v4</title>
45 +<path fill="none" stroke="black" d="M631,-605.77C643.25,-601.05 655.46,-595.14 665.99,-587.8 676.03,-580.81 684.94,-570.76 691.93,-561.38"/>
46 +<polygon fill="black" stroke="black" points="694.9,-563.24 697.8,-553.05 689.18,-559.21 694.9,-563.24"/>
47 +<text text-anchor="middle" x="704.59" y="-575.2" font-family="Times,serif" font-size="14.00">capture</text>
48 +</g>
49 +<!-- v7 -->
50 +<g id="node8" class="node">
51 +<title>v7</title>
52 +<polygon fill="none" stroke="black" points="683.7,-464.2 280.29,-464.2 280.29,-428.2 683.7,-428.2 683.7,-464.2"/>
53 +<text text-anchor="middle" x="481.99" y="-442" font-family="Times,serif" font-size="14.00">v7 (mutable a$2 @ JSX &lt;frozen $6 a={mutable a$2} &gt;&lt;/frozen $6&gt;)</text>
54 +</g>
55 +<!-- v2&#45;&gt;v7 -->
56 +<g id="edge4" class="edge">
57 +<title>v2&#45;&gt;v7</title>
58 +<path fill="none" stroke="black" d="M542.74,-605.64C528.77,-592.65 510.97,-573.56 500.99,-553 488.94,-528.19 484.48,-496.75 482.85,-474.62"/>
59 +<polygon fill="black" stroke="black" points="486.34,-474.35 482.26,-464.57 479.35,-474.76 486.34,-474.35"/>
60 +</g>
61 +<!-- v3 -->
62 +<g id="node4" class="node">
63 +<title>v3</title>
64 +<polygon fill="none" stroke="black" points="1056.06,-641.8 777.93,-641.8 777.93,-605.8 1056.06,-605.8 1056.06,-641.8"/>
65 +<text text-anchor="middle" x="916.99" y="-619.6" font-family="Times,serif" font-size="14.00">v3 (mutable b$3 @ mutable b$3 = Object { &#160;})</text>
66 +</g>
67 +<!-- v3&#45;&gt;v4 -->
68 +<g id="edge2" class="edge">
69 +<title>v3&#45;&gt;v4</title>
70 +<path fill="none" stroke="black" d="M875.7,-605.65C842.07,-591.68 794.44,-571.9 758.53,-556.99"/>
71 +<polygon fill="black" stroke="black" points="759.78,-553.72 749.2,-553.11 757.09,-560.18 759.78,-553.72"/>
72 +</g>
73 +<!-- v4&#45;&gt;v2 -->
74 +<g id="edge5" class="edge">
75 +<title>v4&#45;&gt;v2</title>
76 +<path fill="none" stroke="black" d="M660.57,-553.07C648.55,-558.16 635.9,-564.23 624.8,-571 611.94,-578.85 598.98,-589.24 588.26,-598.67"/>
77 +<polygon fill="black" stroke="black" points="585.63,-596.32 580.55,-605.62 590.32,-601.52 585.63,-596.32"/>
78 +<text text-anchor="middle" x="645.59" y="-575.2" font-family="Times,serif" font-size="14.00">capture</text>
79 +</g>
80 +<!-- v4&#45;&gt;v7 -->
81 +<g id="edge11" class="edge">
82 +<title>v4&#45;&gt;v7</title>
83 +<path fill="none" stroke="black" d="M663.61,-516.95C626.99,-502.89 574.9,-482.88 535.89,-467.9"/>
84 +<polygon fill="black" stroke="black" points="536.86,-464.52 526.27,-464.21 534.35,-471.06 536.86,-464.52"/>
85 +<text text-anchor="middle" x="636.59" y="-486.4" font-family="Times,serif" font-size="14.00">capture</text>
86 +</g>
87 +<!-- v8 -->
88 +<g id="node9" class="node">
89 +<title>v8</title>
90 +<polygon fill="none" stroke="black" points="871.82,-375.4 552.17,-375.4 552.17,-339.4 871.82,-339.4 871.82,-375.4"/>
91 +<text text-anchor="middle" x="711.99" y="-353.2" font-family="Times,serif" font-size="14.00">v8 (mutable b$3 @ Call mutable foo$4(mutable b$3))</text>
92 +</g>
93 +<!-- v4&#45;&gt;v8 -->
94 +<g id="edge6" class="edge">
95 +<title>v4&#45;&gt;v8</title>
96 +<path fill="none" stroke="black" d="M708.38,-516.84C709.08,-486.42 710.53,-422.78 711.36,-386.08"/>
97 +<polygon fill="black" stroke="black" points="714.87,-385.7 711.6,-375.63 707.87,-385.54 714.87,-385.7"/>
98 +</g>
99 +<!-- v5 -->
100 +<g id="node6" class="node">
101 +<title>v5</title>
102 +<polygon fill="none" stroke="black" points="1443.29,-714.8 1036.7,-714.8 1036.7,-678.8 1443.29,-678.8 1443.29,-714.8"/>
103 +<text text-anchor="middle" x="1239.99" y="-692.6" font-family="Times,serif" font-size="14.00">v5 (mutable foo$4 @ Call mutable foo$4(mutable a$2, mutable b$3))</text>
104 +</g>
105 +<!-- v6 -->
106 +<g id="node7" class="node">
107 +<title>v6</title>
108 +<polygon fill="none" stroke="black" points="1405.48,-641.8 1074.51,-641.8 1074.51,-605.8 1405.48,-605.8 1405.48,-641.8"/>
109 +<text text-anchor="middle" x="1239.99" y="-619.6" font-family="Times,serif" font-size="14.00">v6 (mutable foo$4 @ Call mutable foo$4(mutable b$3))</text>
110 +</g>
111 +<!-- v5&#45;&gt;v6 -->
112 +<g id="edge3" class="edge">
113 +<title>v5&#45;&gt;v6</title>
114 +<path fill="none" stroke="black" d="M1239.99,-678.61C1239.99,-670.59 1239.99,-660.85 1239.99,-651.87"/>
115 +<polygon fill="black" stroke="black" points="1243.49,-651.83 1239.99,-641.83 1236.49,-651.83 1243.49,-651.83"/>
116 +</g>
117 +<!-- v7&#45;&gt;v8 -->
118 +<g id="edge14" class="edge">
119 +<title>v7&#45;&gt;v8</title>
120 +<path fill="none" stroke="black" d="M527.16,-428.15C564.5,-414.06 617.66,-394 657.39,-379.01"/>
121 +<polygon fill="black" stroke="black" points="658.81,-382.21 666.93,-375.41 656.34,-375.66 658.81,-382.21"/>
122 +<text text-anchor="middle" x="638.59" y="-397.6" font-family="Times,serif" font-size="14.00">capture</text>
123 +</g>
124 +<!-- v11 -->
125 +<g id="node12" class="node">
126 +<title>v11</title>
127 +<polygon fill="none" stroke="black" points="495.98,-375.4 0.01,-375.4 0.01,-339.4 495.98,-339.4 495.98,-375.4"/>
128 +<text text-anchor="middle" x="247.99" y="-353.2" font-family="Times,serif" font-size="14.00">v11 (mutable _$5 @ mutable _$5 = JSX &lt;frozen $6 a={mutable a$2} &gt;&lt;/frozen $6&gt;)</text>
129 +</g>
130 +<!-- v7&#45;&gt;v11 -->
131 +<g id="edge9" class="edge">
132 +<title>v7&#45;&gt;v11</title>
133 +<path fill="none" stroke="black" d="M420.32,-428.14C402.58,-422.83 383.29,-416.65 365.8,-410.2 341.33,-401.17 314.68,-389.61 292.93,-379.7"/>
134 +<polygon fill="black" stroke="black" points="294.17,-376.41 283.62,-375.42 291.25,-382.78 294.17,-376.41"/>
135 +<text text-anchor="middle" x="386.59" y="-397.6" font-family="Times,serif" font-size="14.00">capture</text>
136 +</g>
137 +<!-- v12 -->
138 +<g id="node13" class="node">
139 +<title>v12</title>
140 +<polygon fill="none" stroke="black" points="720.78,-286.6 197.21,-286.6 197.21,-250.6 720.78,-250.6 720.78,-286.6"/>
141 +<text text-anchor="middle" x="458.99" y="-264.4" font-family="Times,serif" font-size="14.00">v12 (readonly a$2 @ JSX &lt;frozen $7 a={readonly a$2} b={readonly b$3} &gt;&lt;/frozen $7&gt;)</text>
142 +</g>
143 +<!-- v7&#45;&gt;v12 -->
144 +<g id="edge10" class="edge">
145 +<title>v7&#45;&gt;v12</title>
146 +<path fill="none" stroke="black" d="M490.97,-428.14C500.86,-407.05 514.23,-370.19 504.99,-339.4 500.15,-323.25 490.23,-307.38 480.83,-294.86"/>
147 +<polygon fill="black" stroke="black" points="483.41,-292.48 474.48,-286.77 477.9,-296.8 483.41,-292.48"/>
148 +</g>
149 +<!-- v8&#45;&gt;v12 -->
150 +<g id="edge19" class="edge">
151 +<title>v8&#45;&gt;v12</title>
152 +<path fill="none" stroke="black" d="M662.31,-339.35C620.97,-325.17 562.01,-304.94 518.22,-289.92"/>
153 +<polygon fill="black" stroke="black" points="519.16,-286.54 508.56,-286.61 516.88,-293.16 519.16,-286.54"/>
154 +<text text-anchor="middle" x="629.59" y="-308.8" font-family="Times,serif" font-size="14.00">capture</text>
155 +</g>
156 +<!-- v13 -->
157 +<g id="node14" class="node">
158 +<title>v13</title>
159 +<polygon fill="none" stroke="black" points="1042.07,-197.8 517.92,-197.8 517.92,-161.8 1042.07,-161.8 1042.07,-197.8"/>
160 +<text text-anchor="middle" x="779.99" y="-175.6" font-family="Times,serif" font-size="14.00">v13 (readonly b$3 @ JSX &lt;frozen $7 a={readonly a$2} b={readonly b$3} &gt;&lt;/frozen $7&gt;)</text>
161 +</g>
162 +<!-- v8&#45;&gt;v13 -->
163 +<g id="edge13" class="edge">
164 +<title>v8&#45;&gt;v13</title>
165 +<path fill="none" stroke="black" d="M718.64,-339.24C730.52,-308.56 755.49,-244.08 769.64,-207.54"/>
166 +<polygon fill="black" stroke="black" points="772.97,-208.62 773.32,-198.03 766.45,-206.09 772.97,-208.62"/>
167 +</g>
168 +<!-- v9 -->
169 +<g id="node10" class="node">
170 +<title>v9</title>
171 +<polygon fill="none" stroke="black" points="1727.93,-714.8 1514.06,-714.8 1514.06,-678.8 1727.93,-678.8 1727.93,-714.8"/>
172 +<text text-anchor="middle" x="1620.99" y="-692.6" font-family="Times,serif" font-size="14.00">v9 (frozen $6 @ frozen $6 = &quot;div&quot;)</text>
173 +</g>
174 +<!-- v10 -->
175 +<g id="node11" class="node">
176 +<title>v10</title>
177 +<polygon fill="none" stroke="black" points="1818.64,-641.8 1423.34,-641.8 1423.34,-605.8 1818.64,-605.8 1818.64,-641.8"/>
178 +<text text-anchor="middle" x="1620.99" y="-619.6" font-family="Times,serif" font-size="14.00">v10 (frozen $6 @ JSX &lt;frozen $6 a={mutable a$2} &gt;&lt;/frozen $6&gt;)</text>
179 +</g>
180 +<!-- v9&#45;&gt;v10 -->
181 +<g id="edge8" class="edge">
182 +<title>v9&#45;&gt;v10</title>
183 +<path fill="none" stroke="black" d="M1620.99,-678.61C1620.99,-670.59 1620.99,-660.85 1620.99,-651.87"/>
184 +<polygon fill="black" stroke="black" points="1624.49,-651.83 1620.99,-641.83 1617.49,-651.83 1624.49,-651.83"/>
185 +</g>
186 +<!-- v11&#45;&gt;v7 -->
187 +<g id="edge12" class="edge">
188 +<title>v11&#45;&gt;v7</title>
189 +<path fill="none" stroke="black" d="M352.89,-375.42C371.32,-380.11 390.02,-386.01 406.99,-393.4 423.69,-400.67 440.54,-411.88 454.02,-422.01"/>
190 +<polygon fill="black" stroke="black" points="451.9,-424.79 461.95,-428.13 456.18,-419.25 451.9,-424.79"/>
191 +<text text-anchor="middle" x="456.59" y="-397.6" font-family="Times,serif" font-size="14.00">capture</text>
192 +</g>
193 +<!-- v11&#45;&gt;v12 -->
194 +<g id="edge20" class="edge">
195 +<title>v11&#45;&gt;v12</title>
196 +<path fill="none" stroke="black" d="M289.43,-339.35C323.47,-325.35 371.84,-305.45 408.21,-290.49"/>
197 +<polygon fill="black" stroke="black" points="409.74,-293.65 417.65,-286.61 407.07,-287.17 409.74,-293.65"/>
198 +<text text-anchor="middle" x="393.59" y="-308.8" font-family="Times,serif" font-size="14.00">capture</text>
199 +</g>
200 +<!-- v12&#45;&gt;v13 -->
201 +<g id="edge22" class="edge">
202 +<title>v12&#45;&gt;v13</title>
203 +<path fill="none" stroke="black" d="M522.03,-250.55C575.25,-236.16 651.49,-215.55 707.28,-200.46"/>
204 +<polygon fill="black" stroke="black" points="708.36,-203.8 717.1,-197.81 706.53,-197.04 708.36,-203.8"/>
205 +<text text-anchor="middle" x="669.59" y="-220" font-family="Times,serif" font-size="14.00">capture</text>
206 +</g>
207 +<!-- v16 -->
208 +<g id="node17" class="node">
209 +<title>v16</title>
210 +<polygon fill="none" stroke="black" points="1003.49,-109 430.5,-109 430.5,-73 1003.49,-73 1003.49,-109"/>
211 +<text text-anchor="middle" x="716.99" y="-86.8" font-family="Times,serif" font-size="14.00">v16 (frozen $8 @ frozen $8 = JSX &lt;frozen $7 a={readonly a$2} b={readonly b$3} &gt;&lt;/frozen $7&gt;)</text>
212 +</g>
213 +<!-- v12&#45;&gt;v16 -->
214 +<g id="edge17" class="edge">
215 +<title>v12&#45;&gt;v16</title>
216 +<path fill="none" stroke="black" d="M408.55,-250.41C400.93,-245.74 393.97,-239.9 388.99,-232.6 362.47,-193.71 349.48,-161.96 380.99,-127 386.97,-120.37 409.13,-114.91 439.42,-110.44"/>
217 +<polygon fill="black" stroke="black" points="440.11,-113.88 449.53,-109.03 439.14,-106.95 440.11,-113.88"/>
218 +<text text-anchor="middle" x="389.59" y="-175.6" font-family="Times,serif" font-size="14.00">capture</text>
219 +</g>
220 +<!-- v17 -->
221 +<g id="node18" class="node">
222 +<title>v17</title>
223 +<polygon fill="none" stroke="black" points="825.82,-36 608.17,-36 608.17,0 825.82,0 825.82,-36"/>
224 +<text text-anchor="middle" x="716.99" y="-13.8" font-family="Times,serif" font-size="14.00">v17 (frozen $8 @ Return frozen $8)</text>
225 +</g>
226 +<!-- v12&#45;&gt;v17 -->
227 +<g id="edge24" class="edge">
228 +<title>v12&#45;&gt;v17</title>
229 +<path fill="none" stroke="black" d="M447.62,-250.49C424.6,-213.55 378.28,-125.44 421.99,-73 444.64,-45.83 526.33,-32.29 598.02,-25.57"/>
230 +<polygon fill="black" stroke="black" points="598.42,-29.04 608.07,-24.66 597.79,-22.07 598.42,-29.04"/>
231 +<text text-anchor="middle" x="425.59" y="-131.2" font-family="Times,serif" font-size="14.00">capture</text>
232 +</g>
233 +<!-- v13&#45;&gt;v16 -->
234 +<g id="edge18" class="edge">
235 +<title>v13&#45;&gt;v16</title>
236 +<path fill="none" stroke="black" d="M735.6,-161.61C728.52,-156.9 722.11,-151.04 717.8,-143.8 713.47,-136.52 712.21,-127.58 712.36,-119.19"/>
237 +<polygon fill="black" stroke="black" points="715.86,-119.27 713.17,-109.02 708.89,-118.71 715.86,-119.27"/>
238 +<text text-anchor="middle" x="738.59" y="-131.2" font-family="Times,serif" font-size="14.00">capture</text>
239 +</g>
240 +<!-- v13&#45;&gt;v17 -->
241 +<g id="edge25" class="edge">
242 +<title>v13&#45;&gt;v17</title>
243 +<path fill="none" stroke="black" d="M908.55,-161.75C981.4,-146.71 1050.9,-119.67 1011.99,-73 989.35,-45.83 907.65,-32.29 835.96,-25.57"/>
244 +<polygon fill="black" stroke="black" points="836.19,-22.07 825.92,-24.66 835.56,-29.04 836.19,-22.07"/>
245 +<text text-anchor="middle" x="1044.59" y="-86.8" font-family="Times,serif" font-size="14.00">capture</text>
246 +</g>
247 +<!-- v14 -->
248 +<g id="node15" class="node">
249 +<title>v14</title>
250 +<polygon fill="none" stroke="black" points="2199.43,-714.8 1978.56,-714.8 1978.56,-678.8 2199.43,-678.8 2199.43,-714.8"/>
251 +<text text-anchor="middle" x="2088.99" y="-692.6" font-family="Times,serif" font-size="14.00">v14 (frozen $7 @ frozen $7 = &quot;div&quot;)</text>
252 +</g>
253 +<!-- v15 -->
254 +<g id="node16" class="node">
255 +<title>v15</title>
256 +<polygon fill="none" stroke="black" points="2341.34,-641.8 1836.65,-641.8 1836.65,-605.8 2341.34,-605.8 2341.34,-641.8"/>
257 +<text text-anchor="middle" x="2088.99" y="-619.6" font-family="Times,serif" font-size="14.00">v15 (frozen $7 @ JSX &lt;frozen $7 a={readonly a$2} b={readonly b$3} &gt;&lt;/frozen $7&gt;)</text>
258 +</g>
259 +<!-- v14&#45;&gt;v15 -->
260 +<g id="edge15" class="edge">
261 +<title>v14&#45;&gt;v15</title>
262 +<path fill="none" stroke="black" d="M2088.99,-678.61C2088.99,-670.59 2088.99,-660.85 2088.99,-651.87"/>
263 +<polygon fill="black" stroke="black" points="2092.49,-651.83 2088.99,-641.83 2085.49,-651.83 2092.49,-651.83"/>
264 +</g>
265 +<!-- v16&#45;&gt;v12 -->
266 +<g id="edge21" class="edge">
267 +<title>v16&#45;&gt;v12</title>
268 +<path fill="none" stroke="black" d="M612.2,-109.04C552.84,-120.96 486.75,-138.85 467.8,-161.8 449.88,-183.49 450.2,-216.92 453.38,-240.39"/>
269 +<polygon fill="black" stroke="black" points="449.94,-241.07 454.98,-250.39 456.85,-239.96 449.94,-241.07"/>
270 +<text text-anchor="middle" x="488.59" y="-175.6" font-family="Times,serif" font-size="14.00">capture</text>
271 +</g>
272 +<!-- v16&#45;&gt;v13 -->
273 +<g id="edge23" class="edge">
274 +<title>v16&#45;&gt;v13</title>
275 +<path fill="none" stroke="black" d="M741.59,-109.08C747.86,-114.29 754.18,-120.41 758.99,-127 764.42,-134.44 768.71,-143.47 771.96,-151.91"/>
276 +<polygon fill="black" stroke="black" points="768.68,-153.13 775.3,-161.4 775.28,-150.8 768.68,-153.13"/>
277 +<text text-anchor="middle" x="789.59" y="-131.2" font-family="Times,serif" font-size="14.00">capture</text>
278 +</g>
279 +<!-- v16&#45;&gt;v17 -->
280 +<g id="edge16" class="edge">
281 +<title>v16&#45;&gt;v17</title>
282 +<path fill="none" stroke="black" d="M716.99,-72.81C716.99,-64.79 716.99,-55.05 716.99,-46.07"/>
283 +<polygon fill="black" stroke="black" points="720.49,-46.03 716.99,-36.03 713.49,-46.03 720.49,-46.03"/>
284 +</g>
285 +</g>
286 +</svg>
compiler/forget/src/__tests__/fixtures/hir-svg/component.svg new
+739
@@ -0,0 +1,739 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4 +<!-- Generated by graphviz version 6.0.1 (20220924.0800)
5 + -->
6 +<!-- Title: InferMutability Pages: 1 -->
7 +<svg width="9655pt" height="833pt"
8 + viewBox="0.00 0.00 9655.44 833.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9 +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 829)">
10 +<title>InferMutability</title>
11 +<polygon fill="white" stroke="none" points="-4,4 -4,-829 9651.44,-829 9651.44,4 -4,4"/>
12 +<!-- v0 -->
13 +<g id="node1" class="node">
14 +<title>v0</title>
15 +<polygon fill="none" stroke="black" points="277.85,-822.2 71.01,-822.2 71.01,-786.2 277.85,-786.2 277.85,-822.2"/>
16 +<text text-anchor="middle" x="174.43" y="-800" font-family="Times,serif" font-size="14.00">v0 (frozen props$1 @ &lt;no&#45;instr&gt;)</text>
17 +</g>
18 +<!-- v1 -->
19 +<g id="node2" class="node">
20 +<title>v1</title>
21 +<polygon fill="none" stroke="black" points="324.03,-746.4 24.82,-746.4 24.82,-710.4 324.03,-710.4 324.03,-746.4"/>
22 +<text text-anchor="middle" x="174.43" y="-724.2" font-family="Times,serif" font-size="14.00">v1 (frozen props$1.items @ frozen props$1.items)</text>
23 +</g>
24 +<!-- v0&#45;&gt;v1 -->
25 +<g id="edge1" class="edge">
26 +<title>v0&#45;&gt;v1</title>
27 +<path fill="none" stroke="black" d="M174.43,-786.08C174.43,-777.33 174.43,-766.46 174.43,-756.59"/>
28 +<polygon fill="black" stroke="black" points="177.93,-756.42 174.43,-746.42 170.93,-756.42 177.93,-756.42"/>
29 +</g>
30 +<!-- v4 -->
31 +<g id="node5" class="node">
32 +<title>v4</title>
33 +<polygon fill="none" stroke="black" points="348.78,-657.6 0.07,-657.6 0.07,-621.6 348.78,-621.6 348.78,-657.6"/>
34 +<text text-anchor="middle" x="174.43" y="-635.4" font-family="Times,serif" font-size="14.00">v4 (frozen props$1.maxItems @ frozen props$1.maxItems)</text>
35 +</g>
36 +<!-- v1&#45;&gt;v4 -->
37 +<g id="edge3" class="edge">
38 +<title>v1&#45;&gt;v4</title>
39 +<path fill="none" stroke="black" d="M174.43,-710.25C174.43,-698.12 174.43,-681.62 174.43,-667.72"/>
40 +<polygon fill="black" stroke="black" points="177.93,-667.71 174.43,-657.71 170.93,-667.71 177.93,-667.71"/>
41 +</g>
42 +<!-- v2 -->
43 +<g id="node3" class="node">
44 +<title>v2</title>
45 +<polygon fill="none" stroke="black" points="700.9,-822.2 337.96,-822.2 337.96,-786.2 700.9,-786.2 700.9,-822.2"/>
46 +<text text-anchor="middle" x="519.43" y="-800" font-family="Times,serif" font-size="14.00">v2 (frozen items$2 @ frozen items$2 = frozen props$1.items)</text>
47 +</g>
48 +<!-- v3 -->
49 +<g id="node4" class="node">
50 +<title>v3</title>
51 +<polygon fill="none" stroke="black" points="696.61,-746.4 342.25,-746.4 342.25,-710.4 696.61,-710.4 696.61,-746.4"/>
52 +<text text-anchor="middle" x="519.43" y="-724.2" font-family="Times,serif" font-size="14.00">v3 (frozen items$2 @ If (frozen items$2) then:bb3 else:bb2)</text>
53 +</g>
54 +<!-- v2&#45;&gt;v3 -->
55 +<g id="edge2" class="edge">
56 +<title>v2&#45;&gt;v3</title>
57 +<path fill="none" stroke="black" d="M519.43,-786.08C519.43,-777.33 519.43,-766.46 519.43,-756.59"/>
58 +<polygon fill="black" stroke="black" points="522.93,-756.42 519.43,-746.42 515.93,-756.42 522.93,-756.42"/>
59 +</g>
60 +<!-- v3&#45;&gt;v3 -->
61 +<g id="edge11" class="edge">
62 +<title>v3&#45;&gt;v3</title>
63 +<path fill="none" stroke="black" d="M696.7,-733.23C707.97,-732.09 714.77,-730.49 714.77,-728.4 714.77,-727.03 711.84,-725.87 706.64,-724.91"/>
64 +<polygon fill="black" stroke="black" points="707.07,-721.44 696.7,-723.57 706.14,-728.37 707.07,-721.44"/>
65 +</g>
66 +<!-- v5 -->
67 +<g id="node6" class="node">
68 +<title>v5</title>
69 +<polygon fill="none" stroke="black" points="1199.03,-822.2 761.83,-822.2 761.83,-786.2 1199.03,-786.2 1199.03,-822.2"/>
70 +<text text-anchor="middle" x="980.43" y="-800" font-family="Times,serif" font-size="14.00">v5 (frozen maxItems$3 @ frozen maxItems$3 = frozen props$1.maxItems)</text>
71 +</g>
72 +<!-- v6 -->
73 +<g id="node7" class="node">
74 +<title>v6</title>
75 +<polygon fill="none" stroke="black" points="1228.22,-746.4 732.63,-746.4 732.63,-710.4 1228.22,-710.4 1228.22,-746.4"/>
76 +<text text-anchor="middle" x="980.43" y="-724.2" font-family="Times,serif" font-size="14.00">v6 (frozen maxItems$3 @ Call mutable Math$8.max(frozen $9, frozen maxItems$3))</text>
77 +</g>
78 +<!-- v5&#45;&gt;v6 -->
79 +<g id="edge4" class="edge">
80 +<title>v5&#45;&gt;v6</title>
81 +<path fill="none" stroke="black" d="M980.43,-786.08C980.43,-777.33 980.43,-766.46 980.43,-756.59"/>
82 +<polygon fill="black" stroke="black" points="983.93,-756.42 980.43,-746.42 976.93,-756.42 983.93,-756.42"/>
83 +</g>
84 +<!-- v7 -->
85 +<g id="node8" class="node">
86 +<title>v7</title>
87 +<polygon fill="none" stroke="black" points="1649.84,-822.2 1241.01,-822.2 1241.01,-786.2 1649.84,-786.2 1649.84,-822.2"/>
88 +<text text-anchor="middle" x="1445.43" y="-800" font-family="Times,serif" font-size="14.00">v7 (mutable renderedItems$4 @ mutable renderedItems$4 = Array [])</text>
89 +</g>
90 +<!-- v8 -->
91 +<g id="node9" class="node">
92 +<title>v8</title>
93 +<polygon fill="none" stroke="black" points="1633.73,-568.8 1201.13,-568.8 1201.13,-532.8 1633.73,-532.8 1633.73,-568.8"/>
94 +<text text-anchor="middle" x="1417.43" y="-546.6" font-family="Times,serif" font-size="14.00">v8 (readonly renderedItems$4.length @ readonly renderedItems$4.length)</text>
95 +</g>
96 +<!-- v7&#45;&gt;v8 -->
97 +<g id="edge5" class="edge">
98 +<title>v7&#45;&gt;v8</title>
99 +<path fill="none" stroke="black" d="M1423.34,-786.01C1411.3,-775.65 1396.95,-761.56 1387.43,-746.4 1365.27,-711.12 1364.18,-698.71 1357.43,-657.6 1354.83,-641.81 1351.87,-636.6 1357.43,-621.6 1363.87,-604.23 1376.78,-588.28 1388.98,-576.02"/>
100 +<polygon fill="black" stroke="black" points="1391.63,-578.33 1396.42,-568.89 1386.78,-573.28 1391.63,-578.33"/>
101 +</g>
102 +<!-- v9 -->
103 +<g id="node10" class="node">
104 +<title>v9</title>
105 +<polygon fill="none" stroke="black" points="1910.13,-746.4 1396.73,-746.4 1396.73,-710.4 1910.13,-710.4 1910.13,-746.4"/>
106 +<text text-anchor="middle" x="1653.43" y="-724.2" font-family="Times,serif" font-size="14.00">v9 (mutable renderedItems$4.push @ Call mutable renderedItems$4.push(mutable $15))</text>
107 +</g>
108 +<!-- v7&#45;&gt;v9 -->
109 +<g id="edge6" class="edge">
110 +<title>v7&#45;&gt;v9</title>
111 +<path fill="none" stroke="black" d="M1493.41,-786.18C1523.85,-775.37 1563.42,-761.33 1595.6,-749.92"/>
112 +<polygon fill="black" stroke="black" points="1597.07,-753.11 1605.33,-746.47 1594.73,-746.51 1597.07,-753.11"/>
113 +</g>
114 +<!-- v27 -->
115 +<g id="node28" class="node">
116 +<title>v27</title>
117 +<polygon fill="none" stroke="black" points="1643.79,-480 1191.06,-480 1191.06,-444 1643.79,-444 1643.79,-480"/>
118 +<text text-anchor="middle" x="1417.43" y="-457.8" font-family="Times,serif" font-size="14.00">v27 (frozen count$17 @ frozen count$17 = readonly renderedItems$4.length)</text>
119 +</g>
120 +<!-- v8&#45;&gt;v27 -->
121 +<g id="edge19" class="edge">
122 +<title>v8&#45;&gt;v27</title>
123 +<path fill="none" stroke="black" d="M1423.38,-532.56C1425.04,-526.96 1426.6,-520.68 1427.43,-514.8 1428.46,-507.41 1428.46,-505.39 1427.43,-498 1427.07,-495.43 1426.56,-492.78 1425.97,-490.14"/>
124 +<polygon fill="black" stroke="black" points="1429.3,-489.03 1423.38,-480.24 1422.53,-490.8 1429.3,-489.03"/>
125 +<text text-anchor="middle" x="1449.02" y="-502.2" font-family="Times,serif" font-size="14.00">capture</text>
126 +</g>
127 +<!-- v28 -->
128 +<g id="node29" class="node">
129 +<title>v28</title>
130 +<polygon fill="none" stroke="black" points="1393.81,-391.2 871.05,-391.2 871.05,-355.2 1393.81,-355.2 1393.81,-391.2"/>
131 +<text text-anchor="middle" x="1132.43" y="-369" font-family="Times,serif" font-size="14.00">v28 (frozen count$17 @ JSX &lt;frozen $20&gt;{frozen count$17}{frozen $21}&lt;/frozen $20&gt;)</text>
132 +</g>
133 +<!-- v8&#45;&gt;v28 -->
134 +<g id="edge28" class="edge">
135 +<title>v8&#45;&gt;v28</title>
136 +<path fill="none" stroke="black" d="M1293.18,-532.74C1229.67,-521.32 1161.54,-503.96 1141.23,-480 1123.04,-458.54 1123.41,-425.06 1126.68,-401.53"/>
137 +<polygon fill="black" stroke="black" points="1130.16,-401.92 1128.32,-391.49 1123.25,-400.79 1130.16,-401.92"/>
138 +<text text-anchor="middle" x="1162.02" y="-457.8" font-family="Times,serif" font-size="14.00">capture</text>
139 +</g>
140 +<!-- v29 -->
141 +<g id="node30" class="node">
142 +<title>v29</title>
143 +<polygon fill="none" stroke="black" points="2223.27,-302.4 1369.59,-302.4 1369.59,-266.4 2223.27,-266.4 2223.27,-302.4"/>
144 +<text text-anchor="middle" x="1796.43" y="-280.2" font-family="Times,serif" font-size="14.00">v29 (readonly renderedItems$4 @ JSX &lt;frozen $18&gt;{frozen $19}{frozen $22}{frozen $23}{readonly renderedItems$4}{frozen $24}&lt;/frozen $18&gt;)</text>
145 +</g>
146 +<!-- v8&#45;&gt;v29 -->
147 +<g id="edge20" class="edge">
148 +<title>v8&#45;&gt;v29</title>
149 +<path fill="none" stroke="black" d="M1526.57,-532.73C1568.62,-522.38 1615.39,-505.95 1652.43,-480 1716.13,-435.36 1762.99,-353.55 1784.06,-311.65"/>
150 +<polygon fill="black" stroke="black" points="1787.23,-313.14 1788.52,-302.62 1780.95,-310.04 1787.23,-313.14"/>
151 +</g>
152 +<!-- v53 -->
153 +<g id="node54" class="node">
154 +<title>v53</title>
155 +<polygon fill="none" stroke="black" points="1940.21,-657.6 1366.64,-657.6 1366.64,-621.6 1940.21,-621.6 1940.21,-657.6"/>
156 +<text text-anchor="middle" x="1653.43" y="-635.4" font-family="Times,serif" font-size="14.00">v53 (mutable renderedItems$4.length @ Binary mutable renderedItems$4.length &gt;= frozen max$7)</text>
157 +</g>
158 +<!-- v9&#45;&gt;v53 -->
159 +<g id="edge56" class="edge">
160 +<title>v9&#45;&gt;v53</title>
161 +<path fill="none" stroke="black" d="M1647.92,-710.25C1646.6,-698.12 1646.33,-681.62 1647.12,-667.72"/>
162 +<polygon fill="black" stroke="black" points="1650.61,-667.96 1647.93,-657.71 1643.63,-667.4 1650.61,-667.96"/>
163 +</g>
164 +<!-- v10 -->
165 +<g id="node11" class="node">
166 +<title>v10</title>
167 +<polygon fill="none" stroke="black" points="2152.23,-822.2 1772.62,-822.2 1772.62,-786.2 2152.23,-786.2 2152.23,-822.2"/>
168 +<text text-anchor="middle" x="1962.43" y="-800" font-family="Times,serif" font-size="14.00">v10 (mutable seen$5 @ mutable seen$5 = New mutable Set$6())</text>
169 +</g>
170 +<!-- v11 -->
171 +<g id="node12" class="node">
172 +<title>v11</title>
173 +<polygon fill="none" stroke="black" points="2381.05,-657.6 1961.81,-657.6 1961.81,-621.6 2381.05,-621.6 2381.05,-657.6"/>
174 +<text text-anchor="middle" x="2171.43" y="-635.4" font-family="Times,serif" font-size="14.00">v11 (mutable seen$5.has @ Call mutable seen$5.has(mutable item$10))</text>
175 +</g>
176 +<!-- v10&#45;&gt;v11 -->
177 +<g id="edge7" class="edge">
178 +<title>v10&#45;&gt;v11</title>
179 +<path fill="none" stroke="black" d="M1955.54,-785.98C1948.72,-765.84 1941.41,-732.47 1957.43,-710.4 1974.21,-687.27 1998.87,-671.66 2025.53,-661.16"/>
180 +<polygon fill="black" stroke="black" points="2026.87,-664.4 2035.04,-657.65 2024.44,-657.83 2026.87,-664.4"/>
181 +</g>
182 +<!-- v12 -->
183 +<g id="node13" class="node">
184 +<title>v12</title>
185 +<polygon fill="none" stroke="black" points="2388.65,-746.4 1966.2,-746.4 1966.2,-710.4 2388.65,-710.4 2388.65,-746.4"/>
186 +<text text-anchor="middle" x="2177.43" y="-724.2" font-family="Times,serif" font-size="14.00">v12 (mutable seen$5.add @ Call mutable seen$5.add(mutable item$10))</text>
187 +</g>
188 +<!-- v10&#45;&gt;v12 -->
189 +<g id="edge8" class="edge">
190 +<title>v10&#45;&gt;v12</title>
191 +<path fill="none" stroke="black" d="M2012.02,-786.18C2043.63,-775.33 2084.75,-761.21 2118.08,-749.77"/>
192 +<polygon fill="black" stroke="black" points="2119.39,-753.02 2127.71,-746.47 2117.12,-746.4 2119.39,-753.02"/>
193 +</g>
194 +<!-- v11&#45;&gt;v11 -->
195 +<g id="edge45" class="edge">
196 +<title>v11&#45;&gt;v11</title>
197 +<path fill="none" stroke="black" d="M2381.1,-645.14C2392.48,-643.79 2399.24,-641.94 2399.24,-639.6 2399.24,-638.06 2396.33,-636.74 2391.11,-635.63"/>
198 +<polygon fill="black" stroke="black" points="2391.53,-632.15 2381.1,-634.06 2390.44,-639.07 2391.53,-632.15"/>
199 +</g>
200 +<!-- v12&#45;&gt;v11 -->
201 +<g id="edge49" class="edge">
202 +<title>v12&#45;&gt;v11</title>
203 +<path fill="none" stroke="black" d="M2176.24,-710.25C2175.4,-698.12 2174.26,-681.62 2173.3,-667.72"/>
204 +<polygon fill="black" stroke="black" points="2176.79,-667.45 2172.61,-657.71 2169.81,-667.93 2176.79,-667.45"/>
205 +</g>
206 +<!-- v12&#45;&gt;v12 -->
207 +<g id="edge50" class="edge">
208 +<title>v12&#45;&gt;v12</title>
209 +<path fill="none" stroke="black" d="M2388.85,-732.93C2400.11,-731.82 2406.79,-730.31 2406.79,-728.4 2406.79,-727.18 2404.05,-726.12 2399.12,-725.23"/>
210 +<polygon fill="black" stroke="black" points="2399.22,-721.71 2388.85,-723.87 2398.31,-728.65 2399.22,-721.71"/>
211 +</g>
212 +<!-- v13 -->
213 +<g id="node14" class="node">
214 +<title>v13</title>
215 +<polygon fill="none" stroke="black" points="2486.38,-822.2 2216.48,-822.2 2216.48,-786.2 2486.38,-786.2 2486.38,-822.2"/>
216 +<text text-anchor="middle" x="2351.43" y="-800" font-family="Times,serif" font-size="14.00">v13 (mutable Set$6 @ New mutable Set$6())</text>
217 +</g>
218 +<!-- v14 -->
219 +<g id="node15" class="node">
220 +<title>v14</title>
221 +<polygon fill="none" stroke="black" points="2747.54,-822.2 2549.31,-822.2 2549.31,-786.2 2747.54,-786.2 2747.54,-822.2"/>
222 +<text text-anchor="middle" x="2648.43" y="-800" font-family="Times,serif" font-size="14.00">v14 (frozen $9 @ frozen $9 = 0)</text>
223 +</g>
224 +<!-- v15 -->
225 +<g id="node16" class="node">
226 +<title>v15</title>
227 +<polygon fill="none" stroke="black" points="2872.01,-746.4 2424.84,-746.4 2424.84,-710.4 2872.01,-710.4 2872.01,-746.4"/>
228 +<text text-anchor="middle" x="2648.43" y="-724.2" font-family="Times,serif" font-size="14.00">v15 (frozen $9 @ Call mutable Math$8.max(frozen $9, frozen maxItems$3))</text>
229 +</g>
230 +<!-- v14&#45;&gt;v15 -->
231 +<g id="edge9" class="edge">
232 +<title>v14&#45;&gt;v15</title>
233 +<path fill="none" stroke="black" d="M2648.43,-786.08C2648.43,-777.33 2648.43,-766.46 2648.43,-756.59"/>
234 +<polygon fill="black" stroke="black" points="2651.93,-756.42 2648.43,-746.42 2644.93,-756.42 2651.93,-756.42"/>
235 +</g>
236 +<!-- v16 -->
237 +<g id="node17" class="node">
238 +<title>v16</title>
239 +<polygon fill="none" stroke="black" points="3407.37,-822.2 2843.49,-822.2 2843.49,-786.2 3407.37,-786.2 3407.37,-822.2"/>
240 +<text text-anchor="middle" x="3125.43" y="-800" font-family="Times,serif" font-size="14.00">v16 (frozen max$7 @ frozen max$7 = Call mutable Math$8.max(frozen $9, frozen maxItems$3))</text>
241 +</g>
242 +<!-- v17 -->
243 +<g id="node18" class="node">
244 +<title>v17</title>
245 +<polygon fill="none" stroke="black" points="3360.41,-746.4 2890.45,-746.4 2890.45,-710.4 3360.41,-710.4 3360.41,-746.4"/>
246 +<text text-anchor="middle" x="3125.43" y="-724.2" font-family="Times,serif" font-size="14.00">v17 (frozen max$7 @ Binary mutable renderedItems$4.length &gt;= frozen max$7)</text>
247 +</g>
248 +<!-- v16&#45;&gt;v17 -->
249 +<g id="edge10" class="edge">
250 +<title>v16&#45;&gt;v17</title>
251 +<path fill="none" stroke="black" d="M3125.43,-786.08C3125.43,-777.33 3125.43,-766.46 3125.43,-756.59"/>
252 +<polygon fill="black" stroke="black" points="3128.93,-756.42 3125.43,-746.42 3121.93,-756.42 3128.93,-756.42"/>
253 +</g>
254 +<!-- v17&#45;&gt;v17 -->
255 +<g id="edge61" class="edge">
256 +<title>v17&#45;&gt;v17</title>
257 +<path fill="none" stroke="black" d="M3360.67,-732.73C3371.86,-731.65 3378.42,-730.2 3378.42,-728.4 3378.42,-727.25 3375.72,-726.24 3370.85,-725.38"/>
258 +<polygon fill="black" stroke="black" points="3371.04,-721.87 3360.67,-724.07 3370.14,-728.82 3371.04,-721.87"/>
259 +</g>
260 +<!-- v18 -->
261 +<g id="node19" class="node">
262 +<title>v18</title>
263 +<polygon fill="none" stroke="black" points="3939.51,-822.2 3425.34,-822.2 3425.34,-786.2 3939.51,-786.2 3939.51,-822.2"/>
264 +<text text-anchor="middle" x="3682.43" y="-800" font-family="Times,serif" font-size="14.00">v18 (mutable Math$8.max @ Call mutable Math$8.max(frozen $9, frozen maxItems$3))</text>
265 +</g>
266 +<!-- v19 -->
267 +<g id="node20" class="node">
268 +<title>v19</title>
269 +<polygon fill="none" stroke="black" points="4183.82,-822.2 3957.03,-822.2 3957.03,-786.2 4183.82,-786.2 4183.82,-822.2"/>
270 +<text text-anchor="middle" x="4070.43" y="-800" font-family="Times,serif" font-size="14.00">v19 (frozen $11 @ frozen $11 = null)</text>
271 +</g>
272 +<!-- v20 -->
273 +<g id="node21" class="node">
274 +<title>v20</title>
275 +<polygon fill="none" stroke="black" points="4245.02,-746.4 3895.83,-746.4 3895.83,-710.4 4245.02,-710.4 4245.02,-746.4"/>
276 +<text text-anchor="middle" x="4070.43" y="-724.2" font-family="Times,serif" font-size="14.00">v20 (frozen $11 @ Binary mutable item$10 == frozen $11)</text>
277 +</g>
278 +<!-- v19&#45;&gt;v20 -->
279 +<g id="edge12" class="edge">
280 +<title>v19&#45;&gt;v20</title>
281 +<path fill="none" stroke="black" d="M4070.43,-786.08C4070.43,-777.33 4070.43,-766.46 4070.43,-756.59"/>
282 +<polygon fill="black" stroke="black" points="4073.93,-756.42 4070.43,-746.42 4066.93,-756.42 4073.93,-756.42"/>
283 +</g>
284 +<!-- v21 -->
285 +<g id="node22" class="node">
286 +<title>v21</title>
287 +<polygon fill="none" stroke="black" points="4632.67,-822.2 4208.19,-822.2 4208.19,-786.2 4632.67,-786.2 4632.67,-822.2"/>
288 +<text text-anchor="middle" x="4420.43" y="-800" font-family="Times,serif" font-size="14.00">v21 (frozen $12 @ frozen $12 = Binary mutable item$10 == frozen $11)</text>
289 +</g>
290 +<!-- v22 -->
291 +<g id="node23" class="node">
292 +<title>v22</title>
293 +<polygon fill="none" stroke="black" points="4577.95,-746.4 4262.91,-746.4 4262.91,-710.4 4577.95,-710.4 4577.95,-746.4"/>
294 +<text text-anchor="middle" x="4420.43" y="-724.2" font-family="Times,serif" font-size="14.00">v22 (frozen $12 @ If (frozen $12) then:bb8 else:bb9)</text>
295 +</g>
296 +<!-- v21&#45;&gt;v22 -->
297 +<g id="edge13" class="edge">
298 +<title>v21&#45;&gt;v22</title>
299 +<path fill="none" stroke="black" d="M4420.43,-786.08C4420.43,-777.33 4420.43,-766.46 4420.43,-756.59"/>
300 +<polygon fill="black" stroke="black" points="4423.93,-756.42 4420.43,-746.42 4416.93,-756.42 4423.93,-756.42"/>
301 +</g>
302 +<!-- v22&#45;&gt;v22 -->
303 +<g id="edge16" class="edge">
304 +<title>v22&#45;&gt;v22</title>
305 +<path fill="none" stroke="black" d="M4578.11,-733.4C4589.18,-732.26 4595.94,-730.59 4595.94,-728.4 4595.94,-727 4593.17,-725.81 4588.26,-724.84"/>
306 +<polygon fill="black" stroke="black" points="4588.5,-721.33 4578.11,-723.4 4587.52,-728.27 4588.5,-721.33"/>
307 +</g>
308 +<!-- v26 -->
309 +<g id="node27" class="node">
310 +<title>v26</title>
311 +<polygon fill="none" stroke="black" points="4489.3,-657.6 4223.56,-657.6 4223.56,-621.6 4489.3,-621.6 4489.3,-657.6"/>
312 +<text text-anchor="middle" x="4356.43" y="-635.4" font-family="Times,serif" font-size="14.00">v26 (frozen $13 @ frozen $13 = frozen $12)</text>
313 +</g>
314 +<!-- v22&#45;&gt;v26 -->
315 +<g id="edge42" class="edge">
316 +<title>v22&#45;&gt;v26</title>
317 +<path fill="none" stroke="black" d="M4371.44,-710.23C4364.18,-705.56 4357.67,-699.71 4353.23,-692.4 4348.78,-685.06 4348.09,-676.01 4348.97,-667.54"/>
318 +<polygon fill="black" stroke="black" points="4352.42,-668.1 4350.68,-657.65 4345.52,-666.9 4352.42,-668.1"/>
319 +<text text-anchor="middle" x="4374.02" y="-679.8" font-family="Times,serif" font-size="14.00">capture</text>
320 +</g>
321 +<!-- v46 -->
322 +<g id="node47" class="node">
323 +<title>v46</title>
324 +<polygon fill="none" stroke="black" points="4670.95,-568.8 4355.91,-568.8 4355.91,-532.8 4670.95,-532.8 4670.95,-568.8"/>
325 +<text text-anchor="middle" x="4513.43" y="-546.6" font-family="Times,serif" font-size="14.00">v46 (frozen $13 @ If (frozen $13) then:bb1 else:bb4)</text>
326 +</g>
327 +<!-- v22&#45;&gt;v46 -->
328 +<g id="edge48" class="edge">
329 +<title>v22&#45;&gt;v46</title>
330 +<path fill="none" stroke="black" d="M4448.1,-710.14C4465.49,-697.73 4486.78,-679.4 4498.43,-657.6 4511.43,-633.27 4514.39,-601.52 4514.58,-579.17"/>
331 +<polygon fill="black" stroke="black" points="4518.08,-578.99 4514.49,-569.03 4511.08,-579.06 4518.08,-578.99"/>
332 +<text text-anchor="middle" x="4531.02" y="-635.4" font-family="Times,serif" font-size="14.00">capture</text>
333 +</g>
334 +<!-- v23 -->
335 +<g id="node24" class="node">
336 +<title>v23</title>
337 +<polygon fill="none" stroke="black" points="5492.25,-657.6 5108.61,-657.6 5108.61,-621.6 5492.25,-621.6 5492.25,-657.6"/>
338 +<text text-anchor="middle" x="5300.43" y="-635.4" font-family="Times,serif" font-size="14.00">v23 (mutable item$10 @ Binary mutable item$10 == frozen $11)</text>
339 +</g>
340 +<!-- v24 -->
341 +<g id="node25" class="node">
342 +<title>v24</title>
343 +<polygon fill="none" stroke="black" points="5093.89,-568.8 4688.96,-568.8 4688.96,-532.8 5093.89,-532.8 5093.89,-568.8"/>
344 +<text text-anchor="middle" x="4891.43" y="-546.6" font-family="Times,serif" font-size="14.00">v24 (mutable item$10 @ Call mutable seen$5.has(mutable item$10))</text>
345 +</g>
346 +<!-- v23&#45;&gt;v24 -->
347 +<g id="edge14" class="edge">
348 +<title>v23&#45;&gt;v24</title>
349 +<path fill="none" stroke="black" d="M5220.11,-621.55C5151.45,-606.98 5052.74,-586.04 4981.44,-570.9"/>
350 +<polygon fill="black" stroke="black" points="4982.07,-567.46 4971.56,-568.81 4980.62,-574.31 4982.07,-567.46"/>
351 +</g>
352 +<!-- v25 -->
353 +<g id="node26" class="node">
354 +<title>v25</title>
355 +<polygon fill="none" stroke="black" points="5535.45,-568.8 5129.41,-568.8 5129.41,-532.8 5535.45,-532.8 5535.45,-568.8"/>
356 +<text text-anchor="middle" x="5332.43" y="-546.6" font-family="Times,serif" font-size="14.00">v25 (mutable item$10 @ Call mutable seen$5.add(mutable item$10))</text>
357 +</g>
358 +<!-- v23&#45;&gt;v25 -->
359 +<g id="edge15" class="edge">
360 +<title>v23&#45;&gt;v25</title>
361 +<path fill="none" stroke="black" d="M5306.75,-621.45C5311.26,-609.21 5317.42,-592.49 5322.58,-578.51"/>
362 +<polygon fill="black" stroke="black" points="5325.94,-579.51 5326.12,-568.91 5319.38,-577.09 5325.94,-579.51"/>
363 +</g>
364 +<!-- v24&#45;&gt;v24 -->
365 +<g id="edge46" class="edge">
366 +<title>v24&#45;&gt;v24</title>
367 +<path fill="none" stroke="black" d="M5093.82,-556.38C5105.01,-555.02 5111.66,-553.16 5111.66,-550.8 5111.66,-549.29 5108.93,-547.98 5104.03,-546.88"/>
368 +<polygon fill="black" stroke="black" points="5104.25,-543.37 5093.82,-545.22 5103.13,-550.28 5104.25,-543.37"/>
369 +</g>
370 +<!-- v47 -->
371 +<g id="node48" class="node">
372 +<title>v47</title>
373 +<polygon fill="none" stroke="black" points="5059.5,-657.6 4595.35,-657.6 4595.35,-621.6 5059.5,-621.6 5059.5,-657.6"/>
374 +<text text-anchor="middle" x="4827.43" y="-635.4" font-family="Times,serif" font-size="14.00">v47 (mutable $13 @ mutable $13 = Call mutable seen$5.has(mutable item$10))</text>
375 +</g>
376 +<!-- v24&#45;&gt;v47 -->
377 +<g id="edge44" class="edge">
378 +<title>v24&#45;&gt;v47</title>
379 +<path fill="none" stroke="black" d="M4886.36,-569.2C4882.73,-579.8 4877.12,-593.25 4869.43,-603.6 4866.54,-607.49 4863.13,-611.22 4859.53,-614.7"/>
380 +<polygon fill="black" stroke="black" points="4857.08,-612.19 4851.95,-621.47 4861.74,-617.41 4857.08,-612.19"/>
381 +<text text-anchor="middle" x="4900.02" y="-591" font-family="Times,serif" font-size="14.00">capture</text>
382 +</g>
383 +<!-- v48 -->
384 +<g id="node49" class="node">
385 +<title>v48</title>
386 +<polygon fill="none" stroke="black" points="5559.86,-480 5104.99,-480 5104.99,-444 5559.86,-444 5559.86,-480"/>
387 +<text text-anchor="middle" x="5332.43" y="-457.8" font-family="Times,serif" font-size="14.00">v48 (mutable item$10 @ JSX &lt;frozen $14&gt;{mutable item$10}&lt;/frozen $14&gt;)</text>
388 +</g>
389 +<!-- v25&#45;&gt;v48 -->
390 +<g id="edge51" class="edge">
391 +<title>v25&#45;&gt;v48</title>
392 +<path fill="none" stroke="black" d="M5332.43,-532.65C5332.43,-520.52 5332.43,-504.02 5332.43,-490.12"/>
393 +<polygon fill="black" stroke="black" points="5335.93,-490.11 5332.43,-480.11 5328.93,-490.11 5335.93,-490.11"/>
394 +</g>
395 +<!-- v26&#45;&gt;v22 -->
396 +<g id="edge17" class="edge">
397 +<title>v26&#45;&gt;v22</title>
398 +<path fill="none" stroke="black" d="M4380.95,-657.73C4387.22,-662.95 4393.56,-669.05 4398.43,-675.6 4403.95,-683.04 4408.41,-692.08 4411.82,-700.51"/>
399 +<polygon fill="black" stroke="black" points="4408.59,-701.85 4415.36,-710 4415.14,-699.41 4408.59,-701.85"/>
400 +<text text-anchor="middle" x="4429.02" y="-679.8" font-family="Times,serif" font-size="14.00">capture</text>
401 +</g>
402 +<!-- v26&#45;&gt;v46 -->
403 +<g id="edge41" class="edge">
404 +<title>v26&#45;&gt;v46</title>
405 +<path fill="none" stroke="black" d="M4387.45,-621.45C4412.07,-607.84 4446.67,-588.71 4473.38,-573.94"/>
406 +<polygon fill="black" stroke="black" points="4475.42,-576.81 4482.47,-568.91 4472.03,-570.69 4475.42,-576.81"/>
407 +</g>
408 +<!-- v27&#45;&gt;v8 -->
409 +<g id="edge21" class="edge">
410 +<title>v27&#45;&gt;v8</title>
411 +<path fill="none" stroke="black" d="M1394.88,-480.12C1389.76,-485.25 1385.01,-491.32 1382.23,-498 1379.37,-504.89 1379.37,-507.91 1382.23,-514.8 1383.71,-518.35 1385.74,-521.73 1388.09,-524.88"/>
412 +<polygon fill="black" stroke="black" points="1385.67,-527.44 1394.88,-532.68 1390.95,-522.84 1385.67,-527.44"/>
413 +<text text-anchor="middle" x="1403.02" y="-502.2" font-family="Times,serif" font-size="14.00">capture</text>
414 +</g>
415 +<!-- v27&#45;&gt;v28 -->
416 +<g id="edge18" class="edge">
417 +<title>v27&#45;&gt;v28</title>
418 +<path fill="none" stroke="black" d="M1361.46,-443.95C1314.5,-429.65 1247.36,-409.2 1197.91,-394.14"/>
419 +<polygon fill="black" stroke="black" points="1198.85,-390.77 1188.27,-391.21 1196.81,-397.47 1198.85,-390.77"/>
420 +</g>
421 +<!-- v28&#45;&gt;v29 -->
422 +<g id="edge37" class="edge">
423 +<title>v28&#45;&gt;v29</title>
424 +<path fill="none" stroke="black" d="M1262.82,-355.15C1376.22,-340.33 1540.12,-318.9 1656.3,-303.72"/>
425 +<polygon fill="black" stroke="black" points="1656.87,-307.17 1666.33,-302.41 1655.96,-300.23 1656.87,-307.17"/>
426 +<text text-anchor="middle" x="1545.02" y="-324.6" font-family="Times,serif" font-size="14.00">capture</text>
427 +</g>
428 +<!-- v38 -->
429 +<g id="node39" class="node">
430 +<title>v38</title>
431 +<polygon fill="none" stroke="black" points="1351.85,-302.4 785,-302.4 785,-266.4 1351.85,-266.4 1351.85,-302.4"/>
432 +<text text-anchor="middle" x="1068.43" y="-280.2" font-family="Times,serif" font-size="14.00">v38 (frozen $22 @ frozen $22 = JSX &lt;frozen $20&gt;{frozen count$17}{frozen $21}&lt;/frozen $20&gt;)</text>
433 +</g>
434 +<!-- v28&#45;&gt;v38 -->
435 +<g id="edge27" class="edge">
436 +<title>v28&#45;&gt;v38</title>
437 +<path fill="none" stroke="black" d="M1127.36,-354.8C1123.73,-344.2 1118.12,-330.75 1110.43,-320.4 1107.54,-316.51 1104.13,-312.78 1100.53,-309.3"/>
438 +<polygon fill="black" stroke="black" points="1102.74,-306.59 1092.95,-302.53 1098.08,-311.81 1102.74,-306.59"/>
439 +<text text-anchor="middle" x="1141.02" y="-324.6" font-family="Times,serif" font-size="14.00">capture</text>
440 +</g>
441 +<!-- v39 -->
442 +<g id="node40" class="node">
443 +<title>v39</title>
444 +<polygon fill="none" stroke="black" points="1947.97,-124.8 1180.88,-124.8 1180.88,-88.8 1947.97,-88.8 1947.97,-124.8"/>
445 +<text text-anchor="middle" x="1564.43" y="-102.6" font-family="Times,serif" font-size="14.00">v39 (frozen $22 @ JSX &lt;frozen $18&gt;{frozen $19}{frozen $22}{frozen $23}{readonly renderedItems$4}{frozen $24}&lt;/frozen $18&gt;)</text>
446 +</g>
447 +<!-- v28&#45;&gt;v39 -->
448 +<g id="edge35" class="edge">
449 +<title>v28&#45;&gt;v39</title>
450 +<path fill="none" stroke="black" d="M932.29,-355.16C863.24,-344.8 797.79,-328.36 776.43,-302.4 766.26,-290.05 767.29,-279.53 776.43,-266.4 866.87,-136.5 955.81,-176.68 1110.43,-142.8 1141.04,-136.09 1173.07,-130.62 1205.33,-126.17"/>
451 +<polygon fill="black" stroke="black" points="1205.9,-129.62 1215.35,-124.82 1204.97,-122.69 1205.9,-129.62"/>
452 +<text text-anchor="middle" x="825.02" y="-235.8" font-family="Times,serif" font-size="14.00">capture</text>
453 +</g>
454 +<!-- v44 -->
455 +<g id="node45" class="node">
456 +<title>v44</title>
457 +<polygon fill="none" stroke="black" points="2153.62,-213.6 1311.24,-213.6 1311.24,-177.6 2153.62,-177.6 2153.62,-213.6"/>
458 +<text text-anchor="middle" x="1732.43" y="-191.4" font-family="Times,serif" font-size="14.00">v44 (frozen $25 @ frozen $25 = JSX &lt;frozen $18&gt;{frozen $19}{frozen $22}{frozen $23}{readonly renderedItems$4}{frozen $24}&lt;/frozen $18&gt;)</text>
459 +</g>
460 +<!-- v29&#45;&gt;v44 -->
461 +<g id="edge34" class="edge">
462 +<title>v29&#45;&gt;v44</title>
463 +<path fill="none" stroke="black" d="M1751.34,-266.33C1744.14,-261.61 1737.62,-255.71 1733.23,-248.4 1728.88,-241.13 1727.62,-232.2 1727.76,-223.81"/>
464 +<polygon fill="black" stroke="black" points="1731.27,-223.89 1728.58,-213.64 1724.29,-223.33 1731.27,-223.89"/>
465 +<text text-anchor="middle" x="1754.02" y="-235.8" font-family="Times,serif" font-size="14.00">capture</text>
466 +</g>
467 +<!-- v45 -->
468 +<g id="node46" class="node">
469 +<title>v45</title>
470 +<polygon fill="none" stroke="black" points="1680.25,-36 1448.6,-36 1448.6,0 1680.25,0 1680.25,-36"/>
471 +<text text-anchor="middle" x="1564.43" y="-13.8" font-family="Times,serif" font-size="14.00">v45 (frozen $25 @ Return frozen $25)</text>
472 +</g>
473 +<!-- v29&#45;&gt;v45 -->
474 +<g id="edge40" class="edge">
475 +<title>v29&#45;&gt;v45</title>
476 +<path fill="none" stroke="black" d="M1517.08,-266.38C1445.47,-255.99 1369.71,-239.54 1302.43,-213.6 1236.8,-188.29 1204.38,-186.94 1171.43,-124.8 1163.93,-110.66 1161.15,-101.06 1171.43,-88.8 1205.13,-48.58 1336.52,-31.52 1438.2,-24.29"/>
477 +<polygon fill="black" stroke="black" points="1438.52,-27.78 1448.26,-23.6 1438.04,-20.79 1438.52,-27.78"/>
478 +<text text-anchor="middle" x="1216.02" y="-147" font-family="Times,serif" font-size="14.00">capture</text>
479 +</g>
480 +<!-- v30 -->
481 +<g id="node31" class="node">
482 +<title>v30</title>
483 +<polygon fill="none" stroke="black" points="5114.86,-822.2 4879.99,-822.2 4879.99,-786.2 5114.86,-786.2 5114.86,-822.2"/>
484 +<text text-anchor="middle" x="4997.43" y="-800" font-family="Times,serif" font-size="14.00">v30 (frozen $18 @ frozen $18 = &quot;div&quot;)</text>
485 +</g>
486 +<!-- v31 -->
487 +<g id="node32" class="node">
488 +<title>v31</title>
489 +<polygon fill="none" stroke="black" points="5380.97,-746.4 4613.88,-746.4 4613.88,-710.4 5380.97,-710.4 5380.97,-746.4"/>
490 +<text text-anchor="middle" x="4997.43" y="-724.2" font-family="Times,serif" font-size="14.00">v31 (frozen $18 @ JSX &lt;frozen $18&gt;{frozen $19}{frozen $22}{frozen $23}{readonly renderedItems$4}{frozen $24}&lt;/frozen $18&gt;)</text>
491 +</g>
492 +<!-- v30&#45;&gt;v31 -->
493 +<g id="edge22" class="edge">
494 +<title>v30&#45;&gt;v31</title>
495 +<path fill="none" stroke="black" d="M4997.43,-786.08C4997.43,-777.33 4997.43,-766.46 4997.43,-756.59"/>
496 +<polygon fill="black" stroke="black" points="5000.93,-756.42 4997.43,-746.42 4993.93,-756.42 5000.93,-756.42"/>
497 +</g>
498 +<!-- v32 -->
499 +<g id="node33" class="node">
500 +<title>v32</title>
501 +<polygon fill="none" stroke="black" points="5886.6,-824.8 5680.26,-824.8 5680.26,-783.6 5886.6,-783.6 5886.6,-824.8"/>
502 +<text text-anchor="middle" x="5783.43" y="-808.4" font-family="Times,serif" font-size="14.00">v32 (frozen $19 @ frozen $19 = &quot;</text>
503 +<text text-anchor="middle" x="5783.43" y="-791.6" font-family="Times,serif" font-size="14.00"> &#160;&#160;&#160;&#160;&#160;&quot;)</text>
504 +</g>
505 +<!-- v33 -->
506 +<g id="node34" class="node">
507 +<title>v33</title>
508 +<polygon fill="none" stroke="black" points="6166.97,-746.4 5399.88,-746.4 5399.88,-710.4 6166.97,-710.4 6166.97,-746.4"/>
509 +<text text-anchor="middle" x="5783.43" y="-724.2" font-family="Times,serif" font-size="14.00">v33 (frozen $19 @ JSX &lt;frozen $18&gt;{frozen $19}{frozen $22}{frozen $23}{readonly renderedItems$4}{frozen $24}&lt;/frozen $18&gt;)</text>
510 +</g>
511 +<!-- v32&#45;&gt;v33 -->
512 +<g id="edge23" class="edge">
513 +<title>v32&#45;&gt;v33</title>
514 +<path fill="none" stroke="black" d="M5783.43,-783.42C5783.43,-775.29 5783.43,-765.73 5783.43,-756.93"/>
515 +<polygon fill="black" stroke="black" points="5786.93,-756.72 5783.43,-746.72 5779.93,-756.72 5786.93,-756.72"/>
516 +</g>
517 +<!-- v34 -->
518 +<g id="node35" class="node">
519 +<title>v34</title>
520 +<polygon fill="none" stroke="black" points="6545.47,-822.2 6315.38,-822.2 6315.38,-786.2 6545.47,-786.2 6545.47,-822.2"/>
521 +<text text-anchor="middle" x="6430.43" y="-800" font-family="Times,serif" font-size="14.00">v34 (frozen $20 @ frozen $20 = &quot;h1&quot;)</text>
522 +</g>
523 +<!-- v35 -->
524 +<g id="node36" class="node">
525 +<title>v35</title>
526 +<polygon fill="none" stroke="black" points="6676.2,-746.4 6184.65,-746.4 6184.65,-710.4 6676.2,-710.4 6676.2,-746.4"/>
527 +<text text-anchor="middle" x="6430.43" y="-724.2" font-family="Times,serif" font-size="14.00">v35 (frozen $20 @ JSX &lt;frozen $20&gt;{frozen count$17}{frozen $21}&lt;/frozen $20&gt;)</text>
528 +</g>
529 +<!-- v34&#45;&gt;v35 -->
530 +<g id="edge24" class="edge">
531 +<title>v34&#45;&gt;v35</title>
532 +<path fill="none" stroke="black" d="M6430.43,-786.08C6430.43,-777.33 6430.43,-766.46 6430.43,-756.59"/>
533 +<polygon fill="black" stroke="black" points="6433.93,-756.42 6430.43,-746.42 6426.93,-756.42 6433.93,-756.42"/>
534 +</g>
535 +<!-- v36 -->
536 +<g id="node37" class="node">
537 +<title>v36</title>
538 +<polygon fill="none" stroke="black" points="7065.08,-822.2 6813.78,-822.2 6813.78,-786.2 7065.08,-786.2 7065.08,-822.2"/>
539 +<text text-anchor="middle" x="6939.43" y="-800" font-family="Times,serif" font-size="14.00">v36 (frozen $21 @ frozen $21 = &quot; Items&quot;)</text>
540 +</g>
541 +<!-- v37 -->
542 +<g id="node38" class="node">
543 +<title>v37</title>
544 +<polygon fill="none" stroke="black" points="7185.2,-746.4 6693.65,-746.4 6693.65,-710.4 7185.2,-710.4 7185.2,-746.4"/>
545 +<text text-anchor="middle" x="6939.43" y="-724.2" font-family="Times,serif" font-size="14.00">v37 (frozen $21 @ JSX &lt;frozen $20&gt;{frozen count$17}{frozen $21}&lt;/frozen $20&gt;)</text>
546 +</g>
547 +<!-- v36&#45;&gt;v37 -->
548 +<g id="edge25" class="edge">
549 +<title>v36&#45;&gt;v37</title>
550 +<path fill="none" stroke="black" d="M6939.43,-786.08C6939.43,-777.33 6939.43,-766.46 6939.43,-756.59"/>
551 +<polygon fill="black" stroke="black" points="6942.93,-756.42 6939.43,-746.42 6935.93,-756.42 6942.93,-756.42"/>
552 +</g>
553 +<!-- v38&#45;&gt;v28 -->
554 +<g id="edge29" class="edge">
555 +<title>v38&#45;&gt;v28</title>
556 +<path fill="none" stroke="black" d="M1062.68,-302.45C1060.14,-313.17 1058.97,-326.88 1065.23,-337.2 1067.94,-341.65 1071.41,-345.57 1075.35,-349"/>
557 +<polygon fill="black" stroke="black" points="1073.33,-351.86 1083.44,-355.03 1077.51,-346.25 1073.33,-351.86"/>
558 +<text text-anchor="middle" x="1086.02" y="-324.6" font-family="Times,serif" font-size="14.00">capture</text>
559 +</g>
560 +<!-- v38&#45;&gt;v39 -->
561 +<g id="edge26" class="edge">
562 +<title>v38&#45;&gt;v39</title>
563 +<path fill="none" stroke="black" d="M1070.43,-266.04C1074.97,-235.39 1089.11,-172.17 1130.43,-142.8 1140.02,-135.98 1170.61,-130.41 1211.43,-125.88"/>
564 +<polygon fill="black" stroke="black" points="1211.86,-129.36 1221.43,-124.81 1211.12,-122.4 1211.86,-129.36"/>
565 +</g>
566 +<!-- v39&#45;&gt;v44 -->
567 +<g id="edge33" class="edge">
568 +<title>v39&#45;&gt;v44</title>
569 +<path fill="none" stroke="black" d="M1590.55,-124.88C1607.27,-135.49 1629.63,-149.06 1650.23,-159.6 1659.65,-164.42 1669.89,-169.15 1679.83,-173.51"/>
570 +<polygon fill="black" stroke="black" points="1678.67,-176.82 1689.24,-177.55 1681.44,-170.39 1678.67,-176.82"/>
571 +<text text-anchor="middle" x="1671.02" y="-147" font-family="Times,serif" font-size="14.00">capture</text>
572 +</g>
573 +<!-- v39&#45;&gt;v45 -->
574 +<g id="edge39" class="edge">
575 +<title>v39&#45;&gt;v45</title>
576 +<path fill="none" stroke="black" d="M1564.43,-88.65C1564.43,-76.52 1564.43,-60.02 1564.43,-46.12"/>
577 +<polygon fill="black" stroke="black" points="1567.93,-46.11 1564.43,-36.11 1560.93,-46.11 1567.93,-46.11"/>
578 +<text text-anchor="middle" x="1585.02" y="-58.2" font-family="Times,serif" font-size="14.00">capture</text>
579 +</g>
580 +<!-- v40 -->
581 +<g id="node41" class="node">
582 +<title>v40</title>
583 +<polygon fill="none" stroke="black" points="7689.6,-824.8 7483.26,-824.8 7483.26,-783.6 7689.6,-783.6 7689.6,-824.8"/>
584 +<text text-anchor="middle" x="7586.43" y="-808.4" font-family="Times,serif" font-size="14.00">v40 (frozen $23 @ frozen $23 = &quot;</text>
585 +<text text-anchor="middle" x="7586.43" y="-791.6" font-family="Times,serif" font-size="14.00"> &#160;&#160;&#160;&#160;&#160;&quot;)</text>
586 +</g>
587 +<!-- v41 -->
588 +<g id="node42" class="node">
589 +<title>v41</title>
590 +<polygon fill="none" stroke="black" points="7969.97,-746.4 7202.88,-746.4 7202.88,-710.4 7969.97,-710.4 7969.97,-746.4"/>
591 +<text text-anchor="middle" x="7586.43" y="-724.2" font-family="Times,serif" font-size="14.00">v41 (frozen $23 @ JSX &lt;frozen $18&gt;{frozen $19}{frozen $22}{frozen $23}{readonly renderedItems$4}{frozen $24}&lt;/frozen $18&gt;)</text>
592 +</g>
593 +<!-- v40&#45;&gt;v41 -->
594 +<g id="edge30" class="edge">
595 +<title>v40&#45;&gt;v41</title>
596 +<path fill="none" stroke="black" d="M7586.43,-783.42C7586.43,-775.29 7586.43,-765.73 7586.43,-756.93"/>
597 +<polygon fill="black" stroke="black" points="7589.93,-756.72 7586.43,-746.72 7582.93,-756.72 7589.93,-756.72"/>
598 +</g>
599 +<!-- v42 -->
600 +<g id="node43" class="node">
601 +<title>v42</title>
602 +<polygon fill="none" stroke="black" points="8475.6,-824.8 8269.26,-824.8 8269.26,-783.6 8475.6,-783.6 8475.6,-824.8"/>
603 +<text text-anchor="middle" x="8372.43" y="-808.4" font-family="Times,serif" font-size="14.00">v42 (frozen $24 @ frozen $24 = &quot;</text>
604 +<text text-anchor="middle" x="8372.43" y="-791.6" font-family="Times,serif" font-size="14.00"> &#160;&#160;&#160;&quot;)</text>
605 +</g>
606 +<!-- v43 -->
607 +<g id="node44" class="node">
608 +<title>v43</title>
609 +<polygon fill="none" stroke="black" points="8755.97,-746.4 7988.88,-746.4 7988.88,-710.4 8755.97,-710.4 8755.97,-746.4"/>
610 +<text text-anchor="middle" x="8372.43" y="-724.2" font-family="Times,serif" font-size="14.00">v43 (frozen $24 @ JSX &lt;frozen $18&gt;{frozen $19}{frozen $22}{frozen $23}{readonly renderedItems$4}{frozen $24}&lt;/frozen $18&gt;)</text>
611 +</g>
612 +<!-- v42&#45;&gt;v43 -->
613 +<g id="edge31" class="edge">
614 +<title>v42&#45;&gt;v43</title>
615 +<path fill="none" stroke="black" d="M8372.43,-783.42C8372.43,-775.29 8372.43,-765.73 8372.43,-756.93"/>
616 +<polygon fill="black" stroke="black" points="8375.93,-756.72 8372.43,-746.72 8368.93,-756.72 8375.93,-756.72"/>
617 +</g>
618 +<!-- v44&#45;&gt;v29 -->
619 +<g id="edge38" class="edge">
620 +<title>v44&#45;&gt;v29</title>
621 +<path fill="none" stroke="black" d="M1756.95,-213.73C1763.22,-218.95 1769.56,-225.05 1774.43,-231.6 1779.95,-239.04 1784.41,-248.08 1787.82,-256.51"/>
622 +<polygon fill="black" stroke="black" points="1784.59,-257.85 1791.36,-266 1791.14,-255.41 1784.59,-257.85"/>
623 +<text text-anchor="middle" x="1805.02" y="-235.8" font-family="Times,serif" font-size="14.00">capture</text>
624 +</g>
625 +<!-- v44&#45;&gt;v39 -->
626 +<g id="edge36" class="edge">
627 +<title>v44&#45;&gt;v39</title>
628 +<path fill="none" stroke="black" d="M1722.74,-177.3C1715.51,-165.91 1704.62,-151.54 1691.43,-142.8 1682.9,-137.15 1673.48,-132.41 1663.74,-128.43"/>
629 +<polygon fill="black" stroke="black" points="1664.91,-125.13 1654.32,-124.84 1662.41,-131.67 1664.91,-125.13"/>
630 +<text text-anchor="middle" x="1730.02" y="-147" font-family="Times,serif" font-size="14.00">capture</text>
631 +</g>
632 +<!-- v44&#45;&gt;v45 -->
633 +<g id="edge32" class="edge">
634 +<title>v44&#45;&gt;v45</title>
635 +<path fill="none" stroke="black" d="M1853.45,-177.57C1925.57,-162.32 1996.17,-135.03 1957.43,-88.8 1923.72,-48.58 1792.34,-31.52 1690.65,-24.29"/>
636 +<polygon fill="black" stroke="black" points="1690.82,-20.79 1680.6,-23.6 1690.34,-27.78 1690.82,-20.79"/>
637 +</g>
638 +<!-- v47&#45;&gt;v24 -->
639 +<g id="edge47" class="edge">
640 +<title>v47&#45;&gt;v24</title>
641 +<path fill="none" stroke="black" d="M4821.68,-621.55C4819.14,-610.83 4817.97,-597.12 4824.23,-586.8 4826.94,-582.35 4830.41,-578.43 4834.35,-575"/>
642 +<polygon fill="black" stroke="black" points="4836.51,-577.75 4842.44,-568.97 4832.33,-572.14 4836.51,-577.75"/>
643 +<text text-anchor="middle" x="4845.02" y="-591" font-family="Times,serif" font-size="14.00">capture</text>
644 +</g>
645 +<!-- v47&#45;&gt;v46 -->
646 +<g id="edge43" class="edge">
647 +<title>v47&#45;&gt;v46</title>
648 +<path fill="none" stroke="black" d="M4765.77,-621.55C4713.81,-607.19 4639.44,-586.63 4584.89,-571.56"/>
649 +<polygon fill="black" stroke="black" points="4585.52,-568.1 4574.95,-568.81 4583.65,-574.84 4585.52,-568.1"/>
650 +</g>
651 +<!-- v51 -->
652 +<g id="node52" class="node">
653 +<title>v51</title>
654 +<polygon fill="none" stroke="black" points="5525.47,-391.2 5011.38,-391.2 5011.38,-355.2 5525.47,-355.2 5525.47,-391.2"/>
655 +<text text-anchor="middle" x="5268.43" y="-369" font-family="Times,serif" font-size="14.00">v51 (mutable $15 @ mutable $15 = JSX &lt;frozen $14&gt;{mutable item$10}&lt;/frozen $14&gt;)</text>
656 +</g>
657 +<!-- v48&#45;&gt;v51 -->
658 +<g id="edge54" class="edge">
659 +<title>v48&#45;&gt;v51</title>
660 +<path fill="none" stroke="black" d="M5287.34,-443.93C5280.14,-439.21 5273.62,-433.31 5269.23,-426 5264.88,-418.73 5263.62,-409.8 5263.76,-401.41"/>
661 +<polygon fill="black" stroke="black" points="5267.27,-401.49 5264.58,-391.24 5260.29,-400.93 5267.27,-401.49"/>
662 +<text text-anchor="middle" x="5290.02" y="-413.4" font-family="Times,serif" font-size="14.00">capture</text>
663 +</g>
664 +<!-- v52 -->
665 +<g id="node53" class="node">
666 +<title>v52</title>
667 +<polygon fill="none" stroke="black" points="5690.11,-302.4 5272.75,-302.4 5272.75,-266.4 5690.11,-266.4 5690.11,-302.4"/>
668 +<text text-anchor="middle" x="5481.43" y="-280.2" font-family="Times,serif" font-size="14.00">v52 (mutable $15 @ Call mutable renderedItems$4.push(mutable $15))</text>
669 +</g>
670 +<!-- v48&#45;&gt;v52 -->
671 +<g id="edge57" class="edge">
672 +<title>v48&#45;&gt;v52</title>
673 +<path fill="none" stroke="black" d="M5456.86,-443.92C5487.04,-433.59 5515.91,-417.19 5534.43,-391.2 5552.96,-365.19 5529.45,-331.77 5508.12,-309.52"/>
674 +<polygon fill="black" stroke="black" points="5510.58,-307.02 5501.03,-302.42 5505.63,-311.97 5510.58,-307.02"/>
675 +<text text-anchor="middle" x="5562.02" y="-369" font-family="Times,serif" font-size="14.00">capture</text>
676 +</g>
677 +<!-- v49 -->
678 +<g id="node50" class="node">
679 +<title>v49</title>
680 +<polygon fill="none" stroke="black" points="9101.86,-822.2 8866.99,-822.2 8866.99,-786.2 9101.86,-786.2 9101.86,-822.2"/>
681 +<text text-anchor="middle" x="8984.43" y="-800" font-family="Times,serif" font-size="14.00">v49 (frozen $14 @ frozen $14 = &quot;div&quot;)</text>
682 +</g>
683 +<!-- v50 -->
684 +<g id="node51" class="node">
685 +<title>v50</title>
686 +<polygon fill="none" stroke="black" points="9194.64,-746.4 8774.22,-746.4 8774.22,-710.4 9194.64,-710.4 9194.64,-746.4"/>
687 +<text text-anchor="middle" x="8984.43" y="-724.2" font-family="Times,serif" font-size="14.00">v50 (frozen $14 @ JSX &lt;frozen $14&gt;{mutable item$10}&lt;/frozen $14&gt;)</text>
688 +</g>
689 +<!-- v49&#45;&gt;v50 -->
690 +<g id="edge52" class="edge">
691 +<title>v49&#45;&gt;v50</title>
692 +<path fill="none" stroke="black" d="M8984.43,-786.08C8984.43,-777.33 8984.43,-766.46 8984.43,-756.59"/>
693 +<polygon fill="black" stroke="black" points="8987.93,-756.42 8984.43,-746.42 8980.93,-756.42 8987.93,-756.42"/>
694 +</g>
695 +<!-- v51&#45;&gt;v48 -->
696 +<g id="edge55" class="edge">
697 +<title>v51&#45;&gt;v48</title>
698 +<path fill="none" stroke="black" d="M5292.95,-391.33C5299.22,-396.55 5305.56,-402.65 5310.43,-409.2 5315.95,-416.64 5320.41,-425.68 5323.82,-434.11"/>
699 +<polygon fill="black" stroke="black" points="5320.59,-435.45 5327.36,-443.6 5327.14,-433.01 5320.59,-435.45"/>
700 +<text text-anchor="middle" x="5341.02" y="-413.4" font-family="Times,serif" font-size="14.00">capture</text>
701 +</g>
702 +<!-- v51&#45;&gt;v52 -->
703 +<g id="edge53" class="edge">
704 +<title>v51&#45;&gt;v52</title>
705 +<path fill="none" stroke="black" d="M5310.26,-355.15C5344.62,-341.15 5393.45,-321.25 5430.16,-306.29"/>
706 +<polygon fill="black" stroke="black" points="5431.76,-309.42 5439.7,-302.41 5429.11,-302.94 5431.76,-309.42"/>
707 +</g>
708 +<!-- v53&#45;&gt;v8 -->
709 +<g id="edge59" class="edge">
710 +<title>v53&#45;&gt;v8</title>
711 +<path fill="none" stroke="black" d="M1607.08,-621.55C1568.68,-607.43 1513.99,-587.31 1473.19,-572.31"/>
712 +<polygon fill="black" stroke="black" points="1474.26,-568.97 1463.67,-568.81 1471.84,-575.54 1474.26,-568.97"/>
713 +</g>
714 +<!-- v53&#45;&gt;v9 -->
715 +<g id="edge60" class="edge">
716 +<title>v53&#45;&gt;v9</title>
717 +<path fill="none" stroke="black" d="M1658.93,-657.71C1660.25,-669.83 1660.53,-686.34 1659.74,-700.24"/>
718 +<polygon fill="black" stroke="black" points="1656.25,-700 1658.93,-710.25 1663.22,-700.56 1656.25,-700"/>
719 +</g>
720 +<!-- v54 -->
721 +<g id="node55" class="node">
722 +<title>v54</title>
723 +<polygon fill="none" stroke="black" points="9647.45,-822.2 9119.4,-822.2 9119.4,-786.2 9647.45,-786.2 9647.45,-822.2"/>
724 +<text text-anchor="middle" x="9383.43" y="-800" font-family="Times,serif" font-size="14.00">v54 (frozen $16 @ frozen $16 = Binary mutable renderedItems$4.length &gt;= frozen max$7)</text>
725 +</g>
726 +<!-- v55 -->
727 +<g id="node56" class="node">
728 +<title>v55</title>
729 +<polygon fill="none" stroke="black" points="9540.95,-746.4 9225.91,-746.4 9225.91,-710.4 9540.95,-710.4 9540.95,-746.4"/>
730 +<text text-anchor="middle" x="9383.43" y="-724.2" font-family="Times,serif" font-size="14.00">v55 (frozen $16 @ If (frozen $16) then:bb2 else:bb1)</text>
731 +</g>
732 +<!-- v54&#45;&gt;v55 -->
733 +<g id="edge58" class="edge">
734 +<title>v54&#45;&gt;v55</title>
735 +<path fill="none" stroke="black" d="M9383.43,-786.08C9383.43,-777.33 9383.43,-766.46 9383.43,-756.59"/>
736 +<polygon fill="black" stroke="black" points="9386.93,-756.42 9383.43,-746.42 9379.93,-756.42 9386.93,-756.42"/>
737 +</g>
738 +</g>
739 +</svg>
compiler/forget/src/__tests__/fixtures/hir-svg/conditional-break.svg new
+145
@@ -0,0 +1,145 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4 +<!-- Generated by graphviz version 6.0.1 (20220924.0800)
5 + -->
6 +<!-- Title: InferMutability Pages: 1 -->
7 +<svg width="1038pt" height="332pt"
8 + viewBox="0.00 0.00 1037.91 332.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9 +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 328)">
10 +<title>InferMutability</title>
11 +<polygon fill="white" stroke="none" points="-4,4 -4,-328 1033.91,-328 1033.91,4 -4,4"/>
12 +<!-- v0 -->
13 +<g id="node1" class="node">
14 +<title>v0</title>
15 +<polygon fill="none" stroke="black" points="377.1,-324 170.26,-324 170.26,-288 377.1,-288 377.1,-324"/>
16 +<text text-anchor="middle" x="273.68" y="-301.8" font-family="Times,serif" font-size="14.00">v0 (frozen props$1 @ &lt;no&#45;instr&gt;)</text>
17 +</g>
18 +<!-- v1 -->
19 +<g id="node2" class="node">
20 +<title>v1</title>
21 +<polygon fill="none" stroke="black" points="466.46,-252 80.89,-252 80.89,-216 466.46,-216 466.46,-252"/>
22 +<text text-anchor="middle" x="273.68" y="-229.8" font-family="Times,serif" font-size="14.00">v1 (frozen props$1.a @ Call mutable a$2.push(frozen props$1.a))</text>
23 +</g>
24 +<!-- v0&#45;&gt;v1 -->
25 +<g id="edge1" class="edge">
26 +<title>v0&#45;&gt;v1</title>
27 +<path fill="none" stroke="black" d="M273.68,-287.7C273.68,-279.98 273.68,-270.71 273.68,-262.11"/>
28 +<polygon fill="black" stroke="black" points="277.18,-262.1 273.68,-252.1 270.18,-262.1 277.18,-262.1"/>
29 +</g>
30 +<!-- v6 -->
31 +<g id="node7" class="node">
32 +<title>v6</title>
33 +<polygon fill="none" stroke="black" points="462.42,-180 84.94,-180 84.94,-144 462.42,-144 462.42,-180"/>
34 +<text text-anchor="middle" x="273.68" y="-157.8" font-family="Times,serif" font-size="14.00">v6 (frozen props$1.b @ If (frozen props$1.b) then:bb1 else:bb2)</text>
35 +</g>
36 +<!-- v1&#45;&gt;v6 -->
37 +<g id="edge5" class="edge">
38 +<title>v1&#45;&gt;v6</title>
39 +<path fill="none" stroke="black" d="M273.68,-215.7C273.68,-207.98 273.68,-198.71 273.68,-190.11"/>
40 +<polygon fill="black" stroke="black" points="277.18,-190.1 273.68,-180.1 270.18,-190.1 277.18,-190.1"/>
41 +</g>
42 +<!-- v2 -->
43 +<g id="node3" class="node">
44 +<title>v2</title>
45 +<polygon fill="none" stroke="black" points="826.88,-324 566.47,-324 566.47,-288 826.88,-288 826.88,-324"/>
46 +<text text-anchor="middle" x="696.68" y="-301.8" font-family="Times,serif" font-size="14.00">v2 (mutable a$2 @ mutable a$2 = Array [])</text>
47 +</g>
48 +<!-- v3 -->
49 +<g id="node4" class="node">
50 +<title>v3</title>
51 +<polygon fill="none" stroke="black" points="892.14,-252 501.21,-252 501.21,-216 892.14,-216 892.14,-252"/>
52 +<text text-anchor="middle" x="696.68" y="-229.8" font-family="Times,serif" font-size="14.00">v3 (mutable a$2.push @ Call mutable a$2.push(frozen props$1.a))</text>
53 +</g>
54 +<!-- v2&#45;&gt;v3 -->
55 +<g id="edge2" class="edge">
56 +<title>v2&#45;&gt;v3</title>
57 +<path fill="none" stroke="black" d="M696.68,-287.7C696.68,-279.98 696.68,-270.71 696.68,-262.11"/>
58 +<polygon fill="black" stroke="black" points="700.18,-262.1 696.68,-252.1 693.18,-262.1 700.18,-262.1"/>
59 +</g>
60 +<!-- v4 -->
61 +<g id="node5" class="node">
62 +<title>v4</title>
63 +<polygon fill="none" stroke="black" points="983.43,-108 591.93,-108 591.93,-72 983.43,-72 983.43,-108"/>
64 +<text text-anchor="middle" x="787.68" y="-85.8" font-family="Times,serif" font-size="14.00">v4 (mutable a$2.push @ Call mutable a$2.push(frozen props$1.d))</text>
65 +</g>
66 +<!-- v3&#45;&gt;v4 -->
67 +<g id="edge3" class="edge">
68 +<title>v3&#45;&gt;v4</title>
69 +<path fill="none" stroke="black" d="M652.61,-215.98C637.12,-207.62 621.42,-195.85 612.68,-180 604.95,-165.99 603.14,-156.85 612.68,-144 622.7,-130.49 636.08,-120.3 650.99,-112.64"/>
70 +<polygon fill="black" stroke="black" points="652.89,-115.61 660.45,-108.19 649.91,-109.28 652.89,-115.61"/>
71 +</g>
72 +<!-- v5 -->
73 +<g id="node6" class="node">
74 +<title>v5</title>
75 +<polygon fill="none" stroke="black" points="1012.14,-180 621.21,-180 621.21,-144 1012.14,-144 1012.14,-180"/>
76 +<text text-anchor="middle" x="816.68" y="-157.8" font-family="Times,serif" font-size="14.00">v5 (mutable a$2.push @ Call mutable a$2.push(frozen props$1.c))</text>
77 +</g>
78 +<!-- v3&#45;&gt;v5 -->
79 +<g id="edge4" class="edge">
80 +<title>v3&#45;&gt;v5</title>
81 +<path fill="none" stroke="black" d="M726.03,-215.88C741.72,-206.72 761.23,-195.34 778.13,-185.48"/>
82 +<polygon fill="black" stroke="black" points="780.34,-188.25 787.21,-180.19 776.81,-182.21 780.34,-188.25"/>
83 +</g>
84 +<!-- v9 -->
85 +<g id="node10" class="node">
86 +<title>v9</title>
87 +<polygon fill="none" stroke="black" points="899.43,-36 675.93,-36 675.93,0 899.43,0 899.43,-36"/>
88 +<text text-anchor="middle" x="787.68" y="-13.8" font-family="Times,serif" font-size="14.00">v9 (frozen a$2 @ Return frozen a$2)</text>
89 +</g>
90 +<!-- v4&#45;&gt;v9 -->
91 +<g id="edge8" class="edge">
92 +<title>v4&#45;&gt;v9</title>
93 +<path fill="none" stroke="black" d="M787.68,-71.7C787.68,-63.98 787.68,-54.71 787.68,-46.11"/>
94 +<polygon fill="black" stroke="black" points="791.18,-46.1 787.68,-36.1 784.18,-46.1 791.18,-46.1"/>
95 +</g>
96 +<!-- v5&#45;&gt;v4 -->
97 +<g id="edge9" class="edge">
98 +<title>v5&#45;&gt;v4</title>
99 +<path fill="none" stroke="black" d="M809.51,-143.7C806.24,-135.81 802.3,-126.3 798.68,-117.55"/>
100 +<polygon fill="black" stroke="black" points="801.82,-116 794.76,-108.1 795.36,-118.68 801.82,-116"/>
101 +</g>
102 +<!-- v5&#45;&gt;v5 -->
103 +<g id="edge10" class="edge">
104 +<title>v5&#45;&gt;v5</title>
105 +<path fill="none" stroke="black" d="M1012.04,-171.17C1023.23,-168.96 1029.91,-165.9 1029.91,-162 1029.91,-159.44 1027.03,-157.24 1021.89,-155.41"/>
106 +<polygon fill="black" stroke="black" points="1022.6,-151.98 1012.04,-152.83 1020.83,-158.75 1022.6,-151.98"/>
107 +</g>
108 +<!-- v7 -->
109 +<g id="node8" class="node">
110 +<title>v7</title>
111 +<polygon fill="none" stroke="black" points="387.53,-36 -0.18,-36 -0.18,0 387.53,0 387.53,-36"/>
112 +<text text-anchor="middle" x="193.68" y="-13.8" font-family="Times,serif" font-size="14.00">v7 (frozen props$1.d @ Call mutable a$2.push(frozen props$1.d))</text>
113 +</g>
114 +<!-- v6&#45;&gt;v7 -->
115 +<g id="edge6" class="edge">
116 +<title>v6&#45;&gt;v7</title>
117 +<path fill="none" stroke="black" d="M149.89,-143.99C131.03,-135.97 113.83,-124.47 101.68,-108 92.17,-95.13 93.67,-85.85 101.68,-72 109.25,-58.9 121.42,-48.76 134.46,-41.02"/>
118 +<polygon fill="black" stroke="black" points="136.49,-43.9 143.58,-36.03 133.13,-37.75 136.49,-43.9"/>
119 +</g>
120 +<!-- v8 -->
121 +<g id="node9" class="node">
122 +<title>v8</title>
123 +<polygon fill="none" stroke="black" points="496.46,-108 110.89,-108 110.89,-72 496.46,-72 496.46,-108"/>
124 +<text text-anchor="middle" x="303.68" y="-85.8" font-family="Times,serif" font-size="14.00">v8 (frozen props$1.c @ Call mutable a$2.push(frozen props$1.c))</text>
125 +</g>
126 +<!-- v6&#45;&gt;v8 -->
127 +<g id="edge7" class="edge">
128 +<title>v6&#45;&gt;v8</title>
129 +<path fill="none" stroke="black" d="M281.09,-143.7C284.47,-135.81 288.55,-126.3 292.3,-117.55"/>
130 +<polygon fill="black" stroke="black" points="295.63,-118.67 296.35,-108.1 289.19,-115.92 295.63,-118.67"/>
131 +</g>
132 +<!-- v8&#45;&gt;v7 -->
133 +<g id="edge11" class="edge">
134 +<title>v8&#45;&gt;v7</title>
135 +<path fill="none" stroke="black" d="M276.77,-71.88C262.52,-62.81 244.83,-51.55 229.44,-41.76"/>
136 +<polygon fill="black" stroke="black" points="231.01,-38.61 220.69,-36.19 227.25,-44.51 231.01,-38.61"/>
137 +</g>
138 +<!-- v8&#45;&gt;v8 -->
139 +<g id="edge12" class="edge">
140 +<title>v8&#45;&gt;v8</title>
141 +<path fill="none" stroke="black" d="M496.59,-99.23C507.84,-97.01 514.57,-93.94 514.57,-90 514.57,-87.42 511.67,-85.2 506.5,-83.36"/>
142 +<polygon fill="black" stroke="black" points="507.15,-79.91 496.59,-80.77 505.38,-86.69 507.15,-79.91"/>
143 +</g>
144 +</g>
145 +</svg>
compiler/forget/src/__tests__/fixtures/hir-svg/conditional-on-mutable.svg new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4 +<!-- Generated by graphviz version 6.0.1 (20220924.0800)
5 + -->
6 +<!-- Title: InferMutability Pages: 1 -->
7 +<svg width="8pt" height="8pt"
8 + viewBox="0.00 0.00 8.00 8.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9 +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 4)">
10 +<title>InferMutability</title>
11 +<polygon fill="white" stroke="none" points="-4,4 -4,-4 4,-4 4,4 -4,4"/>
12 +</g>
13 +</svg>
compiler/forget/src/__tests__/fixtures/hir-svg/constructor.svg new
+286
@@ -0,0 +1,286 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4 +<!-- Generated by graphviz version 6.0.1 (20220924.0800)
5 + -->
6 +<!-- Title: InferMutability Pages: 1 -->
7 +<svg width="2365pt" height="723pt"
8 + viewBox="0.00 0.00 2365.17 722.80" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9 +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 718.8)">
10 +<title>InferMutability</title>
11 +<polygon fill="white" stroke="none" points="-4,4 -4,-718.8 2361.17,-718.8 2361.17,4 -4,4"/>
12 +<!-- v0 -->
13 +<g id="node1" class="node">
14 +<title>v0</title>
15 +<polygon fill="none" stroke="black" points="418.41,-714.8 211.57,-714.8 211.57,-678.8 418.41,-678.8 418.41,-714.8"/>
16 +<text text-anchor="middle" x="314.99" y="-692.6" font-family="Times,serif" font-size="14.00">v0 (frozen props$1 @ &lt;no&#45;instr&gt;)</text>
17 +</g>
18 +<!-- v1 -->
19 +<g id="node2" class="node">
20 +<title>v1</title>
21 +<polygon fill="none" stroke="black" points="697.2,-714.8 436.79,-714.8 436.79,-678.8 697.2,-678.8 697.2,-714.8"/>
22 +<text text-anchor="middle" x="566.99" y="-692.6" font-family="Times,serif" font-size="14.00">v1 (mutable a$2 @ mutable a$2 = Array [])</text>
23 +</g>
24 +<!-- v2 -->
25 +<g id="node3" class="node">
26 +<title>v2</title>
27 +<polygon fill="none" stroke="black" points="767.07,-641.8 366.92,-641.8 366.92,-605.8 767.07,-605.8 767.07,-641.8"/>
28 +<text text-anchor="middle" x="566.99" y="-619.6" font-family="Times,serif" font-size="14.00">v2 (mutable a$2 @ New mutable Foo$4(mutable a$2, mutable b$3))</text>
29 +</g>
30 +<!-- v1&#45;&gt;v2 -->
31 +<g id="edge1" class="edge">
32 +<title>v1&#45;&gt;v2</title>
33 +<path fill="none" stroke="black" d="M566.99,-678.61C566.99,-670.59 566.99,-660.85 566.99,-651.87"/>
34 +<polygon fill="black" stroke="black" points="570.49,-651.83 566.99,-641.83 563.49,-651.83 570.49,-651.83"/>
35 +</g>
36 +<!-- v4 -->
37 +<g id="node5" class="node">
38 +<title>v4</title>
39 +<polygon fill="none" stroke="black" points="914.86,-553 513.13,-553 513.13,-517 914.86,-517 914.86,-553"/>
40 +<text text-anchor="middle" x="713.99" y="-530.8" font-family="Times,serif" font-size="14.00">v4 (mutable b$3 @ New mutable Foo$4(mutable a$2, mutable b$3))</text>
41 +</g>
42 +<!-- v2&#45;&gt;v4 -->
43 +<g id="edge7" class="edge">
44 +<title>v2&#45;&gt;v4</title>
45 +<path fill="none" stroke="black" d="M635.59,-605.75C647.97,-601.03 660.31,-595.13 670.99,-587.8 681.18,-580.81 690.28,-570.77 697.46,-561.38"/>
46 +<polygon fill="black" stroke="black" points="700.46,-563.21 703.48,-553.06 694.79,-559.1 700.46,-563.21"/>
47 +<text text-anchor="middle" x="709.59" y="-575.2" font-family="Times,serif" font-size="14.00">capture</text>
48 +</g>
49 +<!-- v7 -->
50 +<g id="node8" class="node">
51 +<title>v7</title>
52 +<polygon fill="none" stroke="black" points="686.7,-464.2 283.29,-464.2 283.29,-428.2 686.7,-428.2 686.7,-464.2"/>
53 +<text text-anchor="middle" x="484.99" y="-442" font-family="Times,serif" font-size="14.00">v7 (mutable a$2 @ JSX &lt;frozen $6 a={mutable a$2} &gt;&lt;/frozen $6&gt;)</text>
54 +</g>
55 +<!-- v2&#45;&gt;v7 -->
56 +<g id="edge4" class="edge">
57 +<title>v2&#45;&gt;v7</title>
58 +<path fill="none" stroke="black" d="M546.41,-605.71C532.21,-592.74 514.13,-573.67 503.99,-553 491.78,-528.09 487.34,-496.43 485.77,-474.26"/>
59 +<polygon fill="black" stroke="black" points="489.26,-474 485.21,-464.21 482.27,-474.39 489.26,-474"/>
60 +</g>
61 +<!-- v3 -->
62 +<g id="node4" class="node">
63 +<title>v3</title>
64 +<polygon fill="none" stroke="black" points="1063.06,-641.8 784.93,-641.8 784.93,-605.8 1063.06,-605.8 1063.06,-641.8"/>
65 +<text text-anchor="middle" x="923.99" y="-619.6" font-family="Times,serif" font-size="14.00">v3 (mutable b$3 @ mutable b$3 = Object { &#160;})</text>
66 +</g>
67 +<!-- v3&#45;&gt;v4 -->
68 +<g id="edge2" class="edge">
69 +<title>v3&#45;&gt;v4</title>
70 +<path fill="none" stroke="black" d="M882.75,-605.75C848.87,-591.75 800.73,-571.85 764.54,-556.89"/>
71 +<polygon fill="black" stroke="black" points="765.72,-553.59 755.14,-553.01 763.04,-560.06 765.72,-553.59"/>
72 +</g>
73 +<!-- v4&#45;&gt;v2 -->
74 +<g id="edge5" class="edge">
75 +<title>v4&#45;&gt;v2</title>
76 +<path fill="none" stroke="black" d="M666.03,-553.07C653.86,-558.16 641.06,-564.22 629.8,-571 616.64,-578.92 603.34,-589.44 592.39,-598.94"/>
77 +<polygon fill="black" stroke="black" points="590.02,-596.36 584.87,-605.62 594.67,-601.6 590.02,-596.36"/>
78 +<text text-anchor="middle" x="650.59" y="-575.2" font-family="Times,serif" font-size="14.00">capture</text>
79 +</g>
80 +<!-- v4&#45;&gt;v7 -->
81 +<g id="edge11" class="edge">
82 +<title>v4&#45;&gt;v7</title>
83 +<path fill="none" stroke="black" d="M669.02,-516.95C631.84,-502.86 578.91,-482.8 539.36,-467.81"/>
84 +<polygon fill="black" stroke="black" points="540.45,-464.48 529.86,-464.21 537.97,-471.02 540.45,-464.48"/>
85 +<text text-anchor="middle" x="641.59" y="-486.4" font-family="Times,serif" font-size="14.00">capture</text>
86 +</g>
87 +<!-- v8 -->
88 +<g id="node9" class="node">
89 +<title>v8</title>
90 +<polygon fill="none" stroke="black" points="877.54,-375.4 552.44,-375.4 552.44,-339.4 877.54,-339.4 877.54,-375.4"/>
91 +<text text-anchor="middle" x="714.99" y="-353.2" font-family="Times,serif" font-size="14.00">v8 (mutable b$3 @ New mutable Foo$4(mutable b$3))</text>
92 +</g>
93 +<!-- v4&#45;&gt;v8 -->
94 +<g id="edge6" class="edge">
95 +<title>v4&#45;&gt;v8</title>
96 +<path fill="none" stroke="black" d="M714.09,-516.84C714.26,-486.42 714.63,-422.78 714.84,-386.08"/>
97 +<polygon fill="black" stroke="black" points="718.34,-385.65 714.89,-375.63 711.34,-385.61 718.34,-385.65"/>
98 +</g>
99 +<!-- v5 -->
100 +<g id="node6" class="node">
101 +<title>v5</title>
102 +<polygon fill="none" stroke="black" points="1459.14,-714.8 1042.84,-714.8 1042.84,-678.8 1459.14,-678.8 1459.14,-714.8"/>
103 +<text text-anchor="middle" x="1250.99" y="-692.6" font-family="Times,serif" font-size="14.00">v5 (mutable Foo$4 @ New mutable Foo$4(mutable a$2, mutable b$3))</text>
104 +</g>
105 +<!-- v6 -->
106 +<g id="node7" class="node">
107 +<title>v6</title>
108 +<polygon fill="none" stroke="black" points="1421.33,-641.8 1080.65,-641.8 1080.65,-605.8 1421.33,-605.8 1421.33,-641.8"/>
109 +<text text-anchor="middle" x="1250.99" y="-619.6" font-family="Times,serif" font-size="14.00">v6 (mutable Foo$4 @ New mutable Foo$4(mutable b$3))</text>
110 +</g>
111 +<!-- v5&#45;&gt;v6 -->
112 +<g id="edge3" class="edge">
113 +<title>v5&#45;&gt;v6</title>
114 +<path fill="none" stroke="black" d="M1250.99,-678.61C1250.99,-670.59 1250.99,-660.85 1250.99,-651.87"/>
115 +<polygon fill="black" stroke="black" points="1254.49,-651.83 1250.99,-641.83 1247.49,-651.83 1254.49,-651.83"/>
116 +</g>
117 +<!-- v7&#45;&gt;v8 -->
118 +<g id="edge14" class="edge">
119 +<title>v7&#45;&gt;v8</title>
120 +<path fill="none" stroke="black" d="M530.16,-428.15C567.5,-414.06 620.66,-394 660.39,-379.01"/>
121 +<polygon fill="black" stroke="black" points="661.81,-382.21 669.93,-375.41 659.34,-375.66 661.81,-382.21"/>
122 +<text text-anchor="middle" x="641.59" y="-397.6" font-family="Times,serif" font-size="14.00">capture</text>
123 +</g>
124 +<!-- v11 -->
125 +<g id="node12" class="node">
126 +<title>v11</title>
127 +<polygon fill="none" stroke="black" points="495.98,-375.4 0.01,-375.4 0.01,-339.4 495.98,-339.4 495.98,-375.4"/>
128 +<text text-anchor="middle" x="247.99" y="-353.2" font-family="Times,serif" font-size="14.00">v11 (mutable _$5 @ mutable _$5 = JSX &lt;frozen $6 a={mutable a$2} &gt;&lt;/frozen $6&gt;)</text>
129 +</g>
130 +<!-- v7&#45;&gt;v11 -->
131 +<g id="edge9" class="edge">
132 +<title>v7&#45;&gt;v11</title>
133 +<path fill="none" stroke="black" d="M421.4,-428.17C403.28,-422.88 383.63,-416.71 365.8,-410.2 341.3,-401.26 314.65,-389.7 292.9,-379.77"/>
134 +<polygon fill="black" stroke="black" points="294.14,-376.49 283.6,-375.49 291.21,-382.85 294.14,-376.49"/>
135 +<text text-anchor="middle" x="386.59" y="-397.6" font-family="Times,serif" font-size="14.00">capture</text>
136 +</g>
137 +<!-- v12 -->
138 +<g id="node13" class="node">
139 +<title>v12</title>
140 +<polygon fill="none" stroke="black" points="724.78,-286.6 201.21,-286.6 201.21,-250.6 724.78,-250.6 724.78,-286.6"/>
141 +<text text-anchor="middle" x="462.99" y="-264.4" font-family="Times,serif" font-size="14.00">v12 (readonly a$2 @ JSX &lt;frozen $7 a={readonly a$2} b={readonly b$3} &gt;&lt;/frozen $7&gt;)</text>
142 +</g>
143 +<!-- v7&#45;&gt;v12 -->
144 +<g id="edge10" class="edge">
145 +<title>v7&#45;&gt;v12</title>
146 +<path fill="none" stroke="black" d="M492.97,-428.14C501.75,-407.06 513.54,-370.2 504.99,-339.4 500.57,-323.46 491.41,-307.51 482.78,-294.89"/>
147 +<polygon fill="black" stroke="black" points="485.61,-292.83 476.95,-286.72 479.91,-296.89 485.61,-292.83"/>
148 +</g>
149 +<!-- v8&#45;&gt;v12 -->
150 +<g id="edge19" class="edge">
151 +<title>v8&#45;&gt;v12</title>
152 +<path fill="none" stroke="black" d="M665.51,-339.35C624.33,-325.17 565.61,-304.94 521.99,-289.92"/>
153 +<polygon fill="black" stroke="black" points="522.96,-286.55 512.37,-286.61 520.68,-293.17 522.96,-286.55"/>
154 +<text text-anchor="middle" x="632.59" y="-308.8" font-family="Times,serif" font-size="14.00">capture</text>
155 +</g>
156 +<!-- v13 -->
157 +<g id="node14" class="node">
158 +<title>v13</title>
159 +<polygon fill="none" stroke="black" points="1046.07,-197.8 521.92,-197.8 521.92,-161.8 1046.07,-161.8 1046.07,-197.8"/>
160 +<text text-anchor="middle" x="783.99" y="-175.6" font-family="Times,serif" font-size="14.00">v13 (readonly b$3 @ JSX &lt;frozen $7 a={readonly a$2} b={readonly b$3} &gt;&lt;/frozen $7&gt;)</text>
161 +</g>
162 +<!-- v8&#45;&gt;v13 -->
163 +<g id="edge13" class="edge">
164 +<title>v8&#45;&gt;v13</title>
165 +<path fill="none" stroke="black" d="M721.73,-339.24C733.79,-308.56 759.13,-244.08 773.49,-207.54"/>
166 +<polygon fill="black" stroke="black" points="776.82,-208.61 777.22,-198.03 770.31,-206.05 776.82,-208.61"/>
167 +</g>
168 +<!-- v9 -->
169 +<g id="node10" class="node">
170 +<title>v9</title>
171 +<polygon fill="none" stroke="black" points="1743.93,-714.8 1530.06,-714.8 1530.06,-678.8 1743.93,-678.8 1743.93,-714.8"/>
172 +<text text-anchor="middle" x="1636.99" y="-692.6" font-family="Times,serif" font-size="14.00">v9 (frozen $6 @ frozen $6 = &quot;div&quot;)</text>
173 +</g>
174 +<!-- v10 -->
175 +<g id="node11" class="node">
176 +<title>v10</title>
177 +<polygon fill="none" stroke="black" points="1834.64,-641.8 1439.34,-641.8 1439.34,-605.8 1834.64,-605.8 1834.64,-641.8"/>
178 +<text text-anchor="middle" x="1636.99" y="-619.6" font-family="Times,serif" font-size="14.00">v10 (frozen $6 @ JSX &lt;frozen $6 a={mutable a$2} &gt;&lt;/frozen $6&gt;)</text>
179 +</g>
180 +<!-- v9&#45;&gt;v10 -->
181 +<g id="edge8" class="edge">
182 +<title>v9&#45;&gt;v10</title>
183 +<path fill="none" stroke="black" d="M1636.99,-678.61C1636.99,-670.59 1636.99,-660.85 1636.99,-651.87"/>
184 +<polygon fill="black" stroke="black" points="1640.49,-651.83 1636.99,-641.83 1633.49,-651.83 1640.49,-651.83"/>
185 +</g>
186 +<!-- v11&#45;&gt;v7 -->
187 +<g id="edge12" class="edge">
188 +<title>v11&#45;&gt;v7</title>
189 +<path fill="none" stroke="black" d="M351.94,-375.47C370.65,-380.16 389.69,-386.06 406.99,-393.4 424.22,-400.71 441.72,-411.92 455.77,-422.04"/>
190 +<polygon fill="black" stroke="black" points="453.92,-425.03 464.04,-428.16 458.08,-419.4 453.92,-425.03"/>
191 +<text text-anchor="middle" x="457.59" y="-397.6" font-family="Times,serif" font-size="14.00">capture</text>
192 +</g>
193 +<!-- v11&#45;&gt;v12 -->
194 +<g id="edge20" class="edge">
195 +<title>v11&#45;&gt;v12</title>
196 +<path fill="none" stroke="black" d="M290.21,-339.35C324.9,-325.35 374.19,-305.45 411.25,-290.49"/>
197 +<polygon fill="black" stroke="black" points="412.91,-293.6 420.87,-286.61 410.29,-287.1 412.91,-293.6"/>
198 +<text text-anchor="middle" x="395.59" y="-308.8" font-family="Times,serif" font-size="14.00">capture</text>
199 +</g>
200 +<!-- v12&#45;&gt;v13 -->
201 +<g id="edge22" class="edge">
202 +<title>v12&#45;&gt;v13</title>
203 +<path fill="none" stroke="black" d="M526.03,-250.55C579.25,-236.16 655.49,-215.55 711.28,-200.46"/>
204 +<polygon fill="black" stroke="black" points="712.36,-203.8 721.1,-197.81 710.53,-197.04 712.36,-203.8"/>
205 +<text text-anchor="middle" x="673.59" y="-220" font-family="Times,serif" font-size="14.00">capture</text>
206 +</g>
207 +<!-- v16 -->
208 +<g id="node17" class="node">
209 +<title>v16</title>
210 +<polygon fill="none" stroke="black" points="1007.49,-109 434.5,-109 434.5,-73 1007.49,-73 1007.49,-109"/>
211 +<text text-anchor="middle" x="720.99" y="-86.8" font-family="Times,serif" font-size="14.00">v16 (frozen $8 @ frozen $8 = JSX &lt;frozen $7 a={readonly a$2} b={readonly b$3} &gt;&lt;/frozen $7&gt;)</text>
212 +</g>
213 +<!-- v12&#45;&gt;v16 -->
214 +<g id="edge17" class="edge">
215 +<title>v12&#45;&gt;v16</title>
216 +<path fill="none" stroke="black" d="M412.55,-250.41C404.93,-245.74 397.97,-239.9 392.99,-232.6 366.47,-193.71 353.48,-161.96 384.99,-127 390.97,-120.37 413.13,-114.91 443.42,-110.44"/>
217 +<polygon fill="black" stroke="black" points="444.11,-113.88 453.53,-109.03 443.14,-106.95 444.11,-113.88"/>
218 +<text text-anchor="middle" x="393.59" y="-175.6" font-family="Times,serif" font-size="14.00">capture</text>
219 +</g>
220 +<!-- v17 -->
221 +<g id="node18" class="node">
222 +<title>v17</title>
223 +<polygon fill="none" stroke="black" points="829.82,-36 612.17,-36 612.17,0 829.82,0 829.82,-36"/>
224 +<text text-anchor="middle" x="720.99" y="-13.8" font-family="Times,serif" font-size="14.00">v17 (frozen $8 @ Return frozen $8)</text>
225 +</g>
226 +<!-- v12&#45;&gt;v17 -->
227 +<g id="edge24" class="edge">
228 +<title>v12&#45;&gt;v17</title>
229 +<path fill="none" stroke="black" d="M451.62,-250.49C428.6,-213.55 382.28,-125.44 425.99,-73 448.64,-45.83 530.33,-32.29 602.02,-25.57"/>
230 +<polygon fill="black" stroke="black" points="602.42,-29.04 612.07,-24.66 601.79,-22.07 602.42,-29.04"/>
231 +<text text-anchor="middle" x="429.59" y="-131.2" font-family="Times,serif" font-size="14.00">capture</text>
232 +</g>
233 +<!-- v13&#45;&gt;v16 -->
234 +<g id="edge18" class="edge">
235 +<title>v13&#45;&gt;v16</title>
236 +<path fill="none" stroke="black" d="M739.6,-161.61C732.52,-156.9 726.11,-151.04 721.8,-143.8 717.47,-136.52 716.21,-127.58 716.36,-119.19"/>
237 +<polygon fill="black" stroke="black" points="719.86,-119.27 717.17,-109.02 712.89,-118.71 719.86,-119.27"/>
238 +<text text-anchor="middle" x="742.59" y="-131.2" font-family="Times,serif" font-size="14.00">capture</text>
239 +</g>
240 +<!-- v13&#45;&gt;v17 -->
241 +<g id="edge25" class="edge">
242 +<title>v13&#45;&gt;v17</title>
243 +<path fill="none" stroke="black" d="M912.55,-161.75C985.4,-146.71 1054.9,-119.67 1015.99,-73 993.35,-45.83 911.65,-32.29 839.96,-25.57"/>
244 +<polygon fill="black" stroke="black" points="840.19,-22.07 829.92,-24.66 839.56,-29.04 840.19,-22.07"/>
245 +<text text-anchor="middle" x="1048.59" y="-86.8" font-family="Times,serif" font-size="14.00">capture</text>
246 +</g>
247 +<!-- v14 -->
248 +<g id="node15" class="node">
249 +<title>v14</title>
250 +<polygon fill="none" stroke="black" points="2215.43,-714.8 1994.56,-714.8 1994.56,-678.8 2215.43,-678.8 2215.43,-714.8"/>
251 +<text text-anchor="middle" x="2104.99" y="-692.6" font-family="Times,serif" font-size="14.00">v14 (frozen $7 @ frozen $7 = &quot;div&quot;)</text>
252 +</g>
253 +<!-- v15 -->
254 +<g id="node16" class="node">
255 +<title>v15</title>
256 +<polygon fill="none" stroke="black" points="2357.34,-641.8 1852.65,-641.8 1852.65,-605.8 2357.34,-605.8 2357.34,-641.8"/>
257 +<text text-anchor="middle" x="2104.99" y="-619.6" font-family="Times,serif" font-size="14.00">v15 (frozen $7 @ JSX &lt;frozen $7 a={readonly a$2} b={readonly b$3} &gt;&lt;/frozen $7&gt;)</text>
258 +</g>
259 +<!-- v14&#45;&gt;v15 -->
260 +<g id="edge15" class="edge">
261 +<title>v14&#45;&gt;v15</title>
262 +<path fill="none" stroke="black" d="M2104.99,-678.61C2104.99,-670.59 2104.99,-660.85 2104.99,-651.87"/>
263 +<polygon fill="black" stroke="black" points="2108.49,-651.83 2104.99,-641.83 2101.49,-651.83 2108.49,-651.83"/>
264 +</g>
265 +<!-- v16&#45;&gt;v12 -->
266 +<g id="edge21" class="edge">
267 +<title>v16&#45;&gt;v12</title>
268 +<path fill="none" stroke="black" d="M616.2,-109.04C556.84,-120.96 490.75,-138.85 471.8,-161.8 453.88,-183.49 454.2,-216.92 457.38,-240.39"/>
269 +<polygon fill="black" stroke="black" points="453.94,-241.07 458.98,-250.39 460.85,-239.96 453.94,-241.07"/>
270 +<text text-anchor="middle" x="492.59" y="-175.6" font-family="Times,serif" font-size="14.00">capture</text>
271 +</g>
272 +<!-- v16&#45;&gt;v13 -->
273 +<g id="edge23" class="edge">
274 +<title>v16&#45;&gt;v13</title>
275 +<path fill="none" stroke="black" d="M745.59,-109.08C751.86,-114.29 758.18,-120.41 762.99,-127 768.42,-134.44 772.71,-143.47 775.96,-151.91"/>
276 +<polygon fill="black" stroke="black" points="772.68,-153.13 779.3,-161.4 779.28,-150.8 772.68,-153.13"/>
277 +<text text-anchor="middle" x="793.59" y="-131.2" font-family="Times,serif" font-size="14.00">capture</text>
278 +</g>
279 +<!-- v16&#45;&gt;v17 -->
280 +<g id="edge16" class="edge">
281 +<title>v16&#45;&gt;v17</title>
282 +<path fill="none" stroke="black" d="M720.99,-72.81C720.99,-64.79 720.99,-55.05 720.99,-46.07"/>
283 +<polygon fill="black" stroke="black" points="724.49,-46.03 720.99,-36.03 717.49,-46.03 724.49,-46.03"/>
284 +</g>
285 +</g>
286 +</svg>
compiler/forget/src/__tests__/fixtures/hir-svg/hook-call.svg new
+184
@@ -0,0 +1,184 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4 +<!-- Generated by graphviz version 6.0.1 (20220924.0800)
5 + -->
6 +<!-- Title: InferMutability Pages: 1 -->
7 +<svg width="5481pt" height="266pt"
8 + viewBox="0.00 0.00 5480.57 265.60" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9 +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 261.6)">
10 +<title>InferMutability</title>
11 +<polygon fill="white" stroke="none" points="-4,4 -4,-261.6 5476.57,-261.6 5476.57,4 -4,4"/>
12 +<!-- v0 -->
13 +<g id="node1" class="node">
14 +<title>v0</title>
15 +<polygon fill="none" stroke="black" points="245.38,-254.8 38.53,-254.8 38.53,-218.8 245.38,-218.8 245.38,-254.8"/>
16 +<text text-anchor="middle" x="141.95" y="-232.6" font-family="Times,serif" font-size="14.00">v0 (frozen props$1 @ &lt;no&#45;instr&gt;)</text>
17 +</g>
18 +<!-- v1 -->
19 +<g id="node2" class="node">
20 +<title>v1</title>
21 +<polygon fill="none" stroke="black" points="506.54,-254.8 263.36,-254.8 263.36,-218.8 506.54,-218.8 506.54,-254.8"/>
22 +<text text-anchor="middle" x="384.95" y="-232.6" font-family="Times,serif" font-size="14.00">v1 (frozen x$2 @ frozen x$2 = Array [])</text>
23 +</g>
24 +<!-- v2 -->
25 +<g id="node3" class="node">
26 +<title>v2</title>
27 +<polygon fill="none" stroke="black" points="549.05,-180 220.86,-180 220.86,-144 549.05,-144 549.05,-180"/>
28 +<text text-anchor="middle" x="384.95" y="-157.8" font-family="Times,serif" font-size="14.00">v2 (frozen x$2 @ Call frozen useFreeze$4(frozen x$2))</text>
29 +</g>
30 +<!-- v1&#45;&gt;v2 -->
31 +<g id="edge1" class="edge">
32 +<title>v1&#45;&gt;v2</title>
33 +<path fill="none" stroke="black" d="M384.95,-218.55C384.95,-210.12 384.95,-199.77 384.95,-190.3"/>
34 +<polygon fill="black" stroke="black" points="388.45,-190.13 384.95,-180.13 381.45,-190.13 388.45,-190.13"/>
35 +</g>
36 +<!-- v6 -->
37 +<g id="node7" class="node">
38 +<title>v6</title>
39 +<polygon fill="none" stroke="black" points="568.84,-108 201.07,-108 201.07,-72 568.84,-72 568.84,-108"/>
40 +<text text-anchor="middle" x="384.95" y="-85.8" font-family="Times,serif" font-size="14.00">v6 (frozen x$2 @ Call mutable foo$5(frozen y$3, frozen x$2))</text>
41 +</g>
42 +<!-- v2&#45;&gt;v6 -->
43 +<g id="edge3" class="edge">
44 +<title>v2&#45;&gt;v6</title>
45 +<path fill="none" stroke="black" d="M384.95,-143.7C384.95,-135.98 384.95,-126.71 384.95,-118.11"/>
46 +<polygon fill="black" stroke="black" points="388.45,-118.1 384.95,-108.1 381.45,-118.1 388.45,-118.1"/>
47 +</g>
48 +<!-- v3 -->
49 +<g id="node4" class="node">
50 +<title>v3</title>
51 +<polygon fill="none" stroke="black" points="1173.7,-254.8 770.21,-254.8 770.21,-218.8 1173.7,-218.8 1173.7,-254.8"/>
52 +<text text-anchor="middle" x="971.95" y="-232.6" font-family="Times,serif" font-size="14.00">v3 (frozen y$3 @ frozen y$3 = Call frozen useFreeze$4(frozen x$2))</text>
53 +</g>
54 +<!-- v4 -->
55 +<g id="node5" class="node">
56 +<title>v4</title>
57 +<polygon fill="none" stroke="black" points="1155.84,-180 788.07,-180 788.07,-144 1155.84,-144 1155.84,-180"/>
58 +<text text-anchor="middle" x="971.95" y="-157.8" font-family="Times,serif" font-size="14.00">v4 (frozen y$3 @ Call mutable foo$5(frozen y$3, frozen x$2))</text>
59 +</g>
60 +<!-- v3&#45;&gt;v4 -->
61 +<g id="edge2" class="edge">
62 +<title>v3&#45;&gt;v4</title>
63 +<path fill="none" stroke="black" d="M971.95,-218.55C971.95,-210.12 971.95,-199.77 971.95,-190.3"/>
64 +<polygon fill="black" stroke="black" points="975.45,-190.13 971.95,-180.13 968.45,-190.13 975.45,-190.13"/>
65 +</g>
66 +<!-- v8 -->
67 +<g id="node9" class="node">
68 +<title>v8</title>
69 +<polygon fill="none" stroke="black" points="1356.86,-108 587.05,-108 587.05,-72 1356.86,-72 1356.86,-108"/>
70 +<text text-anchor="middle" x="971.95" y="-85.8" font-family="Times,serif" font-size="14.00">v8 (frozen y$3 @ JSX &lt;frozen Component$0&gt;{frozen $6}{frozen x$2}{frozen $7}{frozen y$3}{frozen $8}&lt;/frozen Component$0&gt;)</text>
71 +</g>
72 +<!-- v4&#45;&gt;v8 -->
73 +<g id="edge4" class="edge">
74 +<title>v4&#45;&gt;v8</title>
75 +<path fill="none" stroke="black" d="M971.95,-143.7C971.95,-135.98 971.95,-126.71 971.95,-118.11"/>
76 +<polygon fill="black" stroke="black" points="975.45,-118.1 971.95,-108.1 968.45,-118.1 975.45,-118.1"/>
77 +</g>
78 +<!-- v5 -->
79 +<g id="node6" class="node">
80 +<title>v5</title>
81 +<polygon fill="none" stroke="black" points="1569.51,-254.8 1192.39,-254.8 1192.39,-218.8 1569.51,-218.8 1569.51,-254.8"/>
82 +<text text-anchor="middle" x="1380.95" y="-232.6" font-family="Times,serif" font-size="14.00">v5 (frozen useFreeze$4 @ Call frozen useFreeze$4(frozen x$2))</text>
83 +</g>
84 +<!-- v9 -->
85 +<g id="node10" class="node">
86 +<title>v9</title>
87 +<polygon fill="none" stroke="black" points="769.86,-36 0.05,-36 0.05,0 769.86,0 769.86,-36"/>
88 +<text text-anchor="middle" x="384.95" y="-13.8" font-family="Times,serif" font-size="14.00">v9 (frozen x$2 @ JSX &lt;frozen Component$0&gt;{frozen $6}{frozen x$2}{frozen $7}{frozen y$3}{frozen $8}&lt;/frozen Component$0&gt;)</text>
89 +</g>
90 +<!-- v6&#45;&gt;v9 -->
91 +<g id="edge5" class="edge">
92 +<title>v6&#45;&gt;v9</title>
93 +<path fill="none" stroke="black" d="M384.95,-71.7C384.95,-63.98 384.95,-54.71 384.95,-46.11"/>
94 +<polygon fill="black" stroke="black" points="388.45,-46.1 384.95,-36.1 381.45,-46.1 388.45,-46.1"/>
95 +</g>
96 +<!-- v7 -->
97 +<g id="node8" class="node">
98 +<title>v7</title>
99 +<polygon fill="none" stroke="black" points="1976.35,-254.8 1587.56,-254.8 1587.56,-218.8 1976.35,-218.8 1976.35,-254.8"/>
100 +<text text-anchor="middle" x="1781.95" y="-232.6" font-family="Times,serif" font-size="14.00">v7 (mutable foo$5 @ Call mutable foo$5(frozen y$3, frozen x$2))</text>
101 +</g>
102 +<!-- v10 -->
103 +<g id="node11" class="node">
104 +<title>v10</title>
105 +<polygon fill="none" stroke="black" points="2187.12,-257.4 1994.79,-257.4 1994.79,-216.2 2187.12,-216.2 2187.12,-257.4"/>
106 +<text text-anchor="middle" x="2090.95" y="-241" font-family="Times,serif" font-size="14.00">v10 (frozen $6 @ frozen $6 = &quot;</text>
107 +<text text-anchor="middle" x="2090.95" y="-224.2" font-family="Times,serif" font-size="14.00"> &#160;&#160;&#160;&#160;&#160;&quot;)</text>
108 +</g>
109 +<!-- v11 -->
110 +<g id="node12" class="node">
111 +<title>v11</title>
112 +<polygon fill="none" stroke="black" points="2475.86,-180 1706.05,-180 1706.05,-144 2475.86,-144 2475.86,-180"/>
113 +<text text-anchor="middle" x="2090.95" y="-157.8" font-family="Times,serif" font-size="14.00">v11 (frozen $6 @ JSX &lt;frozen Component$0&gt;{frozen $6}{frozen x$2}{frozen $7}{frozen y$3}{frozen $8}&lt;/frozen Component$0&gt;)</text>
114 +</g>
115 +<!-- v10&#45;&gt;v11 -->
116 +<g id="edge6" class="edge">
117 +<title>v10&#45;&gt;v11</title>
118 +<path fill="none" stroke="black" d="M2090.95,-215.91C2090.95,-208.09 2090.95,-198.99 2090.95,-190.56"/>
119 +<polygon fill="black" stroke="black" points="2094.45,-190.39 2090.95,-180.39 2087.45,-190.39 2094.45,-190.39"/>
120 +</g>
121 +<!-- v12 -->
122 +<g id="node13" class="node">
123 +<title>v12</title>
124 +<polygon fill="none" stroke="black" points="2975.12,-257.4 2782.79,-257.4 2782.79,-216.2 2975.12,-216.2 2975.12,-257.4"/>
125 +<text text-anchor="middle" x="2878.95" y="-241" font-family="Times,serif" font-size="14.00">v12 (frozen $7 @ frozen $7 = &quot;</text>
126 +<text text-anchor="middle" x="2878.95" y="-224.2" font-family="Times,serif" font-size="14.00"> &#160;&#160;&#160;&#160;&#160;&quot;)</text>
127 +</g>
128 +<!-- v13 -->
129 +<g id="node14" class="node">
130 +<title>v13</title>
131 +<polygon fill="none" stroke="black" points="3263.86,-180 2494.05,-180 2494.05,-144 3263.86,-144 3263.86,-180"/>
132 +<text text-anchor="middle" x="2878.95" y="-157.8" font-family="Times,serif" font-size="14.00">v13 (frozen $7 @ JSX &lt;frozen Component$0&gt;{frozen $6}{frozen x$2}{frozen $7}{frozen y$3}{frozen $8}&lt;/frozen Component$0&gt;)</text>
133 +</g>
134 +<!-- v12&#45;&gt;v13 -->
135 +<g id="edge7" class="edge">
136 +<title>v12&#45;&gt;v13</title>
137 +<path fill="none" stroke="black" d="M2878.95,-215.91C2878.95,-208.09 2878.95,-198.99 2878.95,-190.56"/>
138 +<polygon fill="black" stroke="black" points="2882.45,-190.39 2878.95,-180.39 2875.45,-190.39 2882.45,-190.39"/>
139 +</g>
140 +<!-- v14 -->
141 +<g id="node15" class="node">
142 +<title>v14</title>
143 +<polygon fill="none" stroke="black" points="3763.12,-257.4 3570.79,-257.4 3570.79,-216.2 3763.12,-216.2 3763.12,-257.4"/>
144 +<text text-anchor="middle" x="3666.95" y="-241" font-family="Times,serif" font-size="14.00">v14 (frozen $8 @ frozen $8 = &quot;</text>
145 +<text text-anchor="middle" x="3666.95" y="-224.2" font-family="Times,serif" font-size="14.00"> &#160;&#160;&#160;&quot;)</text>
146 +</g>
147 +<!-- v15 -->
148 +<g id="node16" class="node">
149 +<title>v15</title>
150 +<polygon fill="none" stroke="black" points="4051.86,-180 3282.05,-180 3282.05,-144 4051.86,-144 4051.86,-180"/>
151 +<text text-anchor="middle" x="3666.95" y="-157.8" font-family="Times,serif" font-size="14.00">v15 (frozen $8 @ JSX &lt;frozen Component$0&gt;{frozen $6}{frozen x$2}{frozen $7}{frozen y$3}{frozen $8}&lt;/frozen Component$0&gt;)</text>
152 +</g>
153 +<!-- v14&#45;&gt;v15 -->
154 +<g id="edge8" class="edge">
155 +<title>v14&#45;&gt;v15</title>
156 +<path fill="none" stroke="black" d="M3666.95,-215.91C3666.95,-208.09 3666.95,-198.99 3666.95,-190.56"/>
157 +<polygon fill="black" stroke="black" points="3670.45,-190.39 3666.95,-180.39 3663.45,-190.39 3670.45,-190.39"/>
158 +</g>
159 +<!-- v16 -->
160 +<g id="node17" class="node">
161 +<title>v16</title>
162 +<polygon fill="none" stroke="black" points="4619.01,-254.8 3780.9,-254.8 3780.9,-218.8 4619.01,-218.8 4619.01,-254.8"/>
163 +<text text-anchor="middle" x="4199.95" y="-232.6" font-family="Times,serif" font-size="14.00">v16 (frozen $9 @ frozen $9 = JSX &lt;frozen Component$0&gt;{frozen $6}{frozen x$2}{frozen $7}{frozen y$3}{frozen $8}&lt;/frozen Component$0&gt;)</text>
164 +</g>
165 +<!-- v17 -->
166 +<g id="node18" class="node">
167 +<title>v17</title>
168 +<polygon fill="none" stroke="black" points="4308.78,-180 4091.13,-180 4091.13,-144 4308.78,-144 4308.78,-180"/>
169 +<text text-anchor="middle" x="4199.95" y="-157.8" font-family="Times,serif" font-size="14.00">v17 (frozen $9 @ Return frozen $9)</text>
170 +</g>
171 +<!-- v16&#45;&gt;v17 -->
172 +<g id="edge9" class="edge">
173 +<title>v16&#45;&gt;v17</title>
174 +<path fill="none" stroke="black" d="M4199.95,-218.55C4199.95,-210.12 4199.95,-199.77 4199.95,-190.3"/>
175 +<polygon fill="black" stroke="black" points="4203.45,-190.13 4199.95,-180.13 4196.45,-190.13 4203.45,-190.13"/>
176 +</g>
177 +<!-- v18 -->
178 +<g id="node19" class="node">
179 +<title>v18</title>
180 +<polygon fill="none" stroke="black" points="5472.69,-254.8 4637.21,-254.8 4637.21,-218.8 5472.69,-218.8 5472.69,-254.8"/>
181 +<text text-anchor="middle" x="5054.95" y="-232.6" font-family="Times,serif" font-size="14.00">v18 (frozen Component$0 @ JSX &lt;frozen Component$0&gt;{frozen $6}{frozen x$2}{frozen $7}{frozen y$3}{frozen $8}&lt;/frozen Component$0&gt;)</text>
182 +</g>
183 +</g>
184 +</svg>
compiler/forget/src/__tests__/fixtures/hir-svg/independent-across-if.svg new
+241
@@ -0,0 +1,241 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4 +<!-- Generated by graphviz version 6.0.1 (20220924.0800)
5 + -->
6 +<!-- Title: InferMutability Pages: 1 -->
7 +<svg width="2398pt" height="456pt"
8 + viewBox="0.00 0.00 2397.55 456.40" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9 +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 452.4)">
10 +<title>InferMutability</title>
11 +<polygon fill="white" stroke="none" points="-4,4 -4,-452.4 2393.55,-452.4 2393.55,4 -4,4"/>
12 +<!-- v0 -->
13 +<g id="node1" class="node">
14 +<title>v0</title>
15 +<polygon fill="none" stroke="black" points="303.12,-448.4 96.28,-448.4 96.28,-412.4 303.12,-412.4 303.12,-448.4"/>
16 +<text text-anchor="middle" x="199.7" y="-426.2" font-family="Times,serif" font-size="14.00">v0 (frozen props$1 @ &lt;no&#45;instr&gt;)</text>
17 +</g>
18 +<!-- v1 -->
19 +<g id="node2" class="node">
20 +<title>v1</title>
21 +<polygon fill="none" stroke="black" points="398.53,-375.4 0.87,-375.4 0.87,-339.4 398.53,-339.4 398.53,-375.4"/>
22 +<text text-anchor="middle" x="199.7" y="-353.2" font-family="Times,serif" font-size="14.00">v1 (frozen props$1.a @ Call mutable compute$3(frozen props$1.a))</text>
23 +</g>
24 +<!-- v0&#45;&gt;v1 -->
25 +<g id="edge1" class="edge">
26 +<title>v0&#45;&gt;v1</title>
27 +<path fill="none" stroke="black" d="M199.7,-412.21C199.7,-404.19 199.7,-394.45 199.7,-385.47"/>
28 +<polygon fill="black" stroke="black" points="203.2,-385.43 199.7,-375.43 196.2,-385.43 203.2,-385.43"/>
29 +</g>
30 +<!-- v7 -->
31 +<g id="node8" class="node">
32 +<title>v7</title>
33 +<polygon fill="none" stroke="black" points="399.6,-302.4 -0.2,-302.4 -0.2,-266.4 399.6,-266.4 399.6,-302.4"/>
34 +<text text-anchor="middle" x="199.7" y="-280.2" font-family="Times,serif" font-size="14.00">v7 (frozen props$1.b @ Call mutable compute$3(frozen props$1.b))</text>
35 +</g>
36 +<!-- v1&#45;&gt;v7 -->
37 +<g id="edge5" class="edge">
38 +<title>v1&#45;&gt;v7</title>
39 +<path fill="none" stroke="black" d="M199.7,-339.21C199.7,-331.19 199.7,-321.45 199.7,-312.47"/>
40 +<polygon fill="black" stroke="black" points="203.2,-312.43 199.7,-302.43 196.2,-312.43 203.2,-312.43"/>
41 +</g>
42 +<!-- v2 -->
43 +<g id="node3" class="node">
44 +<title>v2</title>
45 +<polygon fill="none" stroke="black" points="974.97,-448.4 518.43,-448.4 518.43,-412.4 974.97,-412.4 974.97,-448.4"/>
46 +<text text-anchor="middle" x="746.7" y="-426.2" font-family="Times,serif" font-size="14.00">v2 (mutable a$2 @ mutable a$2 = Call mutable compute$3(frozen props$1.a))</text>
47 +</g>
48 +<!-- v3 -->
49 +<g id="node4" class="node">
50 +<title>v3</title>
51 +<polygon fill="none" stroke="black" points="754.39,-375.4 417.01,-375.4 417.01,-339.4 754.39,-339.4 754.39,-375.4"/>
52 +<text text-anchor="middle" x="585.7" y="-353.2" font-family="Times,serif" font-size="14.00">v3 (mutable a$2 @ Call mutable mutate$5(mutable a$2))</text>
53 +</g>
54 +<!-- v2&#45;&gt;v3 -->
55 +<g id="edge2" class="edge">
56 +<title>v2&#45;&gt;v3</title>
57 +<path fill="none" stroke="black" d="M708.14,-412.39C685.8,-402.54 657.48,-390.06 633.71,-379.57"/>
58 +<polygon fill="black" stroke="black" points="635.07,-376.35 624.51,-375.51 632.24,-382.75 635.07,-376.35"/>
59 +</g>
60 +<!-- v4 -->
61 +<g id="node5" class="node">
62 +<title>v4</title>
63 +<polygon fill="none" stroke="black" points="1030.06,-302.4 469.34,-302.4 469.34,-266.4 1030.06,-266.4 1030.06,-302.4"/>
64 +<text text-anchor="middle" x="749.7" y="-280.2" font-family="Times,serif" font-size="14.00">v4 (readonly a$2 @ JSX &lt;frozen Foo$6 a={readonly a$2} b={readonly b$4} &gt;&lt;/frozen Foo$6&gt;)</text>
65 +</g>
66 +<!-- v2&#45;&gt;v4 -->
67 +<g id="edge3" class="edge">
68 +<title>v2&#45;&gt;v4</title>
69 +<path fill="none" stroke="black" d="M761.52,-412.21C769.17,-402.19 777.71,-388.9 781.7,-375.4 786.24,-360.06 785.93,-354.83 781.7,-339.4 779.01,-329.57 774.01,-319.72 768.75,-311.17"/>
70 +<polygon fill="black" stroke="black" points="771.67,-309.24 763.27,-302.79 765.82,-313.07 771.67,-309.24"/>
71 +</g>
72 +<!-- v3&#45;&gt;v3 -->
73 +<g id="edge10" class="edge">
74 +<title>v3&#45;&gt;v3</title>
75 +<path fill="none" stroke="black" d="M754.48,-362.28C765.57,-361.15 772.29,-359.52 772.29,-357.4 772.29,-356.04 769.54,-354.88 764.64,-353.93"/>
76 +<polygon fill="black" stroke="black" points="764.86,-350.43 754.48,-352.52 763.9,-357.36 764.86,-350.43"/>
77 +</g>
78 +<!-- v3&#45;&gt;v4 -->
79 +<g id="edge11" class="edge">
80 +<title>v3&#45;&gt;v4</title>
81 +<path fill="none" stroke="black" d="M624.98,-339.39C647.74,-329.54 676.58,-317.06 700.8,-306.57"/>
82 +<polygon fill="black" stroke="black" points="702.38,-309.7 710.17,-302.51 699.6,-303.27 702.38,-309.7"/>
83 +</g>
84 +<!-- v14 -->
85 +<g id="node15" class="node">
86 +<title>v14</title>
87 +<polygon fill="none" stroke="black" points="1121.77,-213.6 505.63,-213.6 505.63,-177.6 1121.77,-177.6 1121.77,-213.6"/>
88 +<text text-anchor="middle" x="813.7" y="-191.4" font-family="Times,serif" font-size="14.00">v14 (frozen $7 @ frozen $7 = JSX &lt;frozen Foo$6 a={readonly a$2} b={readonly b$4} &gt;&lt;/frozen Foo$6&gt;)</text>
89 +</g>
90 +<!-- v4&#45;&gt;v14 -->
91 +<g id="edge15" class="edge">
92 +<title>v4&#45;&gt;v14</title>
93 +<path fill="none" stroke="black" d="M745.85,-266.36C744.38,-255.64 744.31,-241.94 750.51,-231.6 753.18,-227.14 756.64,-223.21 760.57,-219.75"/>
94 +<polygon fill="black" stroke="black" points="762.75,-222.5 768.61,-213.67 758.53,-216.91 762.75,-222.5"/>
95 +<text text-anchor="middle" x="771.3" y="-235.8" font-family="Times,serif" font-size="14.00">capture</text>
96 +</g>
97 +<!-- v15 -->
98 +<g id="node16" class="node">
99 +<title>v15</title>
100 +<polygon fill="none" stroke="black" points="878.52,-36 660.88,-36 660.88,0 878.52,0 878.52,-36"/>
101 +<text text-anchor="middle" x="769.7" y="-13.8" font-family="Times,serif" font-size="14.00">v15 (frozen $7 @ Return frozen $7)</text>
102 +</g>
103 +<!-- v4&#45;&gt;v15 -->
104 +<g id="edge19" class="edge">
105 +<title>v4&#45;&gt;v15</title>
106 +<path fill="none" stroke="black" d="M582.36,-266.4C519.37,-252.13 468.91,-225.88 496.7,-177.6 539.03,-104.06 629.99,-61.46 695.29,-39.28"/>
107 +<polygon fill="black" stroke="black" points="696.74,-42.49 705.13,-36.02 694.54,-35.84 696.74,-42.49"/>
108 +<text text-anchor="middle" x="542.3" y="-147" font-family="Times,serif" font-size="14.00">capture</text>
109 +</g>
110 +<!-- v5 -->
111 +<g id="node6" class="node">
112 +<title>v5</title>
113 +<polygon fill="none" stroke="black" points="1406.76,-448.4 992.64,-448.4 992.64,-412.4 1406.76,-412.4 1406.76,-448.4"/>
114 +<text text-anchor="middle" x="1199.7" y="-426.2" font-family="Times,serif" font-size="14.00">v5 (mutable compute$3 @ Call mutable compute$3(frozen props$1.a))</text>
115 +</g>
116 +<!-- v6 -->
117 +<g id="node7" class="node">
118 +<title>v6</title>
119 +<polygon fill="none" stroke="black" points="1407.54,-375.4 991.86,-375.4 991.86,-339.4 1407.54,-339.4 1407.54,-375.4"/>
120 +<text text-anchor="middle" x="1199.7" y="-353.2" font-family="Times,serif" font-size="14.00">v6 (mutable compute$3 @ Call mutable compute$3(frozen props$1.b))</text>
121 +</g>
122 +<!-- v5&#45;&gt;v6 -->
123 +<g id="edge4" class="edge">
124 +<title>v5&#45;&gt;v6</title>
125 +<path fill="none" stroke="black" d="M1199.7,-412.21C1199.7,-404.19 1199.7,-394.45 1199.7,-385.47"/>
126 +<polygon fill="black" stroke="black" points="1203.2,-385.43 1199.7,-375.43 1196.2,-385.43 1203.2,-385.43"/>
127 +</g>
128 +<!-- v11 -->
129 +<g id="node12" class="node">
130 +<title>v11</title>
131 +<polygon fill="none" stroke="black" points="390.87,-213.6 8.53,-213.6 8.53,-177.6 390.87,-177.6 390.87,-213.6"/>
132 +<text text-anchor="middle" x="199.7" y="-191.4" font-family="Times,serif" font-size="14.00">v11 (frozen props$1.c @ If (frozen props$1.c) then:bb2 else:bb1)</text>
133 +</g>
134 +<!-- v7&#45;&gt;v11 -->
135 +<g id="edge8" class="edge">
136 +<title>v7&#45;&gt;v11</title>
137 +<path fill="none" stroke="black" d="M199.7,-266.25C199.7,-254.12 199.7,-237.62 199.7,-223.72"/>
138 +<polygon fill="black" stroke="black" points="203.2,-223.71 199.7,-213.71 196.2,-223.71 203.2,-223.71"/>
139 +</g>
140 +<!-- v8 -->
141 +<g id="node9" class="node">
142 +<title>v8</title>
143 +<polygon fill="none" stroke="black" points="1540.83,-302.4 1082.57,-302.4 1082.57,-266.4 1540.83,-266.4 1540.83,-302.4"/>
144 +<text text-anchor="middle" x="1311.7" y="-280.2" font-family="Times,serif" font-size="14.00">v8 (mutable b$4 @ mutable b$4 = Call mutable compute$3(frozen props$1.b))</text>
145 +</g>
146 +<!-- v9 -->
147 +<g id="node10" class="node">
148 +<title>v9</title>
149 +<polygon fill="none" stroke="black" points="1515.96,-213.6 1177.44,-213.6 1177.44,-177.6 1515.96,-177.6 1515.96,-213.6"/>
150 +<text text-anchor="middle" x="1346.7" y="-191.4" font-family="Times,serif" font-size="14.00">v9 (mutable b$4 @ Call mutable mutate$5(mutable b$4))</text>
151 +</g>
152 +<!-- v8&#45;&gt;v9 -->
153 +<g id="edge6" class="edge">
154 +<title>v8&#45;&gt;v9</title>
155 +<path fill="none" stroke="black" d="M1318.62,-266.25C1323.55,-254.01 1330.29,-237.29 1335.93,-223.31"/>
156 +<polygon fill="black" stroke="black" points="1339.31,-224.3 1339.8,-213.71 1332.81,-221.68 1339.31,-224.3"/>
157 +</g>
158 +<!-- v10 -->
159 +<g id="node11" class="node">
160 +<title>v10</title>
161 +<polygon fill="none" stroke="black" points="1365.85,-124.8 797.55,-124.8 797.55,-88.8 1365.85,-88.8 1365.85,-124.8"/>
162 +<text text-anchor="middle" x="1081.7" y="-102.6" font-family="Times,serif" font-size="14.00">v10 (readonly b$4 @ JSX &lt;frozen Foo$6 a={readonly a$2} b={readonly b$4} &gt;&lt;/frozen Foo$6&gt;)</text>
163 +</g>
164 +<!-- v8&#45;&gt;v10 -->
165 +<g id="edge7" class="edge">
166 +<title>v8&#45;&gt;v10</title>
167 +<path fill="none" stroke="black" d="M1264.36,-266.31C1235.01,-254.32 1197.54,-236.37 1168.7,-213.6 1139.74,-190.73 1113.92,-156.71 1098.08,-133.46"/>
168 +<polygon fill="black" stroke="black" points="1100.97,-131.5 1092.51,-125.13 1095.15,-135.39 1100.97,-131.5"/>
169 +</g>
170 +<!-- v9&#45;&gt;v9 -->
171 +<g id="edge12" class="edge">
172 +<title>v9&#45;&gt;v9</title>
173 +<path fill="none" stroke="black" d="M1516.19,-201.54C1527.33,-200.16 1534.08,-198.18 1534.08,-195.6 1534.08,-193.95 1531.31,-192.54 1526.39,-191.38"/>
174 +<polygon fill="black" stroke="black" points="1526.63,-187.87 1516.19,-189.66 1525.47,-194.77 1526.63,-187.87"/>
175 +</g>
176 +<!-- v9&#45;&gt;v10 -->
177 +<g id="edge13" class="edge">
178 +<title>v9&#45;&gt;v10</title>
179 +<path fill="none" stroke="black" d="M1294.66,-177.55C1251.18,-163.31 1189.09,-142.97 1143.16,-127.93"/>
180 +<polygon fill="black" stroke="black" points="1144.21,-124.59 1133.62,-124.81 1142.03,-131.25 1144.21,-124.59"/>
181 +</g>
182 +<!-- v10&#45;&gt;v14 -->
183 +<g id="edge16" class="edge">
184 +<title>v10&#45;&gt;v14</title>
185 +<path fill="none" stroke="black" d="M1029.19,-124.81C985.25,-139.04 922.46,-159.37 875.99,-174.43"/>
186 +<polygon fill="black" stroke="black" points="874.76,-171.14 866.33,-177.55 876.92,-177.8 874.76,-171.14"/>
187 +<text text-anchor="middle" x="993.3" y="-147" font-family="Times,serif" font-size="14.00">capture</text>
188 +</g>
189 +<!-- v10&#45;&gt;v15 -->
190 +<g id="edge20" class="edge">
191 +<title>v10&#45;&gt;v15</title>
192 +<path fill="none" stroke="black" d="M1020.43,-88.75C968.81,-74.39 894.91,-53.83 840.71,-38.76"/>
193 +<polygon fill="black" stroke="black" points="841.4,-35.31 830.83,-36.01 839.52,-42.06 841.4,-35.31"/>
194 +<text text-anchor="middle" x="974.3" y="-58.2" font-family="Times,serif" font-size="14.00">capture</text>
195 +</g>
196 +<!-- v12 -->
197 +<g id="node13" class="node">
198 +<title>v12</title>
199 +<polygon fill="none" stroke="black" points="1801.77,-448.4 1425.63,-448.4 1425.63,-412.4 1801.77,-412.4 1801.77,-448.4"/>
200 +<text text-anchor="middle" x="1613.7" y="-426.2" font-family="Times,serif" font-size="14.00">v12 (mutable mutate$5 @ Call mutable mutate$5(mutable a$2))</text>
201 +</g>
202 +<!-- v13 -->
203 +<g id="node14" class="node">
204 +<title>v13</title>
205 +<polygon fill="none" stroke="black" points="1802.06,-375.4 1425.34,-375.4 1425.34,-339.4 1802.06,-339.4 1802.06,-375.4"/>
206 +<text text-anchor="middle" x="1613.7" y="-353.2" font-family="Times,serif" font-size="14.00">v13 (mutable mutate$5 @ Call mutable mutate$5(mutable b$4))</text>
207 +</g>
208 +<!-- v12&#45;&gt;v13 -->
209 +<g id="edge9" class="edge">
210 +<title>v12&#45;&gt;v13</title>
211 +<path fill="none" stroke="black" d="M1613.7,-412.21C1613.7,-404.19 1613.7,-394.45 1613.7,-385.47"/>
212 +<polygon fill="black" stroke="black" points="1617.2,-385.43 1613.7,-375.43 1610.2,-385.43 1617.2,-385.43"/>
213 +</g>
214 +<!-- v14&#45;&gt;v4 -->
215 +<g id="edge17" class="edge">
216 +<title>v14&#45;&gt;v4</title>
217 +<path fill="none" stroke="black" d="M808.63,-214C805,-224.6 799.39,-238.05 791.7,-248.4 788.81,-252.29 785.4,-256.02 781.8,-259.5"/>
218 +<polygon fill="black" stroke="black" points="779.35,-256.99 774.23,-266.27 784.02,-262.21 779.35,-256.99"/>
219 +<text text-anchor="middle" x="822.3" y="-235.8" font-family="Times,serif" font-size="14.00">capture</text>
220 +</g>
221 +<!-- v14&#45;&gt;v10 -->
222 +<g id="edge18" class="edge">
223 +<title>v14&#45;&gt;v10</title>
224 +<path fill="none" stroke="black" d="M830.23,-177.42C842.46,-165.78 860.11,-151.07 878.51,-142.8 892.1,-136.69 906.64,-131.64 921.47,-127.47"/>
225 +<polygon fill="black" stroke="black" points="922.49,-130.82 931.25,-124.86 920.69,-124.06 922.49,-130.82"/>
226 +<text text-anchor="middle" x="899.3" y="-147" font-family="Times,serif" font-size="14.00">capture</text>
227 +</g>
228 +<!-- v14&#45;&gt;v15 -->
229 +<g id="edge14" class="edge">
230 +<title>v14&#45;&gt;v15</title>
231 +<path fill="none" stroke="black" d="M806.62,-177.36C801.1,-163.38 793.58,-143.08 788.7,-124.8 781.66,-98.42 776.46,-67.64 773.3,-46.11"/>
232 +<polygon fill="black" stroke="black" points="776.74,-45.46 771.87,-36.05 769.81,-46.44 776.74,-45.46"/>
233 +</g>
234 +<!-- v16 -->
235 +<g id="node17" class="node">
236 +<title>v16</title>
237 +<polygon fill="none" stroke="black" points="2389.4,-448.4 1820,-448.4 1820,-412.4 2389.4,-412.4 2389.4,-448.4"/>
238 +<text text-anchor="middle" x="2104.7" y="-426.2" font-family="Times,serif" font-size="14.00">v16 (frozen Foo$6 @ JSX &lt;frozen Foo$6 a={readonly a$2} b={readonly b$4} &gt;&lt;/frozen Foo$6&gt;)</text>
239 +</g>
240 +</g>
241 +</svg>
compiler/forget/src/__tests__/fixtures/hir-svg/independent.svg new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4 +<!-- Generated by graphviz version 6.0.1 (20220924.0800)
5 + -->
6 +<!-- Title: InferMutability Pages: 1 -->
7 +<svg width="8pt" height="8pt"
8 + viewBox="0.00 0.00 8.00 8.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9 +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 4)">
10 +<title>InferMutability</title>
11 +<polygon fill="white" stroke="none" points="-4,4 -4,-4 4,-4 4,4 -4,4"/>
12 +</g>
13 +</svg>
compiler/forget/src/__tests__/fixtures/hir-svg/interdependent-across-if.svg new
+243
@@ -0,0 +1,243 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4 +<!-- Generated by graphviz version 6.0.1 (20220924.0800)
5 + -->
6 +<!-- Title: InferMutability Pages: 1 -->
7 +<svg width="3121pt" height="472pt"
8 + viewBox="0.00 0.00 3120.55 472.20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9 +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 468.2)">
10 +<title>InferMutability</title>
11 +<polygon fill="white" stroke="none" points="-4,4 -4,-468.2 3116.55,-468.2 3116.55,4 -4,4"/>
12 +<!-- v0 -->
13 +<g id="node1" class="node">
14 +<title>v0</title>
15 +<polygon fill="none" stroke="black" points="303.12,-464.2 96.28,-464.2 96.28,-428.2 303.12,-428.2 303.12,-464.2"/>
16 +<text text-anchor="middle" x="199.7" y="-442" font-family="Times,serif" font-size="14.00">v0 (frozen props$1 @ &lt;no&#45;instr&gt;)</text>
17 +</g>
18 +<!-- v1 -->
19 +<g id="node2" class="node">
20 +<title>v1</title>
21 +<polygon fill="none" stroke="black" points="398.53,-391.2 0.87,-391.2 0.87,-355.2 398.53,-355.2 398.53,-391.2"/>
22 +<text text-anchor="middle" x="199.7" y="-369" font-family="Times,serif" font-size="14.00">v1 (frozen props$1.a @ Call mutable compute$3(frozen props$1.a))</text>
23 +</g>
24 +<!-- v0&#45;&gt;v1 -->
25 +<g id="edge1" class="edge">
26 +<title>v0&#45;&gt;v1</title>
27 +<path fill="none" stroke="black" d="M199.7,-428.01C199.7,-419.99 199.7,-410.25 199.7,-401.27"/>
28 +<polygon fill="black" stroke="black" points="203.2,-401.23 199.7,-391.23 196.2,-401.23 203.2,-401.23"/>
29 +</g>
30 +<!-- v7 -->
31 +<g id="node8" class="node">
32 +<title>v7</title>
33 +<polygon fill="none" stroke="black" points="399.6,-302.4 -0.2,-302.4 -0.2,-266.4 399.6,-266.4 399.6,-302.4"/>
34 +<text text-anchor="middle" x="199.7" y="-280.2" font-family="Times,serif" font-size="14.00">v7 (frozen props$1.b @ Call mutable compute$3(frozen props$1.b))</text>
35 +</g>
36 +<!-- v1&#45;&gt;v7 -->
37 +<g id="edge5" class="edge">
38 +<title>v1&#45;&gt;v7</title>
39 +<path fill="none" stroke="black" d="M199.7,-355.05C199.7,-342.92 199.7,-326.42 199.7,-312.52"/>
40 +<polygon fill="black" stroke="black" points="203.2,-312.51 199.7,-302.51 196.2,-312.51 203.2,-312.51"/>
41 +</g>
42 +<!-- v2 -->
43 +<g id="node3" class="node">
44 +<title>v2</title>
45 +<polygon fill="none" stroke="black" points="981.97,-464.2 525.43,-464.2 525.43,-428.2 981.97,-428.2 981.97,-464.2"/>
46 +<text text-anchor="middle" x="753.7" y="-442" font-family="Times,serif" font-size="14.00">v2 (mutable a$2 @ mutable a$2 = Call mutable compute$3(frozen props$1.a))</text>
47 +</g>
48 +<!-- v3 -->
49 +<g id="node4" class="node">
50 +<title>v3</title>
51 +<polygon fill="none" stroke="black" points="1140.05,-391.2 745.35,-391.2 745.35,-355.2 1140.05,-355.2 1140.05,-391.2"/>
52 +<text text-anchor="middle" x="942.7" y="-369" font-family="Times,serif" font-size="14.00">v3 (mutable a$2 @ Call mutable foo$5(mutable a$2, mutable b$4))</text>
53 +</g>
54 +<!-- v2&#45;&gt;v3 -->
55 +<g id="edge2" class="edge">
56 +<title>v2&#45;&gt;v3</title>
57 +<path fill="none" stroke="black" d="M798.97,-428.19C825.54,-418.21 859.32,-405.52 887.45,-394.96"/>
58 +<polygon fill="black" stroke="black" points="889.01,-398.11 897.14,-391.31 886.55,-391.55 889.01,-398.11"/>
59 +</g>
60 +<!-- v4 -->
61 +<g id="node5" class="node">
62 +<title>v4</title>
63 +<polygon fill="none" stroke="black" points="978.06,-302.4 417.34,-302.4 417.34,-266.4 978.06,-266.4 978.06,-302.4"/>
64 +<text text-anchor="middle" x="697.7" y="-280.2" font-family="Times,serif" font-size="14.00">v4 (readonly a$2 @ JSX &lt;frozen Foo$6 a={readonly a$2} b={readonly b$4} &gt;&lt;/frozen Foo$6&gt;)</text>
65 +</g>
66 +<!-- v2&#45;&gt;v4 -->
67 +<g id="edge3" class="edge">
68 +<title>v2&#45;&gt;v4</title>
69 +<path fill="none" stroke="black" d="M747.71,-428.1C737.99,-400.37 718.72,-345.39 707.15,-312.35"/>
70 +<polygon fill="black" stroke="black" points="710.43,-311.14 703.82,-302.86 703.82,-313.46 710.43,-311.14"/>
71 +</g>
72 +<!-- v3&#45;&gt;v3 -->
73 +<g id="edge9" class="edge">
74 +<title>v3&#45;&gt;v3</title>
75 +<path fill="none" stroke="black" d="M1140.14,-377.82C1151.25,-376.7 1157.87,-375.16 1157.87,-373.2 1157.87,-371.94 1155.16,-370.86 1150.28,-369.95"/>
76 +<polygon fill="black" stroke="black" points="1150.52,-366.45 1140.14,-368.58 1149.59,-373.39 1150.52,-366.45"/>
77 +</g>
78 +<!-- v3&#45;&gt;v4 -->
79 +<g id="edge10" class="edge">
80 +<title>v3&#45;&gt;v4</title>
81 +<path fill="none" stroke="black" d="M894.59,-355.15C854.64,-341 797.7,-320.83 755.33,-305.82"/>
82 +<polygon fill="black" stroke="black" points="756.3,-302.45 745.7,-302.41 753.96,-309.04 756.3,-302.45"/>
83 +</g>
84 +<!-- v9 -->
85 +<g id="node10" class="node">
86 +<title>v9</title>
87 +<polygon fill="none" stroke="black" points="1391.33,-302.4 996.07,-302.4 996.07,-266.4 1391.33,-266.4 1391.33,-302.4"/>
88 +<text text-anchor="middle" x="1193.7" y="-280.2" font-family="Times,serif" font-size="14.00">v9 (mutable b$4 @ Call mutable foo$5(mutable a$2, mutable b$4))</text>
89 +</g>
90 +<!-- v3&#45;&gt;v9 -->
91 +<g id="edge14" class="edge">
92 +<title>v3&#45;&gt;v9</title>
93 +<path fill="none" stroke="black" d="M1057.39,-355.2C1076.9,-350.52 1096.67,-344.62 1114.7,-337.2 1132.16,-330.01 1149.89,-318.82 1164.12,-308.67"/>
94 +<polygon fill="black" stroke="black" points="1166.49,-311.27 1172.49,-302.53 1162.35,-305.62 1166.49,-311.27"/>
95 +<text text-anchor="middle" x="1165.3" y="-324.6" font-family="Times,serif" font-size="14.00">capture</text>
96 +</g>
97 +<!-- v13 -->
98 +<g id="node14" class="node">
99 +<title>v13</title>
100 +<polygon fill="none" stroke="black" points="1165.77,-213.6 549.63,-213.6 549.63,-177.6 1165.77,-177.6 1165.77,-213.6"/>
101 +<text text-anchor="middle" x="857.7" y="-191.4" font-family="Times,serif" font-size="14.00">v13 (frozen $7 @ frozen $7 = JSX &lt;frozen Foo$6 a={readonly a$2} b={readonly b$4} &gt;&lt;/frozen Foo$6&gt;)</text>
102 +</g>
103 +<!-- v4&#45;&gt;v13 -->
104 +<g id="edge16" class="edge">
105 +<title>v4&#45;&gt;v13</title>
106 +<path fill="none" stroke="black" d="M718.8,-266.35C732.89,-255.5 752.13,-241.64 770.51,-231.6 779.73,-226.56 789.83,-221.84 799.78,-217.6"/>
107 +<polygon fill="black" stroke="black" points="801.34,-220.74 809.25,-213.69 798.67,-214.28 801.34,-220.74"/>
108 +<text text-anchor="middle" x="791.3" y="-235.8" font-family="Times,serif" font-size="14.00">capture</text>
109 +</g>
110 +<!-- v14 -->
111 +<g id="node15" class="node">
112 +<title>v14</title>
113 +<polygon fill="none" stroke="black" points="922.52,-36 704.88,-36 704.88,0 922.52,0 922.52,-36"/>
114 +<text text-anchor="middle" x="813.7" y="-13.8" font-family="Times,serif" font-size="14.00">v14 (frozen $7 @ Return frozen $7)</text>
115 +</g>
116 +<!-- v4&#45;&gt;v14 -->
117 +<g id="edge20" class="edge">
118 +<title>v4&#45;&gt;v14</title>
119 +<path fill="none" stroke="black" d="M627.9,-266.4C575.21,-249.79 515.9,-220.69 540.7,-177.6 583.03,-104.06 673.99,-61.46 739.29,-39.28"/>
120 +<polygon fill="black" stroke="black" points="740.74,-42.49 749.13,-36.02 738.54,-35.84 740.74,-42.49"/>
121 +<text text-anchor="middle" x="586.3" y="-147" font-family="Times,serif" font-size="14.00">capture</text>
122 +</g>
123 +<!-- v5 -->
124 +<g id="node6" class="node">
125 +<title>v5</title>
126 +<polygon fill="none" stroke="black" points="2092.76,-464.2 1678.64,-464.2 1678.64,-428.2 2092.76,-428.2 2092.76,-464.2"/>
127 +<text text-anchor="middle" x="1885.7" y="-442" font-family="Times,serif" font-size="14.00">v5 (mutable compute$3 @ Call mutable compute$3(frozen props$1.a))</text>
128 +</g>
129 +<!-- v6 -->
130 +<g id="node7" class="node">
131 +<title>v6</title>
132 +<polygon fill="none" stroke="black" points="2093.54,-391.2 1677.86,-391.2 1677.86,-355.2 2093.54,-355.2 2093.54,-391.2"/>
133 +<text text-anchor="middle" x="1885.7" y="-369" font-family="Times,serif" font-size="14.00">v6 (mutable compute$3 @ Call mutable compute$3(frozen props$1.b))</text>
134 +</g>
135 +<!-- v5&#45;&gt;v6 -->
136 +<g id="edge4" class="edge">
137 +<title>v5&#45;&gt;v6</title>
138 +<path fill="none" stroke="black" d="M1885.7,-428.01C1885.7,-419.99 1885.7,-410.25 1885.7,-401.27"/>
139 +<polygon fill="black" stroke="black" points="1889.2,-401.23 1885.7,-391.23 1882.2,-401.23 1889.2,-401.23"/>
140 +</g>
141 +<!-- v11 -->
142 +<g id="node12" class="node">
143 +<title>v11</title>
144 +<polygon fill="none" stroke="black" points="390.87,-213.6 8.53,-213.6 8.53,-177.6 390.87,-177.6 390.87,-213.6"/>
145 +<text text-anchor="middle" x="199.7" y="-191.4" font-family="Times,serif" font-size="14.00">v11 (frozen props$1.c @ If (frozen props$1.c) then:bb2 else:bb1)</text>
146 +</g>
147 +<!-- v7&#45;&gt;v11 -->
148 +<g id="edge8" class="edge">
149 +<title>v7&#45;&gt;v11</title>
150 +<path fill="none" stroke="black" d="M199.7,-266.25C199.7,-254.12 199.7,-237.62 199.7,-223.72"/>
151 +<polygon fill="black" stroke="black" points="203.2,-223.71 199.7,-213.71 196.2,-223.71 203.2,-223.71"/>
152 +</g>
153 +<!-- v8 -->
154 +<g id="node9" class="node">
155 +<title>v8</title>
156 +<polygon fill="none" stroke="black" points="1659.83,-391.2 1201.57,-391.2 1201.57,-355.2 1659.83,-355.2 1659.83,-391.2"/>
157 +<text text-anchor="middle" x="1430.7" y="-369" font-family="Times,serif" font-size="14.00">v8 (mutable b$4 @ mutable b$4 = Call mutable compute$3(frozen props$1.b))</text>
158 +</g>
159 +<!-- v8&#45;&gt;v9 -->
160 +<g id="edge6" class="edge">
161 +<title>v8&#45;&gt;v9</title>
162 +<path fill="none" stroke="black" d="M1384.16,-355.15C1345.6,-341.03 1290.67,-320.91 1249.7,-305.91"/>
163 +<polygon fill="black" stroke="black" points="1250.73,-302.56 1240.13,-302.41 1248.32,-309.13 1250.73,-302.56"/>
164 +</g>
165 +<!-- v10 -->
166 +<g id="node11" class="node">
167 +<title>v10</title>
168 +<polygon fill="none" stroke="black" points="1409.85,-124.8 841.55,-124.8 841.55,-88.8 1409.85,-88.8 1409.85,-124.8"/>
169 +<text text-anchor="middle" x="1125.7" y="-102.6" font-family="Times,serif" font-size="14.00">v10 (readonly b$4 @ JSX &lt;frozen Foo$6 a={readonly a$2} b={readonly b$4} &gt;&lt;/frozen Foo$6&gt;)</text>
170 +</g>
171 +<!-- v8&#45;&gt;v10 -->
172 +<g id="edge7" class="edge">
173 +<title>v8&#45;&gt;v10</title>
174 +<path fill="none" stroke="black" d="M1433.29,-355.18C1435.76,-332.81 1436.8,-293.21 1418.7,-266.4 1368.73,-192.38 1272.45,-149.95 1203.9,-127.93"/>
175 +<polygon fill="black" stroke="black" points="1204.58,-124.48 1194,-124.83 1202.49,-131.16 1204.58,-124.48"/>
176 +</g>
177 +<!-- v9&#45;&gt;v3 -->
178 +<g id="edge11" class="edge">
179 +<title>v9&#45;&gt;v3</title>
180 +<path fill="none" stroke="black" d="M1130.97,-302.46C1112.36,-307.85 1092.01,-314.06 1073.51,-320.4 1046.38,-329.7 1016.62,-341.36 992.35,-351.27"/>
181 +<polygon fill="black" stroke="black" points="990.91,-348.08 982.99,-355.11 993.57,-354.55 990.91,-348.08"/>
182 +<text text-anchor="middle" x="1094.3" y="-324.6" font-family="Times,serif" font-size="14.00">capture</text>
183 +</g>
184 +<!-- v9&#45;&gt;v9 -->
185 +<g id="edge12" class="edge">
186 +<title>v9&#45;&gt;v9</title>
187 +<path fill="none" stroke="black" d="M1391.51,-290.02C1402.63,-288.66 1409.27,-286.78 1409.27,-284.4 1409.27,-282.87 1406.55,-281.55 1401.66,-280.45"/>
188 +<polygon fill="black" stroke="black" points="1401.94,-276.95 1391.51,-278.78 1400.81,-283.85 1401.94,-276.95"/>
189 +</g>
190 +<!-- v9&#45;&gt;v10 -->
191 +<g id="edge13" class="edge">
192 +<title>v9&#45;&gt;v10</title>
193 +<path fill="none" stroke="black" d="M1192.89,-266.27C1191.38,-244.8 1187.05,-207.23 1174.7,-177.6 1168.04,-161.61 1157.23,-145.66 1147.46,-133.05"/>
194 +<polygon fill="black" stroke="black" points="1149.91,-130.5 1140.92,-124.89 1144.44,-134.88 1149.91,-130.5"/>
195 +</g>
196 +<!-- v10&#45;&gt;v13 -->
197 +<g id="edge17" class="edge">
198 +<title>v10&#45;&gt;v13</title>
199 +<path fill="none" stroke="black" d="M1066.84,-124.87C1048.14,-130.43 1027.41,-136.73 1008.51,-142.8 977.62,-152.71 943.41,-164.4 915.39,-174.17"/>
200 +<polygon fill="black" stroke="black" points="914.04,-170.93 905.76,-177.54 916.35,-177.54 914.04,-170.93"/>
201 +<text text-anchor="middle" x="1029.3" y="-147" font-family="Times,serif" font-size="14.00">capture</text>
202 +</g>
203 +<!-- v10&#45;&gt;v14 -->
204 +<g id="edge21" class="edge">
205 +<title>v10&#45;&gt;v14</title>
206 +<path fill="none" stroke="black" d="M1064.43,-88.75C1012.81,-74.39 938.91,-53.83 884.71,-38.76"/>
207 +<polygon fill="black" stroke="black" points="885.4,-35.31 874.83,-36.01 883.52,-42.06 885.4,-35.31"/>
208 +<text text-anchor="middle" x="1018.3" y="-58.2" font-family="Times,serif" font-size="14.00">capture</text>
209 +</g>
210 +<!-- v12 -->
211 +<g id="node13" class="node">
212 +<title>v12</title>
213 +<polygon fill="none" stroke="black" points="2524.5,-464.2 2110.9,-464.2 2110.9,-428.2 2524.5,-428.2 2524.5,-464.2"/>
214 +<text text-anchor="middle" x="2317.7" y="-442" font-family="Times,serif" font-size="14.00">v12 (mutable foo$5 @ Call mutable foo$5(mutable a$2, mutable b$4))</text>
215 +</g>
216 +<!-- v13&#45;&gt;v4 -->
217 +<g id="edge18" class="edge">
218 +<title>v13&#45;&gt;v4</title>
219 +<path fill="none" stroke="black" d="M846.29,-213.75C837.94,-225.07 825.66,-239.43 811.7,-248.4 802.99,-254 793.33,-258.75 783.43,-262.76"/>
220 +<polygon fill="black" stroke="black" points="781.98,-259.56 773.88,-266.39 784.47,-266.11 781.98,-259.56"/>
221 +<text text-anchor="middle" x="851.3" y="-235.8" font-family="Times,serif" font-size="14.00">capture</text>
222 +</g>
223 +<!-- v13&#45;&gt;v10 -->
224 +<g id="edge19" class="edge">
225 +<title>v13&#45;&gt;v10</title>
226 +<path fill="none" stroke="black" d="M991.97,-177.56C1011.72,-172.93 1031.52,-167.06 1049.7,-159.6 1066.83,-152.57 1084.03,-141.29 1097.73,-131.04"/>
227 +<polygon fill="black" stroke="black" points="1099.98,-133.72 1105.77,-124.84 1095.71,-128.17 1099.98,-133.72"/>
228 +<text text-anchor="middle" x="1102.3" y="-147" font-family="Times,serif" font-size="14.00">capture</text>
229 +</g>
230 +<!-- v13&#45;&gt;v14 -->
231 +<g id="edge15" class="edge">
232 +<title>v13&#45;&gt;v14</title>
233 +<path fill="none" stroke="black" d="M850.62,-177.36C845.1,-163.38 837.58,-143.08 832.7,-124.8 825.66,-98.42 820.46,-67.64 817.3,-46.11"/>
234 +<polygon fill="black" stroke="black" points="820.74,-45.46 815.87,-36.05 813.81,-46.44 820.74,-45.46"/>
235 +</g>
236 +<!-- v15 -->
237 +<g id="node16" class="node">
238 +<title>v15</title>
239 +<polygon fill="none" stroke="black" points="3112.4,-464.2 2543,-464.2 2543,-428.2 3112.4,-428.2 3112.4,-464.2"/>
240 +<text text-anchor="middle" x="2827.7" y="-442" font-family="Times,serif" font-size="14.00">v15 (frozen Foo$6 @ JSX &lt;frozen Foo$6 a={readonly a$2} b={readonly b$4} &gt;&lt;/frozen Foo$6&gt;)</text>
241 +</g>
242 +</g>
243 +</svg>
compiler/forget/src/__tests__/fixtures/hir-svg/interdependent.svg new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4 +<!-- Generated by graphviz version 6.0.1 (20220924.0800)
5 + -->
6 +<!-- Title: InferMutability Pages: 1 -->
7 +<svg width="8pt" height="8pt"
8 + viewBox="0.00 0.00 8.00 8.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9 +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 4)">
10 +<title>InferMutability</title>
11 +<polygon fill="white" stroke="none" points="-4,4 -4,-4 4,-4 4,4 -4,4"/>
12 +</g>
13 +</svg>
compiler/forget/src/__tests__/fixtures/hir-svg/property-assignment.svg new
+255
@@ -0,0 +1,255 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4 +<!-- Generated by graphviz version 6.0.1 (20220924.0800)
5 + -->
6 +<!-- Title: InferMutability Pages: 1 -->
7 +<svg width="1847pt" height="707pt"
8 + viewBox="0.00 0.00 1847.27 707.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9 +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 703)">
10 +<title>InferMutability</title>
11 +<polygon fill="white" stroke="none" points="-4,4 -4,-703 1843.27,-703 1843.27,4 -4,4"/>
12 +<!-- v0 -->
13 +<g id="node1" class="node">
14 +<title>v0</title>
15 +<polygon fill="none" stroke="black" points="392.28,-699 185.44,-699 185.44,-663 392.28,-663 392.28,-699"/>
16 +<text text-anchor="middle" x="288.86" y="-676.8" font-family="Times,serif" font-size="14.00">v0 (frozen props$1 @ &lt;no&#45;instr&gt;)</text>
17 +</g>
18 +<!-- v1 -->
19 +<g id="node2" class="node">
20 +<title>v1</title>
21 +<polygon fill="none" stroke="black" points="495,-626 82.72,-626 82.72,-590 495,-590 495,-626"/>
22 +<text text-anchor="middle" x="288.86" y="-603.8" font-family="Times,serif" font-size="14.00">v1 (frozen props$1.p0 @ Call mutable x$2.y.push(frozen props$1.p0))</text>
23 +</g>
24 +<!-- v0&#45;&gt;v1 -->
25 +<g id="edge1" class="edge">
26 +<title>v0&#45;&gt;v1</title>
27 +<path fill="none" stroke="black" d="M288.86,-662.81C288.86,-654.79 288.86,-645.05 288.86,-636.07"/>
28 +<polygon fill="black" stroke="black" points="292.36,-636.03 288.86,-626.03 285.36,-636.03 292.36,-636.03"/>
29 +</g>
30 +<!-- v2 -->
31 +<g id="node3" class="node">
32 +<title>v2</title>
33 +<polygon fill="none" stroke="black" points="1085.92,-699 807.8,-699 807.8,-663 1085.92,-663 1085.92,-699"/>
34 +<text text-anchor="middle" x="946.86" y="-676.8" font-family="Times,serif" font-size="14.00">v2 (mutable x$2 @ mutable x$2 = Object { &#160;})</text>
35 +</g>
36 +<!-- v3 -->
37 +<g id="node4" class="node">
38 +<title>v3</title>
39 +<polygon fill="none" stroke="black" points="1100.76,-626 792.96,-626 792.96,-590 1100.76,-590 1100.76,-626"/>
40 +<text text-anchor="middle" x="946.86" y="-603.8" font-family="Times,serif" font-size="14.00">v3 (mutable x$2.y @ mutable x$2.y = mutable y$3)</text>
41 +</g>
42 +<!-- v2&#45;&gt;v3 -->
43 +<g id="edge2" class="edge">
44 +<title>v2&#45;&gt;v3</title>
45 +<path fill="none" stroke="black" d="M946.86,-662.81C946.86,-654.79 946.86,-645.05 946.86,-636.07"/>
46 +<polygon fill="black" stroke="black" points="950.36,-636.03 946.86,-626.03 943.36,-636.03 950.36,-636.03"/>
47 +</g>
48 +<!-- v5 -->
49 +<g id="node6" class="node">
50 +<title>v5</title>
51 +<polygon fill="none" stroke="black" points="910.77,-537.2 708.95,-537.2 708.95,-501.2 910.77,-501.2 910.77,-537.2"/>
52 +<text text-anchor="middle" x="809.86" y="-515" font-family="Times,serif" font-size="14.00">v5 (mutable y$3 @ mutable y$3)</text>
53 +</g>
54 +<!-- v3&#45;&gt;v5 -->
55 +<g id="edge7" class="edge">
56 +<title>v3&#45;&gt;v5</title>
57 +<path fill="none" stroke="black" d="M846.19,-589.85C837.08,-585.2 828.67,-579.35 821.66,-572 815.45,-565.47 812.25,-556.38 810.69,-547.63"/>
58 +<polygon fill="black" stroke="black" points="814.16,-547.21 809.51,-537.69 807.21,-548.03 814.16,-547.21"/>
59 +<text text-anchor="middle" x="842.45" y="-559.4" font-family="Times,serif" font-size="14.00">capture</text>
60 +</g>
61 +<!-- v6 -->
62 +<g id="node7" class="node">
63 +<title>v6</title>
64 +<polygon fill="none" stroke="black" points="1451.18,-375.4 1030.53,-375.4 1030.53,-339.4 1451.18,-339.4 1451.18,-375.4"/>
65 +<text text-anchor="middle" x="1240.86" y="-353.2" font-family="Times,serif" font-size="14.00">v6 (mutable x$2.y.push @ Call mutable x$2.y.push(frozen props$1.p0))</text>
66 +</g>
67 +<!-- v3&#45;&gt;v6 -->
68 +<g id="edge4" class="edge">
69 +<title>v3&#45;&gt;v6</title>
70 +<path fill="none" stroke="black" d="M967.07,-589.91C1018.36,-546.54 1153.72,-432.08 1212.71,-382.2"/>
71 +<polygon fill="black" stroke="black" points="1215.13,-384.74 1220.51,-375.61 1210.61,-379.39 1215.13,-384.74"/>
72 +</g>
73 +<!-- v7 -->
74 +<g id="node8" class="node">
75 +<title>v7</title>
76 +<polygon fill="none" stroke="black" points="1086.4,-464.2 533.31,-464.2 533.31,-428.2 1086.4,-428.2 1086.4,-464.2"/>
77 +<text text-anchor="middle" x="809.86" y="-442" font-family="Times,serif" font-size="14.00">v7 (mutable y$3 @ JSX &lt;frozen Component$0 data={mutable y$3} &gt;&lt;/frozen Component$0&gt;)</text>
78 +</g>
79 +<!-- v3&#45;&gt;v7 -->
80 +<g id="edge11" class="edge">
81 +<title>v3&#45;&gt;v7</title>
82 +<path fill="none" stroke="black" d="M946.74,-589.66C945.71,-566.94 940.77,-526.95 919.86,-501.2 908.53,-487.26 892.71,-476.64 876.6,-468.67"/>
83 +<polygon fill="black" stroke="black" points="877.65,-465.3 867.1,-464.27 874.71,-471.65 877.65,-465.3"/>
84 +<text text-anchor="middle" x="958.45" y="-515" font-family="Times,serif" font-size="14.00">capture</text>
85 +</g>
86 +<!-- v4 -->
87 +<g id="node5" class="node">
88 +<title>v4</title>
89 +<polygon fill="none" stroke="black" points="775.14,-626 512.58,-626 512.58,-590 775.14,-590 775.14,-626"/>
90 +<text text-anchor="middle" x="643.86" y="-603.8" font-family="Times,serif" font-size="14.00">v4 (mutable y$3 @ mutable y$3 = Array [])</text>
91 +</g>
92 +<!-- v4&#45;&gt;v5 -->
93 +<g id="edge3" class="edge">
94 +<title>v4&#45;&gt;v5</title>
95 +<path fill="none" stroke="black" d="M676.65,-589.85C702.91,-576.12 739.91,-556.77 768.26,-541.95"/>
96 +<polygon fill="black" stroke="black" points="769.89,-545.05 777.13,-537.31 766.65,-538.85 769.89,-545.05"/>
97 +</g>
98 +<!-- v5&#45;&gt;v3 -->
99 +<g id="edge5" class="edge">
100 +<title>v5&#45;&gt;v3</title>
101 +<path fill="none" stroke="black" d="M836.87,-537.31C858.15,-550.8 888.01,-569.71 911.24,-584.43"/>
102 +<polygon fill="black" stroke="black" points="909.47,-587.46 919.79,-589.85 913.22,-581.54 909.47,-587.46"/>
103 +<text text-anchor="middle" x="911.45" y="-559.4" font-family="Times,serif" font-size="14.00">capture</text>
104 +</g>
105 +<!-- v5&#45;&gt;v7 -->
106 +<g id="edge6" class="edge">
107 +<title>v5&#45;&gt;v7</title>
108 +<path fill="none" stroke="black" d="M809.86,-501.01C809.86,-492.99 809.86,-483.25 809.86,-474.27"/>
109 +<polygon fill="black" stroke="black" points="813.36,-474.23 809.86,-464.23 806.36,-474.23 813.36,-474.23"/>
110 +</g>
111 +<!-- v12 -->
112 +<g id="node13" class="node">
113 +<title>v12</title>
114 +<polygon fill="none" stroke="black" points="1381.58,-302.4 706.14,-302.4 706.14,-266.4 1381.58,-266.4 1381.58,-302.4"/>
115 +<text text-anchor="middle" x="1043.86" y="-280.2" font-family="Times,serif" font-size="14.00">v12 (readonly x$2 @ JSX &lt;frozen Component$0 data={readonly x$2} &gt;{readonly child$4}&lt;/frozen Component$0&gt;)</text>
116 +</g>
117 +<!-- v6&#45;&gt;v12 -->
118 +<g id="edge13" class="edge">
119 +<title>v6&#45;&gt;v12</title>
120 +<path fill="none" stroke="black" d="M1193.67,-339.39C1165.85,-329.37 1130.46,-316.61 1101.06,-306.02"/>
121 +<polygon fill="black" stroke="black" points="1101.94,-302.61 1091.34,-302.51 1099.56,-309.2 1101.94,-302.61"/>
122 +</g>
123 +<!-- v7&#45;&gt;v6 -->
124 +<g id="edge14" class="edge">
125 +<title>v7&#45;&gt;v6</title>
126 +<path fill="none" stroke="black" d="M895.31,-428.15C923.8,-422.45 955.7,-416.07 984.86,-410.2 1038.61,-399.39 1098.7,-387.23 1147.15,-377.41"/>
127 +<polygon fill="black" stroke="black" points="1147.88,-380.84 1156.99,-375.42 1146.49,-373.98 1147.88,-380.84"/>
128 +<text text-anchor="middle" x="1083.45" y="-397.6" font-family="Times,serif" font-size="14.00">capture</text>
129 +</g>
130 +<!-- v8 -->
131 +<g id="node9" class="node">
132 +<title>v8</title>
133 +<polygon fill="none" stroke="black" points="934.38,-375.4 255.33,-375.4 255.33,-339.4 934.38,-339.4 934.38,-375.4"/>
134 +<text text-anchor="middle" x="594.86" y="-353.2" font-family="Times,serif" font-size="14.00">v8 (mutable child$4 @ mutable child$4 = JSX &lt;frozen Component$0 data={mutable y$3} &gt;&lt;/frozen Component$0&gt;)</text>
135 +</g>
136 +<!-- v7&#45;&gt;v8 -->
137 +<g id="edge9" class="edge">
138 +<title>v7&#45;&gt;v8</title>
139 +<path fill="none" stroke="black" d="M783.65,-428.02C765.92,-416.97 741.67,-402.94 718.86,-393.4 705.44,-387.79 690.85,-382.77 676.54,-378.4"/>
140 +<polygon fill="black" stroke="black" points="677.27,-374.97 666.69,-375.49 675.28,-381.68 677.27,-374.97"/>
141 +<text text-anchor="middle" x="773.45" y="-397.6" font-family="Times,serif" font-size="14.00">capture</text>
142 +</g>
143 +<!-- v9 -->
144 +<g id="node10" class="node">
145 +<title>v9</title>
146 +<polygon fill="none" stroke="black" points="689.57,-124.8 0.14,-124.8 0.14,-88.8 689.57,-88.8 689.57,-124.8"/>
147 +<text text-anchor="middle" x="344.86" y="-102.6" font-family="Times,serif" font-size="14.00">v9 (readonly child$4 @ JSX &lt;frozen Component$0 data={readonly x$2} &gt;{readonly child$4}&lt;/frozen Component$0&gt;)</text>
148 +</g>
149 +<!-- v7&#45;&gt;v9 -->
150 +<g id="edge20" class="edge">
151 +<title>v7&#45;&gt;v9</title>
152 +<path fill="none" stroke="black" d="M538.41,-428.17C386.29,-414.81 226.86,-392.65 226.86,-358.4 226.86,-358.4 226.86,-358.4 226.86,-194.6 226.86,-163.98 252.95,-142.97 280.6,-129.29"/>
153 +<polygon fill="black" stroke="black" points="282.4,-132.31 290,-124.93 279.46,-125.96 282.4,-132.31"/>
154 +<text text-anchor="middle" x="247.45" y="-280.2" font-family="Times,serif" font-size="14.00">capture</text>
155 +</g>
156 +<!-- v7&#45;&gt;v12 -->
157 +<g id="edge18" class="edge">
158 +<title>v7&#45;&gt;v12</title>
159 +<path fill="none" stroke="black" d="M849.74,-428.2C877.37,-415.54 914.34,-396.8 943.86,-375.4 962.38,-361.97 963.78,-354.84 980.66,-339.4 991.81,-329.21 1004.39,-318.33 1015.39,-309.03"/>
160 +<polygon fill="black" stroke="black" points="1017.67,-311.68 1023.06,-302.57 1013.16,-306.33 1017.67,-311.68"/>
161 +<text text-anchor="middle" x="1001.45" y="-353.2" font-family="Times,serif" font-size="14.00">capture</text>
162 +</g>
163 +<!-- v8&#45;&gt;v7 -->
164 +<g id="edge12" class="edge">
165 +<title>v8&#45;&gt;v7</title>
166 +<path fill="none" stroke="black" d="M616.48,-375.44C631.72,-386.72 653,-401.06 673.66,-410.2 686.91,-416.06 701.32,-421.08 715.66,-425.34"/>
167 +<polygon fill="black" stroke="black" points="714.98,-428.79 725.56,-428.17 716.9,-422.06 714.98,-428.79"/>
168 +<text text-anchor="middle" x="694.45" y="-397.6" font-family="Times,serif" font-size="14.00">capture</text>
169 +</g>
170 +<!-- v8&#45;&gt;v9 -->
171 +<g id="edge8" class="edge">
172 +<title>v8&#45;&gt;v9</title>
173 +<path fill="none" stroke="black" d="M577.67,-339.31C534.23,-296.11 419.9,-182.42 369.41,-132.22"/>
174 +<polygon fill="black" stroke="black" points="371.72,-129.58 362.16,-125.01 366.78,-134.54 371.72,-129.58"/>
175 +</g>
176 +<!-- v13 -->
177 +<g id="node14" class="node">
178 +<title>v13</title>
179 +<polygon fill="none" stroke="black" points="1469.5,-213.6 746.22,-213.6 746.22,-177.6 1469.5,-177.6 1469.5,-213.6"/>
180 +<text text-anchor="middle" x="1107.86" y="-191.4" font-family="Times,serif" font-size="14.00">v13 (frozen $5 @ frozen $5 = JSX &lt;frozen Component$0 data={readonly x$2} &gt;{readonly child$4}&lt;/frozen Component$0&gt;)</text>
181 +</g>
182 +<!-- v9&#45;&gt;v13 -->
183 +<g id="edge17" class="edge">
184 +<title>v9&#45;&gt;v13</title>
185 +<path fill="none" stroke="black" d="M580.57,-124.82C640.13,-129.87 703.91,-135.91 762.86,-142.8 840.96,-151.92 928.59,-165.12 995.98,-175.9"/>
186 +<polygon fill="black" stroke="black" points="995.77,-179.42 1006.19,-177.55 996.88,-172.5 995.77,-179.42"/>
187 +<text text-anchor="middle" x="907.45" y="-147" font-family="Times,serif" font-size="14.00">capture</text>
188 +</g>
189 +<!-- v14 -->
190 +<g id="node15" class="node">
191 +<title>v14</title>
192 +<polygon fill="none" stroke="black" points="826.68,-36 609.03,-36 609.03,0 826.68,0 826.68,-36"/>
193 +<text text-anchor="middle" x="717.86" y="-13.8" font-family="Times,serif" font-size="14.00">v14 (frozen $5 @ Return frozen $5)</text>
194 +</g>
195 +<!-- v9&#45;&gt;v14 -->
196 +<g id="edge23" class="edge">
197 +<title>v9&#45;&gt;v14</title>
198 +<path fill="none" stroke="black" d="M418.11,-88.75C480.46,-74.24 570.01,-53.41 634.97,-38.29"/>
199 +<polygon fill="black" stroke="black" points="635.83,-41.68 644.78,-36.01 634.24,-34.86 635.83,-41.68"/>
200 +<text text-anchor="middle" x="585.45" y="-58.2" font-family="Times,serif" font-size="14.00">capture</text>
201 +</g>
202 +<!-- v10 -->
203 +<g id="node11" class="node">
204 +<title>v10</title>
205 +<polygon fill="none" stroke="black" points="1783.39,-699 1174.33,-699 1174.33,-663 1783.39,-663 1783.39,-699"/>
206 +<text text-anchor="middle" x="1478.86" y="-676.8" font-family="Times,serif" font-size="14.00">v10 (frozen Component$0 @ JSX &lt;frozen Component$0 data={mutable y$3} &gt;&lt;/frozen Component$0&gt;)</text>
207 +</g>
208 +<!-- v11 -->
209 +<g id="node12" class="node">
210 +<title>v11</title>
211 +<polygon fill="none" stroke="black" points="1839.18,-626 1118.53,-626 1118.53,-590 1839.18,-590 1839.18,-626"/>
212 +<text text-anchor="middle" x="1478.86" y="-603.8" font-family="Times,serif" font-size="14.00">v11 (frozen Component$0 @ JSX &lt;frozen Component$0 data={readonly x$2} &gt;{readonly child$4}&lt;/frozen Component$0&gt;)</text>
213 +</g>
214 +<!-- v10&#45;&gt;v11 -->
215 +<g id="edge10" class="edge">
216 +<title>v10&#45;&gt;v11</title>
217 +<path fill="none" stroke="black" d="M1478.86,-662.81C1478.86,-654.79 1478.86,-645.05 1478.86,-636.07"/>
218 +<polygon fill="black" stroke="black" points="1482.36,-636.03 1478.86,-626.03 1475.36,-636.03 1482.36,-636.03"/>
219 +</g>
220 +<!-- v12&#45;&gt;v13 -->
221 +<g id="edge16" class="edge">
222 +<title>v12&#45;&gt;v13</title>
223 +<path fill="none" stroke="black" d="M1040.01,-266.36C1038.53,-255.64 1038.47,-241.94 1044.66,-231.6 1047.34,-227.14 1050.8,-223.21 1054.73,-219.75"/>
224 +<polygon fill="black" stroke="black" points="1056.91,-222.5 1062.77,-213.67 1052.68,-216.91 1056.91,-222.5"/>
225 +<text text-anchor="middle" x="1065.45" y="-235.8" font-family="Times,serif" font-size="14.00">capture</text>
226 +</g>
227 +<!-- v12&#45;&gt;v14 -->
228 +<g id="edge22" class="edge">
229 +<title>v12&#45;&gt;v14</title>
230 +<path fill="none" stroke="black" d="M912.44,-266.33C841.56,-254.69 763.32,-237.11 736.86,-213.6 689.95,-171.93 700.88,-88.98 710.57,-46.09"/>
231 +<polygon fill="black" stroke="black" points="714.04,-46.64 712.98,-36.1 707.23,-45 714.04,-46.64"/>
232 +<text text-anchor="middle" x="727.45" y="-147" font-family="Times,serif" font-size="14.00">capture</text>
233 +</g>
234 +<!-- v13&#45;&gt;v9 -->
235 +<g id="edge21" class="edge">
236 +<title>v13&#45;&gt;v9</title>
237 +<path fill="none" stroke="black" d="M1060.74,-177.56C1025.69,-165.67 976.41,-150.58 931.86,-142.8 857.39,-129.79 776.88,-121.38 700.07,-116"/>
238 +<polygon fill="black" stroke="black" points="699.96,-112.48 689.75,-115.29 699.48,-119.47 699.96,-112.48"/>
239 +<text text-anchor="middle" x="1021.45" y="-147" font-family="Times,serif" font-size="14.00">capture</text>
240 +</g>
241 +<!-- v13&#45;&gt;v12 -->
242 +<g id="edge19" class="edge">
243 +<title>v13&#45;&gt;v12</title>
244 +<path fill="none" stroke="black" d="M1102.79,-214C1099.16,-224.6 1093.55,-238.05 1085.86,-248.4 1082.97,-252.29 1079.56,-256.02 1075.96,-259.5"/>
245 +<polygon fill="black" stroke="black" points="1073.51,-256.99 1068.38,-266.27 1078.17,-262.21 1073.51,-256.99"/>
246 +<text text-anchor="middle" x="1116.45" y="-235.8" font-family="Times,serif" font-size="14.00">capture</text>
247 +</g>
248 +<!-- v13&#45;&gt;v14 -->
249 +<g id="edge15" class="edge">
250 +<title>v13&#45;&gt;v14</title>
251 +<path fill="none" stroke="black" d="M1090.62,-177.46C1078.8,-166.44 1062.33,-152.42 1045.86,-142.8 963.82,-94.9 859.9,-59.39 791.27,-38.97"/>
252 +<polygon fill="black" stroke="black" points="791.99,-35.53 781.41,-36.07 790.01,-42.25 791.99,-35.53"/>
253 +</g>
254 +</g>
255 +</svg>
compiler/forget/src/__tests__/fixtures/hir-svg/reassignment-conditional.svg new
+298
@@ -0,0 +1,298 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4 +<!-- Generated by graphviz version 6.0.1 (20220924.0800)
5 + -->
6 +<!-- Title: InferMutability Pages: 1 -->
7 +<svg width="1555pt" height="796pt"
8 + viewBox="0.00 0.00 1555.03 795.80" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9 +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 791.8)">
10 +<title>InferMutability</title>
11 +<polygon fill="white" stroke="none" points="-4,4 -4,-791.8 1551.03,-791.8 1551.03,4 -4,4"/>
12 +<!-- v0 -->
13 +<g id="node1" class="node">
14 +<title>v0</title>
15 +<polygon fill="none" stroke="black" points="304.49,-787.8 97.65,-787.8 97.65,-751.8 304.49,-751.8 304.49,-787.8"/>
16 +<text text-anchor="middle" x="201.07" y="-765.6" font-family="Times,serif" font-size="14.00">v0 (frozen props$1 @ &lt;no&#45;instr&gt;)</text>
17 +</g>
18 +<!-- v1 -->
19 +<g id="node2" class="node">
20 +<title>v1</title>
21 +<polygon fill="none" stroke="black" points="402.21,-714.8 -0.07,-714.8 -0.07,-678.8 402.21,-678.8 402.21,-714.8"/>
22 +<text text-anchor="middle" x="201.07" y="-692.6" font-family="Times,serif" font-size="14.00">v1 (frozen props$1.p0 @ Call mutable x$2.push(frozen props$1.p0))</text>
23 +</g>
24 +<!-- v0&#45;&gt;v1 -->
25 +<g id="edge1" class="edge">
26 +<title>v0&#45;&gt;v1</title>
27 +<path fill="none" stroke="black" d="M201.07,-751.61C201.07,-743.59 201.07,-733.85 201.07,-724.87"/>
28 +<polygon fill="black" stroke="black" points="204.57,-724.83 201.07,-714.83 197.57,-724.83 204.57,-724.83"/>
29 +</g>
30 +<!-- v5 -->
31 +<g id="node6" class="node">
32 +<title>v5</title>
33 +<polygon fill="none" stroke="black" points="396.81,-641.8 5.33,-641.8 5.33,-605.8 396.81,-605.8 396.81,-641.8"/>
34 +<text text-anchor="middle" x="201.07" y="-619.6" font-family="Times,serif" font-size="14.00">v5 (frozen props$1.p1 @ If (frozen props$1.p1) then:bb2 else:bb1)</text>
35 +</g>
36 +<!-- v1&#45;&gt;v5 -->
37 +<g id="edge4" class="edge">
38 +<title>v1&#45;&gt;v5</title>
39 +<path fill="none" stroke="black" d="M201.07,-678.61C201.07,-670.59 201.07,-660.85 201.07,-651.87"/>
40 +<polygon fill="black" stroke="black" points="204.57,-651.83 201.07,-641.83 197.57,-651.83 204.57,-651.83"/>
41 +</g>
42 +<!-- v2 -->
43 +<g id="node3" class="node">
44 +<title>v2</title>
45 +<polygon fill="none" stroke="black" points="758.35,-787.8 495.79,-787.8 495.79,-751.8 758.35,-751.8 758.35,-787.8"/>
46 +<text text-anchor="middle" x="627.07" y="-765.6" font-family="Times,serif" font-size="14.00">v2 (mutable x$2 @ mutable x$2 = Array [])</text>
47 +</g>
48 +<!-- v3 -->
49 +<g id="node4" class="node">
50 +<title>v3</title>
51 +<polygon fill="none" stroke="black" points="826.9,-714.8 427.25,-714.8 427.25,-678.8 826.9,-678.8 826.9,-714.8"/>
52 +<text text-anchor="middle" x="627.07" y="-692.6" font-family="Times,serif" font-size="14.00">v3 (mutable x$2.push @ Call mutable x$2.push(frozen props$1.p0))</text>
53 +</g>
54 +<!-- v2&#45;&gt;v3 -->
55 +<g id="edge2" class="edge">
56 +<title>v2&#45;&gt;v3</title>
57 +<path fill="none" stroke="black" d="M627.07,-751.61C627.07,-743.59 627.07,-733.85 627.07,-724.87"/>
58 +<polygon fill="black" stroke="black" points="630.57,-724.83 627.07,-714.83 623.57,-724.83 630.57,-724.83"/>
59 +</g>
60 +<!-- v4 -->
61 +<g id="node5" class="node">
62 +<title>v4</title>
63 +<polygon fill="none" stroke="black" points="727.98,-641.8 526.16,-641.8 526.16,-605.8 727.98,-605.8 727.98,-641.8"/>
64 +<text text-anchor="middle" x="627.07" y="-619.6" font-family="Times,serif" font-size="14.00">v4 (mutable x$2 @ mutable x$2)</text>
65 +</g>
66 +<!-- v3&#45;&gt;v4 -->
67 +<g id="edge3" class="edge">
68 +<title>v3&#45;&gt;v4</title>
69 +<path fill="none" stroke="black" d="M627.07,-678.61C627.07,-670.59 627.07,-660.85 627.07,-651.87"/>
70 +<polygon fill="black" stroke="black" points="630.57,-651.83 627.07,-641.83 623.57,-651.83 630.57,-651.83"/>
71 +</g>
72 +<!-- v6 -->
73 +<g id="node7" class="node">
74 +<title>v6</title>
75 +<polygon fill="none" stroke="black" points="706.47,-553 419.67,-553 419.67,-517 706.47,-517 706.47,-553"/>
76 +<text text-anchor="middle" x="563.07" y="-530.8" font-family="Times,serif" font-size="14.00">v6 (mutable y$3 @ mutable y$3 = mutable x$2)</text>
77 +</g>
78 +<!-- v4&#45;&gt;v6 -->
79 +<g id="edge6" class="edge">
80 +<title>v4&#45;&gt;v6</title>
81 +<path fill="none" stroke="black" d="M622,-605.4C618.37,-594.8 612.76,-581.35 605.07,-571 602.18,-567.11 598.77,-563.38 595.17,-559.9"/>
82 +<polygon fill="black" stroke="black" points="597.39,-557.19 587.6,-553.13 592.72,-562.41 597.39,-557.19"/>
83 +<text text-anchor="middle" x="635.67" y="-575.2" font-family="Times,serif" font-size="14.00">capture</text>
84 +</g>
85 +<!-- v8 -->
86 +<g id="node9" class="node">
87 +<title>v8</title>
88 +<polygon fill="none" stroke="black" points="1127.3,-464.2 590.84,-464.2 590.84,-428.2 1127.3,-428.2 1127.3,-464.2"/>
89 +<text text-anchor="middle" x="859.07" y="-442" font-family="Times,serif" font-size="14.00">v8 (mutable x$2 @ JSX &lt;frozen Component$0 x={mutable x$2} &gt;&lt;/frozen Component$0&gt;)</text>
90 +</g>
91 +<!-- v4&#45;&gt;v8 -->
92 +<g id="edge7" class="edge">
93 +<title>v4&#45;&gt;v8</title>
94 +<path fill="none" stroke="black" d="M728.02,-618.2C827.25,-611.32 968.69,-594.35 1003.07,-553 1033.07,-516.92 977.35,-486.54 926.73,-467.72"/>
95 +<polygon fill="black" stroke="black" points="927.63,-464.32 917.04,-464.23 925.26,-470.91 927.63,-464.32"/>
96 +</g>
97 +<!-- v9 -->
98 +<g id="node10" class="node">
99 +<title>v9</title>
100 +<polygon fill="none" stroke="black" points="402.21,-553 -0.07,-553 -0.07,-517 402.21,-517 402.21,-553"/>
101 +<text text-anchor="middle" x="201.07" y="-530.8" font-family="Times,serif" font-size="14.00">v9 (frozen props$1.p2 @ Call mutable y$3.push(frozen props$1.p2))</text>
102 +</g>
103 +<!-- v5&#45;&gt;v9 -->
104 +<g id="edge9" class="edge">
105 +<title>v5&#45;&gt;v9</title>
106 +<path fill="none" stroke="black" d="M201.07,-605.65C201.07,-593.52 201.07,-577.02 201.07,-563.12"/>
107 +<polygon fill="black" stroke="black" points="204.57,-563.11 201.07,-553.11 197.57,-563.11 204.57,-563.11"/>
108 +</g>
109 +<!-- v6&#45;&gt;v4 -->
110 +<g id="edge8" class="edge">
111 +<title>v6&#45;&gt;v4</title>
112 +<path fill="none" stroke="black" d="M557.32,-553.05C554.78,-563.77 553.62,-577.48 559.88,-587.8 562.58,-592.25 566.05,-596.17 570,-599.6"/>
113 +<polygon fill="black" stroke="black" points="567.97,-602.46 578.08,-605.63 572.16,-596.85 567.97,-602.46"/>
114 +<text text-anchor="middle" x="580.67" y="-575.2" font-family="Times,serif" font-size="14.00">capture</text>
115 +</g>
116 +<!-- v7 -->
117 +<g id="node8" class="node">
118 +<title>v7</title>
119 +<polygon fill="none" stroke="black" points="762.9,-375.4 363.25,-375.4 363.25,-339.4 762.9,-339.4 762.9,-375.4"/>
120 +<text text-anchor="middle" x="563.07" y="-353.2" font-family="Times,serif" font-size="14.00">v7 (mutable y$3.push @ Call mutable y$3.push(frozen props$1.p2))</text>
121 +</g>
122 +<!-- v6&#45;&gt;v7 -->
123 +<g id="edge5" class="edge">
124 +<title>v6&#45;&gt;v7</title>
125 +<path fill="none" stroke="black" d="M563.07,-516.84C563.07,-486.42 563.07,-422.78 563.07,-386.08"/>
126 +<polygon fill="black" stroke="black" points="566.57,-385.63 563.07,-375.63 559.57,-385.63 566.57,-385.63"/>
127 +</g>
128 +<!-- v6&#45;&gt;v8 -->
129 +<g id="edge14" class="edge">
130 +<title>v6&#45;&gt;v8</title>
131 +<path fill="none" stroke="black" d="M621.2,-516.95C670.07,-502.62 739.99,-482.12 791.38,-467.05"/>
132 +<polygon fill="black" stroke="black" points="792.47,-470.38 801.08,-464.21 790.5,-463.66 792.47,-470.38"/>
133 +<text text-anchor="middle" x="758.67" y="-486.4" font-family="Times,serif" font-size="14.00">capture</text>
134 +</g>
135 +<!-- v14 -->
136 +<g id="node15" class="node">
137 +<title>v14</title>
138 +<polygon fill="none" stroke="black" points="1160.38,-286.6 503.76,-286.6 503.76,-250.6 1160.38,-250.6 1160.38,-286.6"/>
139 +<text text-anchor="middle" x="832.07" y="-264.4" font-family="Times,serif" font-size="14.00">v14 (readonly x$2 @ JSX &lt;frozen Component$0 x={readonly x$2} y={readonly y$3} &gt;&lt;/frozen Component$0&gt;)</text>
140 +</g>
141 +<!-- v7&#45;&gt;v14 -->
142 +<g id="edge21" class="edge">
143 +<title>v7&#45;&gt;v14</title>
144 +<path fill="none" stroke="black" d="M615.9,-339.35C660.04,-325.11 723.06,-304.77 769.68,-289.73"/>
145 +<polygon fill="black" stroke="black" points="770.92,-293.01 779.37,-286.61 768.78,-286.35 770.92,-293.01"/>
146 +<text text-anchor="middle" x="742.67" y="-308.8" font-family="Times,serif" font-size="14.00">capture</text>
147 +</g>
148 +<!-- v15 -->
149 +<g id="node16" class="node">
150 +<title>v15</title>
151 +<polygon fill="none" stroke="black" points="796.38,-197.8 139.76,-197.8 139.76,-161.8 796.38,-161.8 796.38,-197.8"/>
152 +<text text-anchor="middle" x="468.07" y="-175.6" font-family="Times,serif" font-size="14.00">v15 (readonly y$3 @ JSX &lt;frozen Component$0 x={readonly x$2} y={readonly y$3} &gt;&lt;/frozen Component$0&gt;)</text>
153 +</g>
154 +<!-- v7&#45;&gt;v15 -->
155 +<g id="edge16" class="edge">
156 +<title>v7&#45;&gt;v15</title>
157 +<path fill="none" stroke="black" d="M541.3,-339.39C526.18,-326.47 506.74,-307.41 495.07,-286.6 481.29,-262.02 474.41,-230.31 471.06,-208.03"/>
158 +<polygon fill="black" stroke="black" points="474.5,-207.37 469.69,-197.93 467.57,-208.31 474.5,-207.37"/>
159 +</g>
160 +<!-- v8&#45;&gt;v7 -->
161 +<g id="edge17" class="edge">
162 +<title>v8&#45;&gt;v7</title>
163 +<path fill="none" stroke="black" d="M798.55,-428.19C778.58,-422.53 756.26,-416.15 735.88,-410.2 700.46,-399.86 661.04,-388.07 628.81,-378.35"/>
164 +<polygon fill="black" stroke="black" points="629.63,-374.94 619.04,-375.4 627.61,-381.64 629.63,-374.94"/>
165 +<text text-anchor="middle" x="756.67" y="-397.6" font-family="Times,serif" font-size="14.00">capture</text>
166 +</g>
167 +<!-- v11 -->
168 +<g id="node12" class="node">
169 +<title>v11</title>
170 +<polygon fill="none" stroke="black" points="1447.29,-375.4 818.85,-375.4 818.85,-339.4 1447.29,-339.4 1447.29,-375.4"/>
171 +<text text-anchor="middle" x="1133.07" y="-353.2" font-family="Times,serif" font-size="14.00">v11 (mutable _$4 @ mutable _$4 = JSX &lt;frozen Component$0 x={mutable x$2} &gt;&lt;/frozen Component$0&gt;)</text>
172 +</g>
173 +<!-- v8&#45;&gt;v11 -->
174 +<g id="edge11" class="edge">
175 +<title>v8&#45;&gt;v11</title>
176 +<path fill="none" stroke="black" d="M912.88,-428.15C957.93,-413.88 1022.31,-393.49 1069.82,-378.44"/>
177 +<polygon fill="black" stroke="black" points="1070.91,-381.76 1079.39,-375.41 1068.8,-375.09 1070.91,-381.76"/>
178 +<text text-anchor="middle" x="1041.67" y="-397.6" font-family="Times,serif" font-size="14.00">capture</text>
179 +</g>
180 +<!-- v8&#45;&gt;v14 -->
181 +<g id="edge13" class="edge">
182 +<title>v8&#45;&gt;v14</title>
183 +<path fill="none" stroke="black" d="M842.34,-427.93C830.79,-414.73 816.41,-395.45 810.07,-375.4 801.69,-348.87 810.4,-317.58 819.21,-295.94"/>
184 +<polygon fill="black" stroke="black" points="822.44,-297.3 823.21,-286.73 816.02,-294.51 822.44,-297.3"/>
185 +</g>
186 +<!-- v10 -->
187 +<g id="node11" class="node">
188 +<title>v10</title>
189 +<polygon fill="none" stroke="black" points="993.85,-553 724.29,-553 724.29,-517 993.85,-517 993.85,-553"/>
190 +<text text-anchor="middle" x="859.07" y="-530.8" font-family="Times,serif" font-size="14.00">v10 (mutable x$2 @ mutable x$2 = Array [])</text>
191 +</g>
192 +<!-- v10&#45;&gt;v8 -->
193 +<g id="edge10" class="edge">
194 +<title>v10&#45;&gt;v8</title>
195 +<path fill="none" stroke="black" d="M859.07,-516.85C859.07,-504.72 859.07,-488.22 859.07,-474.32"/>
196 +<polygon fill="black" stroke="black" points="862.57,-474.31 859.07,-464.31 855.57,-474.31 862.57,-474.31"/>
197 +</g>
198 +<!-- v11&#45;&gt;v8 -->
199 +<g id="edge15" class="edge">
200 +<title>v11&#45;&gt;v8</title>
201 +<path fill="none" stroke="black" d="M981.38,-375.44C962.62,-380.07 944.03,-385.94 926.88,-393.4 911.42,-400.12 896.32,-411.1 884.3,-421.22"/>
202 +<polygon fill="black" stroke="black" points="881.73,-418.81 876.51,-428.03 886.34,-424.08 881.73,-418.81"/>
203 +<text text-anchor="middle" x="947.67" y="-397.6" font-family="Times,serif" font-size="14.00">capture</text>
204 +</g>
205 +<!-- v11&#45;&gt;v14 -->
206 +<g id="edge22" class="edge">
207 +<title>v11&#45;&gt;v14</title>
208 +<path fill="none" stroke="black" d="M1073.96,-339.35C1024.26,-325.02 953.16,-304.52 900.9,-289.45"/>
209 +<polygon fill="black" stroke="black" points="901.62,-286.01 891.04,-286.61 899.68,-292.74 901.62,-286.01"/>
210 +<text text-anchor="middle" x="1030.67" y="-308.8" font-family="Times,serif" font-size="14.00">capture</text>
211 +</g>
212 +<!-- v12 -->
213 +<g id="node13" class="node">
214 +<title>v12</title>
215 +<polygon fill="none" stroke="black" points="1492.28,-787.8 899.86,-787.8 899.86,-751.8 1492.28,-751.8 1492.28,-787.8"/>
216 +<text text-anchor="middle" x="1196.07" y="-765.6" font-family="Times,serif" font-size="14.00">v12 (frozen Component$0 @ JSX &lt;frozen Component$0 x={mutable x$2} &gt;&lt;/frozen Component$0&gt;)</text>
217 +</g>
218 +<!-- v13 -->
219 +<g id="node14" class="node">
220 +<title>v13</title>
221 +<polygon fill="none" stroke="black" points="1546.98,-714.8 845.16,-714.8 845.16,-678.8 1546.98,-678.8 1546.98,-714.8"/>
222 +<text text-anchor="middle" x="1196.07" y="-692.6" font-family="Times,serif" font-size="14.00">v13 (frozen Component$0 @ JSX &lt;frozen Component$0 x={readonly x$2} y={readonly y$3} &gt;&lt;/frozen Component$0&gt;)</text>
223 +</g>
224 +<!-- v12&#45;&gt;v13 -->
225 +<g id="edge12" class="edge">
226 +<title>v12&#45;&gt;v13</title>
227 +<path fill="none" stroke="black" d="M1196.07,-751.61C1196.07,-743.59 1196.07,-733.85 1196.07,-724.87"/>
228 +<polygon fill="black" stroke="black" points="1199.57,-724.83 1196.07,-714.83 1192.57,-724.83 1199.57,-724.83"/>
229 +</g>
230 +<!-- v14&#45;&gt;v15 -->
231 +<g id="edge24" class="edge">
232 +<title>v14&#45;&gt;v15</title>
233 +<path fill="none" stroke="black" d="M760.59,-250.55C699.86,-236.07 612.71,-215.29 549.35,-200.18"/>
234 +<polygon fill="black" stroke="black" points="549.93,-196.72 539.39,-197.81 548.3,-203.53 549.93,-196.72"/>
235 +<text text-anchor="middle" x="703.67" y="-220" font-family="Times,serif" font-size="14.00">capture</text>
236 +</g>
237 +<!-- v16 -->
238 +<g id="node17" class="node">
239 +<title>v16</title>
240 +<polygon fill="none" stroke="black" points="1039.3,-109 334.84,-109 334.84,-73 1039.3,-73 1039.3,-109"/>
241 +<text text-anchor="middle" x="687.07" y="-86.8" font-family="Times,serif" font-size="14.00">v16 (frozen $5 @ frozen $5 = JSX &lt;frozen Component$0 x={readonly x$2} y={readonly y$3} &gt;&lt;/frozen Component$0&gt;)</text>
242 +</g>
243 +<!-- v14&#45;&gt;v16 -->
244 +<g id="edge19" class="edge">
245 +<title>v14&#45;&gt;v16</title>
246 +<path fill="none" stroke="black" d="M831.65,-250.5C830.28,-228.04 824.97,-188.34 805.07,-161.8 789.2,-140.63 764.86,-124.68 742.39,-113.41"/>
247 +<polygon fill="black" stroke="black" points="743.77,-110.19 733.24,-109.02 740.74,-116.5 743.77,-110.19"/>
248 +<text text-anchor="middle" x="843.67" y="-175.6" font-family="Times,serif" font-size="14.00">capture</text>
249 +</g>
250 +<!-- v17 -->
251 +<g id="node18" class="node">
252 +<title>v17</title>
253 +<polygon fill="none" stroke="black" points="795.9,-36 578.25,-36 578.25,0 795.9,0 795.9,-36"/>
254 +<text text-anchor="middle" x="687.07" y="-13.8" font-family="Times,serif" font-size="14.00">v17 (frozen $5 @ Return frozen $5)</text>
255 +</g>
256 +<!-- v14&#45;&gt;v17 -->
257 +<g id="edge26" class="edge">
258 +<title>v14&#45;&gt;v17</title>
259 +<path fill="none" stroke="black" d="M878.63,-250.59C959.39,-218.6 1111.08,-146.13 1048.07,-73 1017.14,-37.1 899.15,-24.72 806.37,-20.62"/>
260 +<polygon fill="black" stroke="black" points="806.47,-17.13 796.34,-20.21 806.18,-24.12 806.47,-17.13"/>
261 +<text text-anchor="middle" x="1079.67" y="-131.2" font-family="Times,serif" font-size="14.00">capture</text>
262 +</g>
263 +<!-- v15&#45;&gt;v16 -->
264 +<g id="edge20" class="edge">
265 +<title>v15&#45;&gt;v16</title>
266 +<path fill="none" stroke="black" d="M523.5,-161.78C539.92,-156.4 557.84,-150.18 574.07,-143.8 597.24,-134.7 622.47,-123.28 643.2,-113.49"/>
267 +<polygon fill="black" stroke="black" points="644.86,-116.57 652.38,-109.11 641.85,-110.25 644.86,-116.57"/>
268 +<text text-anchor="middle" x="632.67" y="-131.2" font-family="Times,serif" font-size="14.00">capture</text>
269 +</g>
270 +<!-- v15&#45;&gt;v17 -->
271 +<g id="edge27" class="edge">
272 +<title>v15&#45;&gt;v17</title>
273 +<path fill="none" stroke="black" d="M385,-161.74C320.54,-144.83 247.88,-115.3 284.88,-73 303.45,-51.77 456.22,-35.97 567.99,-27.11"/>
274 +<polygon fill="black" stroke="black" points="568.3,-30.6 577.99,-26.33 567.75,-23.62 568.3,-30.6"/>
275 +<text text-anchor="middle" x="305.67" y="-86.8" font-family="Times,serif" font-size="14.00">capture</text>
276 +</g>
277 +<!-- v16&#45;&gt;v14 -->
278 +<g id="edge23" class="edge">
279 +<title>v16&#45;&gt;v14</title>
280 +<path fill="none" stroke="black" d="M794.14,-109.13C823.25,-119.38 851.33,-135.73 868.07,-161.8 884.08,-186.74 868.17,-219.58 852.74,-242.01"/>
281 +<polygon fill="black" stroke="black" points="849.72,-240.2 846.69,-250.35 855.39,-244.31 849.72,-240.2"/>
282 +<text text-anchor="middle" x="895.67" y="-175.6" font-family="Times,serif" font-size="14.00">capture</text>
283 +</g>
284 +<!-- v16&#45;&gt;v15 -->
285 +<g id="edge25" class="edge">
286 +<title>v16&#45;&gt;v15</title>
287 +<path fill="none" stroke="black" d="M577.03,-109.03C560.43,-113.66 543.86,-119.55 528.88,-127 515.09,-133.86 501.82,-144.52 491.22,-154.38"/>
288 +<polygon fill="black" stroke="black" points="488.75,-151.9 484,-161.36 493.62,-156.93 488.75,-151.9"/>
289 +<text text-anchor="middle" x="549.67" y="-131.2" font-family="Times,serif" font-size="14.00">capture</text>
290 +</g>
291 +<!-- v16&#45;&gt;v17 -->
292 +<g id="edge18" class="edge">
293 +<title>v16&#45;&gt;v17</title>
294 +<path fill="none" stroke="black" d="M687.07,-72.81C687.07,-64.79 687.07,-55.05 687.07,-46.07"/>
295 +<polygon fill="black" stroke="black" points="690.57,-46.03 687.07,-36.03 683.57,-46.03 690.57,-46.03"/>
296 +</g>
297 +</g>
298 +</svg>
compiler/forget/src/__tests__/fixtures/hir-svg/reassignment.svg new
+252
@@ -0,0 +1,252 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4 +<!-- Generated by graphviz version 6.0.1 (20220924.0800)
5 + -->
6 +<!-- Title: InferMutability Pages: 1 -->
7 +<svg width="1965pt" height="691pt"
8 + viewBox="0.00 0.00 1965.36 691.20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9 +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 687.2)">
10 +<title>InferMutability</title>
11 +<polygon fill="white" stroke="none" points="-4,4 -4,-687.2 1961.36,-687.2 1961.36,4 -4,4"/>
12 +<!-- v0 -->
13 +<g id="node1" class="node">
14 +<title>v0</title>
15 +<polygon fill="none" stroke="black" points="735.44,-683.2 528.6,-683.2 528.6,-647.2 735.44,-647.2 735.44,-683.2"/>
16 +<text text-anchor="middle" x="632.02" y="-661" font-family="Times,serif" font-size="14.00">v0 (frozen props$1 @ &lt;no&#45;instr&gt;)</text>
17 +</g>
18 +<!-- v1 -->
19 +<g id="node2" class="node">
20 +<title>v1</title>
21 +<polygon fill="none" stroke="black" points="833.16,-610.2 430.88,-610.2 430.88,-574.2 833.16,-574.2 833.16,-610.2"/>
22 +<text text-anchor="middle" x="632.02" y="-588" font-family="Times,serif" font-size="14.00">v1 (frozen props$1.p0 @ Call mutable x$2.push(frozen props$1.p0))</text>
23 +</g>
24 +<!-- v0&#45;&gt;v1 -->
25 +<g id="edge1" class="edge">
26 +<title>v0&#45;&gt;v1</title>
27 +<path fill="none" stroke="black" d="M632.02,-647.01C632.02,-638.99 632.02,-629.25 632.02,-620.27"/>
28 +<polygon fill="black" stroke="black" points="635.52,-620.23 632.02,-610.23 628.52,-620.23 635.52,-620.23"/>
29 +</g>
30 +<!-- v5 -->
31 +<g id="node6" class="node">
32 +<title>v5</title>
33 +<polygon fill="none" stroke="black" points="833.16,-537.2 430.88,-537.2 430.88,-501.2 833.16,-501.2 833.16,-537.2"/>
34 +<text text-anchor="middle" x="632.02" y="-515" font-family="Times,serif" font-size="14.00">v5 (frozen props$1.p1 @ Call mutable y$3.push(frozen props$1.p1))</text>
35 +</g>
36 +<!-- v1&#45;&gt;v5 -->
37 +<g id="edge4" class="edge">
38 +<title>v1&#45;&gt;v5</title>
39 +<path fill="none" stroke="black" d="M632.02,-574.01C632.02,-565.99 632.02,-556.25 632.02,-547.27"/>
40 +<polygon fill="black" stroke="black" points="635.52,-547.23 632.02,-537.23 628.52,-547.23 635.52,-547.23"/>
41 +</g>
42 +<!-- v2 -->
43 +<g id="node3" class="node">
44 +<title>v2</title>
45 +<polygon fill="none" stroke="black" points="1182.3,-683.2 919.74,-683.2 919.74,-647.2 1182.3,-647.2 1182.3,-683.2"/>
46 +<text text-anchor="middle" x="1051.02" y="-661" font-family="Times,serif" font-size="14.00">v2 (mutable x$2 @ mutable x$2 = Array [])</text>
47 +</g>
48 +<!-- v3 -->
49 +<g id="node4" class="node">
50 +<title>v3</title>
51 +<polygon fill="none" stroke="black" points="1250.84,-610.2 851.19,-610.2 851.19,-574.2 1250.84,-574.2 1250.84,-610.2"/>
52 +<text text-anchor="middle" x="1051.02" y="-588" font-family="Times,serif" font-size="14.00">v3 (mutable x$2.push @ Call mutable x$2.push(frozen props$1.p0))</text>
53 +</g>
54 +<!-- v2&#45;&gt;v3 -->
55 +<g id="edge2" class="edge">
56 +<title>v2&#45;&gt;v3</title>
57 +<path fill="none" stroke="black" d="M1051.02,-647.01C1051.02,-638.99 1051.02,-629.25 1051.02,-620.27"/>
58 +<polygon fill="black" stroke="black" points="1054.52,-620.23 1051.02,-610.23 1047.52,-620.23 1054.52,-620.23"/>
59 +</g>
60 +<!-- v4 -->
61 +<g id="node5" class="node">
62 +<title>v4</title>
63 +<polygon fill="none" stroke="black" points="1151.93,-537.2 950.11,-537.2 950.11,-501.2 1151.93,-501.2 1151.93,-537.2"/>
64 +<text text-anchor="middle" x="1051.02" y="-515" font-family="Times,serif" font-size="14.00">v4 (mutable x$2 @ mutable x$2)</text>
65 +</g>
66 +<!-- v3&#45;&gt;v4 -->
67 +<g id="edge3" class="edge">
68 +<title>v3&#45;&gt;v4</title>
69 +<path fill="none" stroke="black" d="M1051.02,-574.01C1051.02,-565.99 1051.02,-556.25 1051.02,-547.27"/>
70 +<polygon fill="black" stroke="black" points="1054.52,-547.23 1051.02,-537.23 1047.52,-547.23 1054.52,-547.23"/>
71 +</g>
72 +<!-- v6 -->
73 +<g id="node7" class="node">
74 +<title>v6</title>
75 +<polygon fill="none" stroke="black" points="1194.42,-448.4 907.62,-448.4 907.62,-412.4 1194.42,-412.4 1194.42,-448.4"/>
76 +<text text-anchor="middle" x="1051.02" y="-426.2" font-family="Times,serif" font-size="14.00">v6 (mutable y$3 @ mutable y$3 = mutable x$2)</text>
77 +</g>
78 +<!-- v4&#45;&gt;v6 -->
79 +<g id="edge6" class="edge">
80 +<title>v4&#45;&gt;v6</title>
81 +<path fill="none" stroke="black" d="M1031.32,-501.05C1026.66,-495.84 1022.32,-489.74 1019.83,-483.2 1017.17,-476.22 1017.17,-473.38 1019.83,-466.4 1021.15,-462.92 1022.99,-459.58 1025.13,-456.42"/>
82 +<polygon fill="black" stroke="black" points="1027.89,-458.57 1031.32,-448.55 1022.39,-454.25 1027.89,-458.57"/>
83 +<text text-anchor="middle" x="1040.62" y="-470.6" font-family="Times,serif" font-size="14.00">capture</text>
84 +</g>
85 +<!-- v6&#45;&gt;v4 -->
86 +<g id="edge7" class="edge">
87 +<title>v6&#45;&gt;v4</title>
88 +<path fill="none" stroke="black" d="M1056.97,-448.64C1058.63,-454.24 1060.2,-460.52 1061.02,-466.4 1062.05,-473.79 1062.05,-475.81 1061.02,-483.2 1060.66,-485.77 1060.16,-488.42 1059.57,-491.06"/>
89 +<polygon fill="black" stroke="black" points="1056.12,-490.4 1056.97,-500.96 1062.89,-492.17 1056.12,-490.4"/>
90 +<text text-anchor="middle" x="1082.62" y="-470.6" font-family="Times,serif" font-size="14.00">capture</text>
91 +</g>
92 +<!-- v7 -->
93 +<g id="node8" class="node">
94 +<title>v7</title>
95 +<polygon fill="none" stroke="black" points="1250.84,-375.4 851.19,-375.4 851.19,-339.4 1250.84,-339.4 1250.84,-375.4"/>
96 +<text text-anchor="middle" x="1051.02" y="-353.2" font-family="Times,serif" font-size="14.00">v7 (mutable y$3.push @ Call mutable y$3.push(frozen props$1.p1))</text>
97 +</g>
98 +<!-- v6&#45;&gt;v7 -->
99 +<g id="edge5" class="edge">
100 +<title>v6&#45;&gt;v7</title>
101 +<path fill="none" stroke="black" d="M1051.02,-412.21C1051.02,-404.19 1051.02,-394.45 1051.02,-385.47"/>
102 +<polygon fill="black" stroke="black" points="1054.52,-385.43 1051.02,-375.43 1047.52,-385.43 1054.52,-385.43"/>
103 +</g>
104 +<!-- v14 -->
105 +<g id="node15" class="node">
106 +<title>v14</title>
107 +<polygon fill="none" stroke="black" points="1372.6,-302.4 729.44,-302.4 729.44,-266.4 1372.6,-266.4 1372.6,-302.4"/>
108 +<text text-anchor="middle" x="1051.02" y="-280.2" font-family="Times,serif" font-size="14.00">v14 (readonly y$3 @ JSX &lt;frozen Component$0 x={frozen x$2} y={readonly y$3} &gt;&lt;/frozen Component$0&gt;)</text>
109 +</g>
110 +<!-- v7&#45;&gt;v14 -->
111 +<g id="edge13" class="edge">
112 +<title>v7&#45;&gt;v14</title>
113 +<path fill="none" stroke="black" d="M1051.02,-339.21C1051.02,-331.19 1051.02,-321.45 1051.02,-312.47"/>
114 +<polygon fill="black" stroke="black" points="1054.52,-312.43 1051.02,-302.43 1047.52,-312.43 1054.52,-312.43"/>
115 +</g>
116 +<!-- v8 -->
117 +<g id="node9" class="node">
118 +<title>v8</title>
119 +<polygon fill="none" stroke="black" points="380.61,-375.4 137.43,-375.4 137.43,-339.4 380.61,-339.4 380.61,-375.4"/>
120 +<text text-anchor="middle" x="259.02" y="-353.2" font-family="Times,serif" font-size="14.00">v8 (frozen x$2 @ frozen x$2 = Array [])</text>
121 +</g>
122 +<!-- v9 -->
123 +<g id="node10" class="node">
124 +<title>v9</title>
125 +<polygon fill="none" stroke="black" points="518.06,-302.4 -0.02,-302.4 -0.02,-266.4 518.06,-266.4 518.06,-302.4"/>
126 +<text text-anchor="middle" x="259.02" y="-280.2" font-family="Times,serif" font-size="14.00">v9 (frozen x$2 @ JSX &lt;frozen Component$0 x={frozen x$2} &gt;&lt;/frozen Component$0&gt;)</text>
127 +</g>
128 +<!-- v8&#45;&gt;v9 -->
129 +<g id="edge8" class="edge">
130 +<title>v8&#45;&gt;v9</title>
131 +<path fill="none" stroke="black" d="M259.02,-339.21C259.02,-331.19 259.02,-321.45 259.02,-312.47"/>
132 +<polygon fill="black" stroke="black" points="262.52,-312.43 259.02,-302.43 255.52,-312.43 262.52,-312.43"/>
133 +</g>
134 +<!-- v10 -->
135 +<g id="node11" class="node">
136 +<title>v10</title>
137 +<polygon fill="none" stroke="black" points="623.2,-213.6 22.83,-213.6 22.83,-177.6 623.2,-177.6 623.2,-213.6"/>
138 +<text text-anchor="middle" x="323.02" y="-191.4" font-family="Times,serif" font-size="14.00">v10 (frozen _$4 @ frozen _$4 = JSX &lt;frozen Component$0 x={frozen x$2} &gt;&lt;/frozen Component$0&gt;)</text>
139 +</g>
140 +<!-- v9&#45;&gt;v10 -->
141 +<g id="edge9" class="edge">
142 +<title>v9&#45;&gt;v10</title>
143 +<path fill="none" stroke="black" d="M255.17,-266.36C253.7,-255.64 253.63,-241.94 259.83,-231.6 262.5,-227.14 265.96,-223.21 269.89,-219.75"/>
144 +<polygon fill="black" stroke="black" points="272.07,-222.5 277.93,-213.67 267.84,-216.91 272.07,-222.5"/>
145 +<text text-anchor="middle" x="280.62" y="-235.8" font-family="Times,serif" font-size="14.00">capture</text>
146 +</g>
147 +<!-- v13 -->
148 +<g id="node14" class="node">
149 +<title>v13</title>
150 +<polygon fill="none" stroke="black" points="1015.37,-124.8 384.67,-124.8 384.67,-88.8 1015.37,-88.8 1015.37,-124.8"/>
151 +<text text-anchor="middle" x="700.02" y="-102.6" font-family="Times,serif" font-size="14.00">v13 (frozen x$2 @ JSX &lt;frozen Component$0 x={frozen x$2} y={readonly y$3} &gt;&lt;/frozen Component$0&gt;)</text>
152 +</g>
153 +<!-- v9&#45;&gt;v13 -->
154 +<g id="edge11" class="edge">
155 +<title>v9&#45;&gt;v13</title>
156 +<path fill="none" stroke="black" d="M120.57,-266.36C43.83,-251.39 -28.3,-224.44 14.02,-177.6 39.59,-149.29 209.75,-131.87 374.18,-121.51"/>
157 +<polygon fill="black" stroke="black" points="374.73,-124.99 384.49,-120.87 374.3,-118 374.73,-124.99"/>
158 +</g>
159 +<!-- v10&#45;&gt;v9 -->
160 +<g id="edge12" class="edge">
161 +<title>v10&#45;&gt;v9</title>
162 +<path fill="none" stroke="black" d="M317.95,-214C314.32,-224.6 308.71,-238.05 301.02,-248.4 298.13,-252.29 294.72,-256.02 291.12,-259.5"/>
163 +<polygon fill="black" stroke="black" points="288.67,-256.99 283.55,-266.27 293.33,-262.21 288.67,-256.99"/>
164 +<text text-anchor="middle" x="331.62" y="-235.8" font-family="Times,serif" font-size="14.00">capture</text>
165 +</g>
166 +<!-- v10&#45;&gt;v13 -->
167 +<g id="edge17" class="edge">
168 +<title>v10&#45;&gt;v13</title>
169 +<path fill="none" stroke="black" d="M397.05,-177.55C460.08,-163.04 550.58,-142.21 616.25,-127.09"/>
170 +<polygon fill="black" stroke="black" points="617.2,-130.46 626.16,-124.81 615.62,-123.64 617.2,-130.46"/>
171 +<text text-anchor="middle" x="566.62" y="-147" font-family="Times,serif" font-size="14.00">capture</text>
172 +</g>
173 +<!-- v11 -->
174 +<g id="node12" class="node">
175 +<title>v11</title>
176 +<polygon fill="none" stroke="black" points="1904.89,-683.2 1321.15,-683.2 1321.15,-647.2 1904.89,-647.2 1904.89,-683.2"/>
177 +<text text-anchor="middle" x="1613.02" y="-661" font-family="Times,serif" font-size="14.00">v11 (frozen Component$0 @ JSX &lt;frozen Component$0 x={frozen x$2} &gt;&lt;/frozen Component$0&gt;)</text>
178 +</g>
179 +<!-- v12 -->
180 +<g id="node13" class="node">
181 +<title>v12</title>
182 +<polygon fill="none" stroke="black" points="1957.2,-610.2 1268.84,-610.2 1268.84,-574.2 1957.2,-574.2 1957.2,-610.2"/>
183 +<text text-anchor="middle" x="1613.02" y="-588" font-family="Times,serif" font-size="14.00">v12 (frozen Component$0 @ JSX &lt;frozen Component$0 x={frozen x$2} y={readonly y$3} &gt;&lt;/frozen Component$0&gt;)</text>
184 +</g>
185 +<!-- v11&#45;&gt;v12 -->
186 +<g id="edge10" class="edge">
187 +<title>v11&#45;&gt;v12</title>
188 +<path fill="none" stroke="black" d="M1613.02,-647.01C1613.02,-638.99 1613.02,-629.25 1613.02,-620.27"/>
189 +<polygon fill="black" stroke="black" points="1616.52,-620.23 1613.02,-610.23 1609.52,-620.23 1616.52,-620.23"/>
190 +</g>
191 +<!-- v15 -->
192 +<g id="node16" class="node">
193 +<title>v15</title>
194 +<polygon fill="none" stroke="black" points="1332.52,-213.6 641.52,-213.6 641.52,-177.6 1332.52,-177.6 1332.52,-213.6"/>
195 +<text text-anchor="middle" x="987.02" y="-191.4" font-family="Times,serif" font-size="14.00">v15 (frozen $5 @ frozen $5 = JSX &lt;frozen Component$0 x={frozen x$2} y={readonly y$3} &gt;&lt;/frozen Component$0&gt;)</text>
196 +</g>
197 +<!-- v13&#45;&gt;v15 -->
198 +<g id="edge15" class="edge">
199 +<title>v13&#45;&gt;v15</title>
200 +<path fill="none" stroke="black" d="M754.75,-124.9C787.52,-135.09 830.02,-148.21 867.83,-159.6 884.31,-164.56 902.11,-169.84 918.79,-174.74"/>
201 +<polygon fill="black" stroke="black" points="917.89,-178.12 928.47,-177.58 919.86,-171.41 917.89,-178.12"/>
202 +<text text-anchor="middle" x="888.62" y="-147" font-family="Times,serif" font-size="14.00">capture</text>
203 +</g>
204 +<!-- v16 -->
205 +<g id="node17" class="node">
206 +<title>v16</title>
207 +<polygon fill="none" stroke="black" points="1151.84,-36 934.19,-36 934.19,0 1151.84,0 1151.84,-36"/>
208 +<text text-anchor="middle" x="1043.02" y="-13.8" font-family="Times,serif" font-size="14.00">v16 (frozen $5 @ Return frozen $5)</text>
209 +</g>
210 +<!-- v13&#45;&gt;v16 -->
211 +<g id="edge20" class="edge">
212 +<title>v13&#45;&gt;v16</title>
213 +<path fill="none" stroke="black" d="M767.38,-88.75C824.48,-74.3 906.38,-53.58 966.06,-38.47"/>
214 +<polygon fill="black" stroke="black" points="966.98,-41.85 975.82,-36.01 965.26,-35.07 966.98,-41.85"/>
215 +<text text-anchor="middle" x="923.62" y="-58.2" font-family="Times,serif" font-size="14.00">capture</text>
216 +</g>
217 +<!-- v14&#45;&gt;v15 -->
218 +<g id="edge16" class="edge">
219 +<title>v14&#45;&gt;v15</title>
220 +<path fill="none" stroke="black" d="M1005.93,-266.33C998.73,-261.61 992.21,-255.71 987.83,-248.4 983.47,-241.13 982.21,-232.2 982.36,-223.81"/>
221 +<polygon fill="black" stroke="black" points="985.86,-223.89 983.17,-213.64 978.88,-223.33 985.86,-223.89"/>
222 +<text text-anchor="middle" x="1008.62" y="-235.8" font-family="Times,serif" font-size="14.00">capture</text>
223 +</g>
224 +<!-- v14&#45;&gt;v16 -->
225 +<g id="edge21" class="edge">
226 +<title>v14&#45;&gt;v16</title>
227 +<path fill="none" stroke="black" d="M1191.41,-266.37C1255.94,-255.37 1322.48,-238.38 1342.02,-213.6 1409.86,-127.56 1241.15,-67.5 1130.43,-38.61"/>
228 +<polygon fill="black" stroke="black" points="1131.12,-35.17 1120.57,-36.08 1129.38,-41.95 1131.12,-35.17"/>
229 +<text text-anchor="middle" x="1375.62" y="-147" font-family="Times,serif" font-size="14.00">capture</text>
230 +</g>
231 +<!-- v15&#45;&gt;v13 -->
232 +<g id="edge18" class="edge">
233 +<title>v15&#45;&gt;v13</title>
234 +<path fill="none" stroke="black" d="M966.53,-177.48C951.53,-165.87 930.19,-151.16 909.02,-142.8 893.21,-136.56 876.31,-131.43 859.22,-127.22"/>
235 +<polygon fill="black" stroke="black" points="859.67,-123.73 849.14,-124.84 858.07,-130.54 859.67,-123.73"/>
236 +<text text-anchor="middle" x="961.62" y="-147" font-family="Times,serif" font-size="14.00">capture</text>
237 +</g>
238 +<!-- v15&#45;&gt;v14 -->
239 +<g id="edge19" class="edge">
240 +<title>v15&#45;&gt;v14</title>
241 +<path fill="none" stroke="black" d="M1011.55,-213.73C1017.81,-218.95 1024.15,-225.05 1029.02,-231.6 1034.55,-239.04 1039,-248.08 1042.41,-256.51"/>
242 +<polygon fill="black" stroke="black" points="1039.18,-257.85 1045.95,-266 1045.74,-255.41 1039.18,-257.85"/>
243 +<text text-anchor="middle" x="1059.62" y="-235.8" font-family="Times,serif" font-size="14.00">capture</text>
244 +</g>
245 +<!-- v15&#45;&gt;v16 -->
246 +<g id="edge14" class="edge">
247 +<title>v15&#45;&gt;v16</title>
248 +<path fill="none" stroke="black" d="M998.02,-177.5C1006.37,-163.77 1017.48,-143.73 1024.02,-124.8 1032.93,-99 1037.86,-68.14 1040.45,-46.42"/>
249 +<polygon fill="black" stroke="black" points="1043.95,-46.59 1041.57,-36.27 1037,-45.83 1043.95,-46.59"/>
250 +</g>
251 +</g>
252 +</svg>
compiler/forget/src/__tests__/fixtures/hir-svg/simple.svg new
+157
@@ -0,0 +1,157 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4 +<!-- Generated by graphviz version 6.0.1 (20220924.0800)
5 + -->
6 +<!-- Title: InferMutability Pages: 1 -->
7 +<svg width="3054pt" height="116pt"
8 + viewBox="0.00 0.00 3053.93 116.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9 +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 112)">
10 +<title>InferMutability</title>
11 +<polygon fill="white" stroke="none" points="-4,4 -4,-112 3049.93,-112 3049.93,4 -4,4"/>
12 +<!-- v0 -->
13 +<g id="node1" class="node">
14 +<title>v0</title>
15 +<polygon fill="none" stroke="black" points="245.32,-108 62.7,-108 62.7,-72 245.32,-72 245.32,-108"/>
16 +<text text-anchor="middle" x="154.01" y="-85.8" font-family="Times,serif" font-size="14.00">v0 (frozen x$1 @ &lt;no&#45;instr&gt;)</text>
17 +</g>
18 +<!-- v1 -->
19 +<g id="node2" class="node">
20 +<title>v1</title>
21 +<polygon fill="none" stroke="black" points="308.03,-36 -0.01,-36 -0.01,0 308.03,0 308.03,-36"/>
22 +<text text-anchor="middle" x="154.01" y="-13.8" font-family="Times,serif" font-size="14.00">v1 (frozen x$1 @ If (frozen x$1) then:bb2 else:bb1)</text>
23 +</g>
24 +<!-- v0&#45;&gt;v1 -->
25 +<g id="edge1" class="edge">
26 +<title>v0&#45;&gt;v1</title>
27 +<path fill="none" stroke="black" d="M154.01,-71.7C154.01,-63.98 154.01,-54.71 154.01,-46.11"/>
28 +<polygon fill="black" stroke="black" points="157.51,-46.1 154.01,-36.1 150.51,-46.1 157.51,-46.1"/>
29 +</g>
30 +<!-- v2 -->
31 +<g id="node3" class="node">
32 +<title>v2</title>
33 +<polygon fill="none" stroke="black" points="769.32,-108 586.7,-108 586.7,-72 769.32,-72 769.32,-108"/>
34 +<text text-anchor="middle" x="678.01" y="-85.8" font-family="Times,serif" font-size="14.00">v2 (frozen y$2 @ &lt;no&#45;instr&gt;)</text>
35 +</g>
36 +<!-- v3 -->
37 +<g id="node4" class="node">
38 +<title>v3</title>
39 +<polygon fill="none" stroke="black" points="686.4,-36 325.62,-36 325.62,0 686.4,0 686.4,-36"/>
40 +<text text-anchor="middle" x="506.01" y="-13.8" font-family="Times,serif" font-size="14.00">v3 (frozen y$2 @ Call mutable foo$0(frozen $3, frozen y$2))</text>
41 +</g>
42 +<!-- v2&#45;&gt;v3 -->
43 +<g id="edge2" class="edge">
44 +<title>v2&#45;&gt;v3</title>
45 +<path fill="none" stroke="black" d="M635.93,-71.88C612.21,-62.22 582.39,-50.09 557.31,-39.88"/>
46 +<polygon fill="black" stroke="black" points="558.53,-36.6 547.95,-36.07 555.89,-43.08 558.53,-36.6"/>
47 +</g>
48 +<!-- v4 -->
49 +<g id="node5" class="node">
50 +<title>v4</title>
51 +<polygon fill="none" stroke="black" points="996.08,-36 703.93,-36 703.93,0 996.08,0 996.08,-36"/>
52 +<text text-anchor="middle" x="850.01" y="-13.8" font-family="Times,serif" font-size="14.00">v4 (frozen y$2 @ Binary frozen y$2 * frozen $5)</text>
53 +</g>
54 +<!-- v2&#45;&gt;v4 -->
55 +<g id="edge3" class="edge">
56 +<title>v2&#45;&gt;v4</title>
57 +<path fill="none" stroke="black" d="M720.08,-71.88C743.81,-62.22 773.62,-50.09 798.71,-39.88"/>
58 +<polygon fill="black" stroke="black" points="800.13,-43.08 808.07,-36.07 797.49,-36.6 800.13,-43.08"/>
59 +</g>
60 +<!-- v5 -->
61 +<g id="node6" class="node">
62 +<title>v5</title>
63 +<polygon fill="none" stroke="black" points="1296.05,-108 1085.96,-108 1085.96,-72 1296.05,-72 1296.05,-108"/>
64 +<text text-anchor="middle" x="1191.01" y="-85.8" font-family="Times,serif" font-size="14.00">v5 (frozen $3 @ frozen $3 = false)</text>
65 +</g>
66 +<!-- v6 -->
67 +<g id="node7" class="node">
68 +<title>v6</title>
69 +<polygon fill="none" stroke="black" points="1367.9,-36 1014.12,-36 1014.12,0 1367.9,0 1367.9,-36"/>
70 +<text text-anchor="middle" x="1191.01" y="-13.8" font-family="Times,serif" font-size="14.00">v6 (frozen $3 @ Call mutable foo$0(frozen $3, frozen y$2))</text>
71 +</g>
72 +<!-- v5&#45;&gt;v6 -->
73 +<g id="edge4" class="edge">
74 +<title>v5&#45;&gt;v6</title>
75 +<path fill="none" stroke="black" d="M1191.01,-71.7C1191.01,-63.98 1191.01,-54.71 1191.01,-46.11"/>
76 +<polygon fill="black" stroke="black" points="1194.51,-46.1 1191.01,-36.1 1187.51,-46.1 1194.51,-46.1"/>
77 +</g>
78 +<!-- v7 -->
79 +<g id="node8" class="node">
80 +<title>v7</title>
81 +<polygon fill="none" stroke="black" points="1736.04,-108 1313.97,-108 1313.97,-72 1736.04,-72 1736.04,-108"/>
82 +<text text-anchor="middle" x="1525.01" y="-85.8" font-family="Times,serif" font-size="14.00">v7 (frozen $4 @ frozen $4 = Call mutable foo$0(frozen $3, frozen y$2))</text>
83 +</g>
84 +<!-- v8 -->
85 +<g id="node9" class="node">
86 +<title>v8</title>
87 +<polygon fill="none" stroke="black" points="1630.33,-36 1419.68,-36 1419.68,0 1630.33,0 1630.33,-36"/>
88 +<text text-anchor="middle" x="1525.01" y="-13.8" font-family="Times,serif" font-size="14.00">v8 (frozen $4 @ Return frozen $4)</text>
89 +</g>
90 +<!-- v7&#45;&gt;v8 -->
91 +<g id="edge5" class="edge">
92 +<title>v7&#45;&gt;v8</title>
93 +<path fill="none" stroke="black" d="M1525.01,-71.7C1525.01,-63.98 1525.01,-54.71 1525.01,-46.11"/>
94 +<polygon fill="black" stroke="black" points="1528.51,-46.1 1525.01,-36.1 1521.51,-46.1 1528.51,-46.1"/>
95 +</g>
96 +<!-- v9 -->
97 +<g id="node10" class="node">
98 +<title>v9</title>
99 +<polygon fill="none" stroke="black" points="2135.9,-108 1754.12,-108 1754.12,-72 2135.9,-72 2135.9,-108"/>
100 +<text text-anchor="middle" x="1945.01" y="-85.8" font-family="Times,serif" font-size="14.00">v9 (mutable foo$0 @ Call mutable foo$0(frozen $3, frozen y$2))</text>
101 +</g>
102 +<!-- v10 -->
103 +<g id="node11" class="node">
104 +<title>v10</title>
105 +<polygon fill="none" stroke="black" points="2359.63,-108 2154.39,-108 2154.39,-72 2359.63,-72 2359.63,-108"/>
106 +<text text-anchor="middle" x="2257.01" y="-85.8" font-family="Times,serif" font-size="14.00">v10 (frozen $5 @ frozen $5 = 10)</text>
107 +</g>
108 +<!-- v11 -->
109 +<g id="node12" class="node">
110 +<title>v11</title>
111 +<polygon fill="none" stroke="black" points="2403.08,-36 2110.93,-36 2110.93,0 2403.08,0 2403.08,-36"/>
112 +<text text-anchor="middle" x="2257.01" y="-13.8" font-family="Times,serif" font-size="14.00">v11 (frozen $5 @ Binary frozen y$2 * frozen $5)</text>
113 +</g>
114 +<!-- v10&#45;&gt;v11 -->
115 +<g id="edge6" class="edge">
116 +<title>v10&#45;&gt;v11</title>
117 +<path fill="none" stroke="black" d="M2257.01,-71.7C2257.01,-63.98 2257.01,-54.71 2257.01,-46.11"/>
118 +<polygon fill="black" stroke="black" points="2260.51,-46.1 2257.01,-36.1 2253.51,-46.1 2260.51,-46.1"/>
119 +</g>
120 +<!-- v12 -->
121 +<g id="node13" class="node">
122 +<title>v12</title>
123 +<polygon fill="none" stroke="black" points="2738.23,-108 2377.79,-108 2377.79,-72 2738.23,-72 2738.23,-108"/>
124 +<text text-anchor="middle" x="2558.01" y="-85.8" font-family="Times,serif" font-size="14.00">v12 (frozen $6 @ frozen $6 = Binary frozen y$2 * frozen $5)</text>
125 +</g>
126 +<!-- v13 -->
127 +<g id="node14" class="node">
128 +<title>v13</title>
129 +<polygon fill="none" stroke="black" points="2668.7,-36 2447.32,-36 2447.32,0 2668.7,0 2668.7,-36"/>
130 +<text text-anchor="middle" x="2558.01" y="-13.8" font-family="Times,serif" font-size="14.00">v13 (frozen $6 @ Array [frozen $6])</text>
131 +</g>
132 +<!-- v12&#45;&gt;v13 -->
133 +<g id="edge7" class="edge">
134 +<title>v12&#45;&gt;v13</title>
135 +<path fill="none" stroke="black" d="M2558.01,-71.7C2558.01,-63.98 2558.01,-54.71 2558.01,-46.11"/>
136 +<polygon fill="black" stroke="black" points="2561.51,-46.1 2558.01,-36.1 2554.51,-46.1 2561.51,-46.1"/>
137 +</g>
138 +<!-- v14 -->
139 +<g id="node15" class="node">
140 +<title>v14</title>
141 +<polygon fill="none" stroke="black" points="3045.85,-108 2756.17,-108 2756.17,-72 3045.85,-72 3045.85,-108"/>
142 +<text text-anchor="middle" x="2901.01" y="-85.8" font-family="Times,serif" font-size="14.00">v14 (frozen $7 @ frozen $7 = Array [frozen $6])</text>
143 +</g>
144 +<!-- v15 -->
145 +<g id="node16" class="node">
146 +<title>v15</title>
147 +<polygon fill="none" stroke="black" points="3009.83,-36 2792.18,-36 2792.18,0 3009.83,0 3009.83,-36"/>
148 +<text text-anchor="middle" x="2901.01" y="-13.8" font-family="Times,serif" font-size="14.00">v15 (frozen $7 @ Return frozen $7)</text>
149 +</g>
150 +<!-- v14&#45;&gt;v15 -->
151 +<g id="edge8" class="edge">
152 +<title>v14&#45;&gt;v15</title>
153 +<path fill="none" stroke="black" d="M2901.01,-71.7C2901.01,-63.98 2901.01,-54.71 2901.01,-46.11"/>
154 +<polygon fill="black" stroke="black" points="2904.51,-46.1 2901.01,-36.1 2897.51,-46.1 2904.51,-46.1"/>
155 +</g>
156 +</g>
157 +</svg>
compiler/forget/src/__tests__/fixtures/hir-svg/switch.svg new
+345
@@ -0,0 +1,345 @@
1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4 +<!-- Generated by graphviz version 6.0.1 (20220924.0800)
5 + -->
6 +<!-- Title: InferMutability Pages: 1 -->
7 +<svg width="3277pt" height="602pt"
8 + viewBox="0.00 0.00 3276.76 602.40" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9 +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 598.4)">
10 +<title>InferMutability</title>
11 +<polygon fill="white" stroke="none" points="-4,4 -4,-598.4 3272.76,-598.4 3272.76,4 -4,4"/>
12 +<!-- v0 -->
13 +<g id="node1" class="node">
14 +<title>v0</title>
15 +<polygon fill="none" stroke="black" points="509.99,-594.4 303.15,-594.4 303.15,-558.4 509.99,-558.4 509.99,-594.4"/>
16 +<text text-anchor="middle" x="406.57" y="-572.2" font-family="Times,serif" font-size="14.00">v0 (frozen props$1 @ &lt;no&#45;instr&gt;)</text>
17 +</g>
18 +<!-- v1 -->
19 +<g id="node2" class="node">
20 +<title>v1</title>
21 +<polygon fill="none" stroke="black" points="734.98,-521.4 78.17,-521.4 78.17,-485.4 734.98,-485.4 734.98,-521.4"/>
22 +<text text-anchor="middle" x="406.57" y="-499.2" font-family="Times,serif" font-size="14.00">v1 (frozen props$1.p0 @ Switch (frozen props$1.p0); &#160;&#160;Case frozen $5: bb4; &#160;&#160;Case frozen $4: bb2; &#160;&#160;Default: bb1)</text>
23 +</g>
24 +<!-- v0&#45;&gt;v1 -->
25 +<g id="edge1" class="edge">
26 +<title>v0&#45;&gt;v1</title>
27 +<path fill="none" stroke="black" d="M406.57,-558.21C406.57,-550.19 406.57,-540.45 406.57,-531.47"/>
28 +<polygon fill="black" stroke="black" points="410.07,-531.43 406.57,-521.43 403.07,-531.43 410.07,-531.43"/>
29 +</g>
30 +<!-- v12 -->
31 +<g id="node13" class="node">
32 +<title>v12</title>
33 +<polygon fill="none" stroke="black" points="409.21,-448.4 -0.07,-448.4 -0.07,-412.4 409.21,-412.4 409.21,-448.4"/>
34 +<text text-anchor="middle" x="204.57" y="-426.2" font-family="Times,serif" font-size="14.00">v12 (frozen props$1.p2 @ Call mutable x$2.push(frozen props$1.p2))</text>
35 +</g>
36 +<!-- v1&#45;&gt;v12 -->
37 +<g id="edge8" class="edge">
38 +<title>v1&#45;&gt;v12</title>
39 +<path fill="none" stroke="black" d="M358.19,-485.39C329.54,-475.32 293.06,-462.5 262.83,-451.88"/>
40 +<polygon fill="black" stroke="black" points="263.85,-448.53 253.26,-448.51 261.53,-455.13 263.85,-448.53"/>
41 +</g>
42 +<!-- v13 -->
43 +<g id="node14" class="node">
44 +<title>v13</title>
45 +<polygon fill="none" stroke="black" points="467.37,-359.6 67.77,-359.6 67.77,-323.6 467.37,-323.6 467.37,-359.6"/>
46 +<text text-anchor="middle" x="267.57" y="-337.4" font-family="Times,serif" font-size="14.00">v13 (frozen props$1.p4 @ Call frozen y$3.push(frozen props$1.p4))</text>
47 +</g>
48 +<!-- v1&#45;&gt;v13 -->
49 +<g id="edge9" class="edge">
50 +<title>v1&#45;&gt;v13</title>
51 +<path fill="none" stroke="black" d="M420.72,-485.28C434.64,-466.22 451.77,-435.13 436.57,-412.4 421.01,-389.14 396.12,-373.62 370.17,-363.27"/>
52 +<polygon fill="black" stroke="black" points="371.17,-359.9 360.58,-359.68 368.72,-366.46 371.17,-359.9"/>
53 +</g>
54 +<!-- v2 -->
55 +<g id="node3" class="node">
56 +<title>v2</title>
57 +<polygon fill="none" stroke="black" points="1172.85,-594.4 910.29,-594.4 910.29,-558.4 1172.85,-558.4 1172.85,-594.4"/>
58 +<text text-anchor="middle" x="1041.57" y="-572.2" font-family="Times,serif" font-size="14.00">v2 (mutable x$2 @ mutable x$2 = Array [])</text>
59 +</g>
60 +<!-- v3 -->
61 +<g id="node4" class="node">
62 +<title>v3</title>
63 +<polygon fill="none" stroke="black" points="1241.4,-521.4 841.75,-521.4 841.75,-485.4 1241.4,-485.4 1241.4,-521.4"/>
64 +<text text-anchor="middle" x="1041.57" y="-499.2" font-family="Times,serif" font-size="14.00">v3 (mutable x$2.push @ Call mutable x$2.push(frozen props$1.p2))</text>
65 +</g>
66 +<!-- v2&#45;&gt;v3 -->
67 +<g id="edge2" class="edge">
68 +<title>v2&#45;&gt;v3</title>
69 +<path fill="none" stroke="black" d="M1041.57,-558.21C1041.57,-550.19 1041.57,-540.45 1041.57,-531.47"/>
70 +<polygon fill="black" stroke="black" points="1045.07,-531.43 1041.57,-521.43 1038.07,-531.43 1045.07,-531.43"/>
71 +</g>
72 +<!-- v4 -->
73 +<g id="node5" class="node">
74 +<title>v4</title>
75 +<polygon fill="none" stroke="black" points="1171.48,-448.4 969.66,-448.4 969.66,-412.4 1171.48,-412.4 1171.48,-448.4"/>
76 +<text text-anchor="middle" x="1070.57" y="-426.2" font-family="Times,serif" font-size="14.00">v4 (mutable x$2 @ mutable x$2)</text>
77 +</g>
78 +<!-- v2&#45;&gt;v4 -->
79 +<g id="edge3" class="edge">
80 +<title>v2&#45;&gt;v4</title>
81 +<path fill="none" stroke="black" d="M1172.81,-558.38C1215.6,-549.94 1255.51,-537.93 1268.57,-521.4 1300.34,-481.18 1242.76,-458.31 1181.64,-445.7"/>
82 +<polygon fill="black" stroke="black" points="1182.3,-442.26 1171.81,-443.76 1180.95,-449.13 1182.3,-442.26"/>
83 +</g>
84 +<!-- v5 -->
85 +<g id="node6" class="node">
86 +<title>v5</title>
87 +<polygon fill="none" stroke="black" points="1093.88,-359.6 533.26,-359.6 533.26,-323.6 1093.88,-323.6 1093.88,-359.6"/>
88 +<text text-anchor="middle" x="813.57" y="-337.4" font-family="Times,serif" font-size="14.00">v5 (readonly x$2 @ JSX &lt;frozen Component$0 data={readonly x$2} &gt;&lt;/frozen Component$0&gt;)</text>
89 +</g>
90 +<!-- v2&#45;&gt;v5 -->
91 +<g id="edge4" class="edge">
92 +<title>v2&#45;&gt;v5</title>
93 +<path fill="none" stroke="black" d="M930.31,-558.39C887.81,-549.56 846.25,-537.25 832.57,-521.4 796.04,-479.06 801.33,-408.41 807.8,-369.81"/>
94 +<polygon fill="black" stroke="black" points="811.27,-370.29 809.63,-359.83 804.39,-369.04 811.27,-370.29"/>
95 +</g>
96 +<!-- v3&#45;&gt;v3 -->
97 +<g id="edge10" class="edge">
98 +<title>v3&#45;&gt;v3</title>
99 +<path fill="none" stroke="black" d="M1241.53,-508.02C1252.78,-506.9 1259.48,-505.36 1259.48,-503.4 1259.48,-502.14 1256.73,-501.06 1251.8,-500.15"/>
100 +<polygon fill="black" stroke="black" points="1251.9,-496.63 1241.53,-498.78 1250.98,-503.57 1251.9,-496.63"/>
101 +</g>
102 +<!-- v3&#45;&gt;v4 -->
103 +<g id="edge11" class="edge">
104 +<title>v3&#45;&gt;v4</title>
105 +<path fill="none" stroke="black" d="M1042.71,-485.21C1045.23,-476.93 1049.14,-466.81 1053.33,-457.59"/>
106 +<polygon fill="black" stroke="black" points="1056.56,-458.96 1057.75,-448.43 1050.26,-455.91 1056.56,-458.96"/>
107 +</g>
108 +<!-- v3&#45;&gt;v5 -->
109 +<g id="edge12" class="edge">
110 +<title>v3&#45;&gt;v5</title>
111 +<path fill="none" stroke="black" d="M1015.51,-485.37C999.55,-474.85 978.77,-461.01 960.57,-448.4 920.35,-420.53 874.7,-387.44 845.09,-365.78"/>
112 +<polygon fill="black" stroke="black" points="846.95,-362.8 836.81,-359.72 842.81,-368.45 846.95,-362.8"/>
113 +</g>
114 +<!-- v4&#45;&gt;v3 -->
115 +<g id="edge18" class="edge">
116 +<title>v4&#45;&gt;v3</title>
117 +<path fill="none" stroke="black" d="M1069.48,-448.43C1066.98,-456.69 1063.08,-466.8 1058.89,-476.03"/>
118 +<polygon fill="black" stroke="black" points="1055.65,-474.68 1054.47,-485.21 1061.96,-477.72 1055.65,-474.68"/>
119 +</g>
120 +<!-- v4&#45;&gt;v4 -->
121 +<g id="edge19" class="edge">
122 +<title>v4&#45;&gt;v4</title>
123 +<path fill="none" stroke="black" d="M1171.67,-436.11C1182.54,-435.01 1189.53,-433.11 1189.53,-430.4 1189.53,-428.66 1186.66,-427.26 1181.74,-426.18"/>
124 +<polygon fill="black" stroke="black" points="1182.08,-422.7 1171.67,-424.69 1181.05,-429.62 1182.08,-422.7"/>
125 +</g>
126 +<!-- v4&#45;&gt;v5 -->
127 +<g id="edge20" class="edge">
128 +<title>v4&#45;&gt;v5</title>
129 +<path fill="none" stroke="black" d="M1020.1,-412.35C978.02,-398.14 917.97,-377.86 873.46,-362.83"/>
130 +<polygon fill="black" stroke="black" points="874.52,-359.49 863.92,-359.61 872.28,-366.12 874.52,-359.49"/>
131 +</g>
132 +<!-- v15 -->
133 +<g id="node16" class="node">
134 +<title>v15</title>
135 +<polygon fill="none" stroke="black" points="1405.47,-359.6 1111.67,-359.6 1111.67,-323.6 1405.47,-323.6 1405.47,-359.6"/>
136 +<text text-anchor="middle" x="1258.57" y="-337.4" font-family="Times,serif" font-size="14.00">v15 (mutable y$3 @ mutable y$3 = mutable x$2)</text>
137 +</g>
138 +<!-- v4&#45;&gt;v15 -->
139 +<g id="edge17" class="edge">
140 +<title>v4&#45;&gt;v15</title>
141 +<path fill="none" stroke="black" d="M1082.75,-412.03C1091.64,-400.61 1104.67,-386.23 1119.38,-377.6 1129.18,-371.84 1139.92,-367.03 1150.93,-363"/>
142 +<polygon fill="black" stroke="black" points="1152.35,-366.22 1160.67,-359.66 1150.08,-359.59 1152.35,-366.22"/>
143 +<text text-anchor="middle" x="1140.17" y="-381.8" font-family="Times,serif" font-size="14.00">capture</text>
144 +</g>
145 +<!-- v16 -->
146 +<g id="node17" class="node">
147 +<title>v16</title>
148 +<polygon fill="none" stroke="black" points="1213.29,-270.8 541.85,-270.8 541.85,-234.8 1213.29,-234.8 1213.29,-270.8"/>
149 +<text text-anchor="middle" x="877.57" y="-248.6" font-family="Times,serif" font-size="14.00">v16 (frozen child$6 @ frozen child$6 = JSX &lt;frozen Component$0 data={readonly x$2} &gt;&lt;/frozen Component$0&gt;)</text>
150 +</g>
151 +<!-- v5&#45;&gt;v16 -->
152 +<g id="edge23" class="edge">
153 +<title>v5&#45;&gt;v16</title>
154 +<path fill="none" stroke="black" d="M809.72,-323.56C808.25,-312.84 808.18,-299.14 814.38,-288.8 817.05,-284.34 820.51,-280.41 824.44,-276.95"/>
155 +<polygon fill="black" stroke="black" points="826.62,-279.7 832.48,-270.87 822.4,-274.11 826.62,-279.7"/>
156 +<text text-anchor="middle" x="835.17" y="-293" font-family="Times,serif" font-size="14.00">capture</text>
157 +</g>
158 +<!-- v17 -->
159 +<g id="node18" class="node">
160 +<title>v17</title>
161 +<polygon fill="none" stroke="black" points="916.1,-197.8 259.04,-197.8 259.04,-161.8 916.1,-161.8 916.1,-197.8"/>
162 +<text text-anchor="middle" x="587.57" y="-175.6" font-family="Times,serif" font-size="14.00">v17 (frozen child$6 @ JSX &lt;frozen Component$0 data={frozen y$3} &gt;{frozen child$6}&lt;/frozen Component$0&gt;)</text>
163 +</g>
164 +<!-- v5&#45;&gt;v17 -->
165 +<g id="edge29" class="edge">
166 +<title>v5&#45;&gt;v17</title>
167 +<path fill="none" stroke="black" d="M645.94,-323.58C578.57,-312.96 511.95,-296.3 491.38,-270.8 481.33,-258.35 483.29,-248.61 491.38,-234.8 499.39,-221.11 512.3,-210.62 526.08,-202.7"/>
168 +<polygon fill="black" stroke="black" points="528.03,-205.63 535.23,-197.86 524.75,-199.44 528.03,-205.63"/>
169 +<text text-anchor="middle" x="512.17" y="-248.6" font-family="Times,serif" font-size="14.00">capture</text>
170 +</g>
171 +<!-- v6 -->
172 +<g id="node7" class="node">
173 +<title>v6</title>
174 +<polygon fill="none" stroke="black" points="1677.67,-359.6 1423.48,-359.6 1423.48,-323.6 1677.67,-323.6 1677.67,-359.6"/>
175 +<text text-anchor="middle" x="1550.57" y="-337.4" font-family="Times,serif" font-size="14.00">v6 (frozen y$3 @ frozen y$3 = undefined)</text>
176 +</g>
177 +<!-- v7 -->
178 +<g id="node8" class="node">
179 +<title>v7</title>
180 +<polygon fill="none" stroke="black" points="1741.21,-270.8 1359.94,-270.8 1359.94,-234.8 1741.21,-234.8 1741.21,-270.8"/>
181 +<text text-anchor="middle" x="1550.57" y="-248.6" font-family="Times,serif" font-size="14.00">v7 (frozen y$3.push @ Call frozen y$3.push(frozen props$1.p4))</text>
182 +</g>
183 +<!-- v6&#45;&gt;v7 -->
184 +<g id="edge5" class="edge">
185 +<title>v6&#45;&gt;v7</title>
186 +<path fill="none" stroke="black" d="M1550.57,-323.45C1550.57,-311.32 1550.57,-294.82 1550.57,-280.92"/>
187 +<polygon fill="black" stroke="black" points="1554.07,-280.91 1550.57,-270.91 1547.07,-280.91 1554.07,-280.91"/>
188 +</g>
189 +<!-- v20 -->
190 +<g id="node21" class="node">
191 +<title>v20</title>
192 +<polygon fill="none" stroke="black" points="1868.61,-197.8 1232.53,-197.8 1232.53,-161.8 1868.61,-161.8 1868.61,-197.8"/>
193 +<text text-anchor="middle" x="1550.57" y="-175.6" font-family="Times,serif" font-size="14.00">v20 (frozen y$3 @ JSX &lt;frozen Component$0 data={frozen y$3} &gt;{frozen child$6}&lt;/frozen Component$0&gt;)</text>
194 +</g>
195 +<!-- v7&#45;&gt;v20 -->
196 +<g id="edge26" class="edge">
197 +<title>v7&#45;&gt;v20</title>
198 +<path fill="none" stroke="black" d="M1550.57,-234.61C1550.57,-226.59 1550.57,-216.85 1550.57,-207.87"/>
199 +<polygon fill="black" stroke="black" points="1554.07,-207.83 1550.57,-197.83 1547.07,-207.83 1554.07,-207.83"/>
200 +</g>
201 +<!-- v8 -->
202 +<g id="node9" class="node">
203 +<title>v8</title>
204 +<polygon fill="none" stroke="black" points="1724.62,-594.4 1514.53,-594.4 1514.53,-558.4 1724.62,-558.4 1724.62,-594.4"/>
205 +<text text-anchor="middle" x="1619.57" y="-572.2" font-family="Times,serif" font-size="14.00">v8 (frozen $4 @ frozen $4 = false)</text>
206 +</g>
207 +<!-- v9 -->
208 +<g id="node10" class="node">
209 +<title>v9</title>
210 +<polygon fill="none" stroke="black" points="1923.36,-521.4 1315.78,-521.4 1315.78,-485.4 1923.36,-485.4 1923.36,-521.4"/>
211 +<text text-anchor="middle" x="1619.57" y="-499.2" font-family="Times,serif" font-size="14.00">v9 (frozen $4 @ Switch (frozen props$1.p0); &#160;&#160;Case frozen $5: bb4; &#160;&#160;Case frozen $4: bb2; &#160;&#160;Default: bb1)</text>
212 +</g>
213 +<!-- v8&#45;&gt;v9 -->
214 +<g id="edge6" class="edge">
215 +<title>v8&#45;&gt;v9</title>
216 +<path fill="none" stroke="black" d="M1619.57,-558.21C1619.57,-550.19 1619.57,-540.45 1619.57,-531.47"/>
217 +<polygon fill="black" stroke="black" points="1623.07,-531.43 1619.57,-521.43 1616.07,-531.43 1623.07,-531.43"/>
218 +</g>
219 +<!-- v10 -->
220 +<g id="node11" class="node">
221 +<title>v10</title>
222 +<polygon fill="none" stroke="black" points="2354.95,-594.4 2142.19,-594.4 2142.19,-558.4 2354.95,-558.4 2354.95,-594.4"/>
223 +<text text-anchor="middle" x="2248.57" y="-572.2" font-family="Times,serif" font-size="14.00">v10 (frozen $5 @ frozen $5 = true)</text>
224 +</g>
225 +<!-- v11 -->
226 +<g id="node12" class="node">
227 +<title>v11</title>
228 +<polygon fill="none" stroke="black" points="2555.86,-521.4 1941.28,-521.4 1941.28,-485.4 2555.86,-485.4 2555.86,-521.4"/>
229 +<text text-anchor="middle" x="2248.57" y="-499.2" font-family="Times,serif" font-size="14.00">v11 (frozen $5 @ Switch (frozen props$1.p0); &#160;&#160;Case frozen $5: bb4; &#160;&#160;Case frozen $4: bb2; &#160;&#160;Default: bb1)</text>
230 +</g>
231 +<!-- v10&#45;&gt;v11 -->
232 +<g id="edge7" class="edge">
233 +<title>v10&#45;&gt;v11</title>
234 +<path fill="none" stroke="black" d="M2248.57,-558.21C2248.57,-550.19 2248.57,-540.45 2248.57,-531.47"/>
235 +<polygon fill="black" stroke="black" points="2252.07,-531.43 2248.57,-521.43 2245.07,-531.43 2252.07,-531.43"/>
236 +</g>
237 +<!-- v12&#45;&gt;v12 -->
238 +<g id="edge13" class="edge">
239 +<title>v12&#45;&gt;v12</title>
240 +<path fill="none" stroke="black" d="M409.42,-434.96C420.54,-433.84 427.14,-432.32 427.14,-430.4 427.14,-429.17 424.43,-428.1 419.56,-427.2"/>
241 +<polygon fill="black" stroke="black" points="419.8,-423.7 409.42,-425.84 418.87,-430.64 419.8,-423.7"/>
242 +</g>
243 +<!-- v12&#45;&gt;v13 -->
244 +<g id="edge14" class="edge">
245 +<title>v12&#45;&gt;v13</title>
246 +<path fill="none" stroke="black" d="M217.02,-412.25C226.16,-399.65 238.74,-382.32 249.07,-368.1"/>
247 +<polygon fill="black" stroke="black" points="252.11,-369.86 255.15,-359.71 246.44,-365.75 252.11,-369.86"/>
248 +</g>
249 +<!-- v14 -->
250 +<g id="node15" class="node">
251 +<title>v14</title>
252 +<polygon fill="none" stroke="black" points="1945.66,-359.6 1695.48,-359.6 1695.48,-323.6 1945.66,-323.6 1945.66,-359.6"/>
253 +<text text-anchor="middle" x="1820.57" y="-337.4" font-family="Times,serif" font-size="14.00">v14 (frozen y$3 @ frozen y$3 = Array [])</text>
254 +</g>
255 +<!-- v14&#45;&gt;v7 -->
256 +<g id="edge15" class="edge">
257 +<title>v14&#45;&gt;v7</title>
258 +<path fill="none" stroke="black" d="M1767.55,-323.55C1723.25,-309.31 1659.98,-288.97 1613.19,-273.93"/>
259 +<polygon fill="black" stroke="black" points="1614.06,-270.53 1603.47,-270.81 1611.92,-277.2 1614.06,-270.53"/>
260 +</g>
261 +<!-- v15&#45;&gt;v4 -->
262 +<g id="edge21" class="edge">
263 +<title>v15&#45;&gt;v4</title>
264 +<path fill="none" stroke="black" d="M1228.56,-359.62C1209.39,-370.2 1183.85,-383.76 1160.57,-394.4 1149.96,-399.25 1138.46,-404.05 1127.35,-408.47"/>
265 +<polygon fill="black" stroke="black" points="1125.74,-405.34 1117.71,-412.25 1128.3,-411.85 1125.74,-405.34"/>
266 +<text text-anchor="middle" x="1214.17" y="-381.8" font-family="Times,serif" font-size="14.00">capture</text>
267 +</g>
268 +<!-- v15&#45;&gt;v7 -->
269 +<g id="edge16" class="edge">
270 +<title>v15&#45;&gt;v7</title>
271 +<path fill="none" stroke="black" d="M1315.91,-323.55C1364.03,-309.25 1432.82,-288.8 1483.48,-273.74"/>
272 +<polygon fill="black" stroke="black" points="1484.77,-277.01 1493.36,-270.81 1482.78,-270.3 1484.77,-277.01"/>
273 +</g>
274 +<!-- v16&#45;&gt;v5 -->
275 +<g id="edge25" class="edge">
276 +<title>v16&#45;&gt;v5</title>
277 +<path fill="none" stroke="black" d="M872.5,-271.2C868.87,-281.8 863.26,-295.25 855.57,-305.6 852.68,-309.49 849.27,-313.22 845.67,-316.7"/>
278 +<polygon fill="black" stroke="black" points="843.22,-314.19 838.1,-323.47 847.89,-319.41 843.22,-314.19"/>
279 +<text text-anchor="middle" x="886.17" y="-293" font-family="Times,serif" font-size="14.00">capture</text>
280 +</g>
281 +<!-- v16&#45;&gt;v17 -->
282 +<g id="edge22" class="edge">
283 +<title>v16&#45;&gt;v17</title>
284 +<path fill="none" stroke="black" d="M808.11,-234.79C765.66,-224.4 711.22,-211.07 667.05,-200.26"/>
285 +<polygon fill="black" stroke="black" points="667.77,-196.83 657.22,-197.85 666.1,-203.63 667.77,-196.83"/>
286 +</g>
287 +<!-- v21 -->
288 +<g id="node22" class="node">
289 +<title>v21</title>
290 +<polygon fill="none" stroke="black" points="872.26,-109 174.88,-109 174.88,-73 872.26,-73 872.26,-109"/>
291 +<text text-anchor="middle" x="523.57" y="-86.8" font-family="Times,serif" font-size="14.00">v21 (frozen $7 @ frozen $7 = JSX &lt;frozen Component$0 data={frozen y$3} &gt;{frozen child$6}&lt;/frozen Component$0&gt;)</text>
292 +</g>
293 +<!-- v17&#45;&gt;v21 -->
294 +<g id="edge28" class="edge">
295 +<title>v17&#45;&gt;v21</title>
296 +<path fill="none" stroke="black" d="M582.5,-161.4C578.87,-150.8 573.26,-137.35 565.57,-127 562.68,-123.11 559.27,-119.38 555.67,-115.9"/>
297 +<polygon fill="black" stroke="black" points="557.89,-113.19 548.1,-109.13 553.22,-118.41 557.89,-113.19"/>
298 +<text text-anchor="middle" x="596.17" y="-131.2" font-family="Times,serif" font-size="14.00">capture</text>
299 +</g>
300 +<!-- v22 -->
301 +<g id="node23" class="node">
302 +<title>v22</title>
303 +<polygon fill="none" stroke="black" points="824.4,-36 606.75,-36 606.75,0 824.4,0 824.4,-36"/>
304 +<text text-anchor="middle" x="715.57" y="-13.8" font-family="Times,serif" font-size="14.00">v22 (frozen $7 @ Return frozen $7)</text>
305 +</g>
306 +<!-- v17&#45;&gt;v22 -->
307 +<g id="edge31" class="edge">
308 +<title>v17&#45;&gt;v22</title>
309 +<path fill="none" stroke="black" d="M730.6,-161.75C795.41,-150.79 861.93,-133.85 881.57,-109 907.92,-75.67 865.04,-53.02 816.27,-38.78"/>
310 +<polygon fill="black" stroke="black" points="817.03,-35.35 806.46,-36.04 815.15,-42.1 817.03,-35.35"/>
311 +<text text-anchor="middle" x="911.17" y="-86.8" font-family="Times,serif" font-size="14.00">capture</text>
312 +</g>
313 +<!-- v18 -->
314 +<g id="node19" class="node">
315 +<title>v18</title>
316 +<polygon fill="none" stroke="black" points="3227.98,-594.4 2615.16,-594.4 2615.16,-558.4 3227.98,-558.4 3227.98,-594.4"/>
317 +<text text-anchor="middle" x="2921.57" y="-572.2" font-family="Times,serif" font-size="14.00">v18 (frozen Component$0 @ JSX &lt;frozen Component$0 data={readonly x$2} &gt;&lt;/frozen Component$0&gt;)</text>
318 +</g>
319 +<!-- v19 -->
320 +<g id="node20" class="node">
321 +<title>v19</title>
322 +<polygon fill="none" stroke="black" points="3268.94,-521.4 2574.2,-521.4 2574.2,-485.4 3268.94,-485.4 3268.94,-521.4"/>
323 +<text text-anchor="middle" x="2921.57" y="-499.2" font-family="Times,serif" font-size="14.00">v19 (frozen Component$0 @ JSX &lt;frozen Component$0 data={frozen y$3} &gt;{frozen child$6}&lt;/frozen Component$0&gt;)</text>
324 +</g>
325 +<!-- v18&#45;&gt;v19 -->
326 +<g id="edge24" class="edge">
327 +<title>v18&#45;&gt;v19</title>
328 +<path fill="none" stroke="black" d="M2921.57,-558.21C2921.57,-550.19 2921.57,-540.45 2921.57,-531.47"/>
329 +<polygon fill="black" stroke="black" points="2925.07,-531.43 2921.57,-521.43 2918.07,-531.43 2925.07,-531.43"/>
330 +</g>
331 +<!-- v21&#45;&gt;v17 -->
332 +<g id="edge30" class="edge">
333 +<title>v21&#45;&gt;v17</title>
334 +<path fill="none" stroke="black" d="M517.82,-109.05C515.28,-119.77 514.12,-133.48 520.38,-143.8 523.08,-148.25 526.55,-152.17 530.5,-155.6"/>
335 +<polygon fill="black" stroke="black" points="528.47,-158.46 538.58,-161.63 532.66,-152.85 528.47,-158.46"/>
336 +<text text-anchor="middle" x="541.17" y="-131.2" font-family="Times,serif" font-size="14.00">capture</text>
337 +</g>
338 +<!-- v21&#45;&gt;v22 -->
339 +<g id="edge27" class="edge">
340 +<title>v21&#45;&gt;v22</title>
341 +<path fill="none" stroke="black" d="M569.56,-72.99C596.67,-62.97 631.16,-50.21 659.82,-39.62"/>
342 +<polygon fill="black" stroke="black" points="661.13,-42.86 669.29,-36.11 658.7,-36.3 661.13,-42.86"/>
343 +</g>
344 +</g>
345 +</svg>
compiler/forget/src/__tests__/fixtures/hir/call.expect.md new
+61
@@ -0,0 +1,61 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo() {}
6 +
7 +function Component(props) {
8 + const a = [];
9 + const b = {};
10 + foo(a, b);
11 + let _ = <div a={a} />;
12 + foo(b);
13 + return <div a={a} b={b} />;
14 +}
15 +
16 +```
17 +
18 +## HIR
19 +
20 +```
21 +bb0:
22 + Return
23 +```
24 +
25 +## Code
26 +
27 +```javascript
28 +function foo$0() {
29 + return;
30 +}
31 +
32 +```
33 +## HIR
34 +
35 +```
36 +bb0:
37 + mutable a$2 = Array []
38 + mutable b$3 = Object { }
39 + Call mutable foo$4(mutable a$2, mutable b$3)
40 + frozen $6 = "div"
41 + mutable _$5 = JSX <frozen $6 a={mutable a$2} ></frozen $6>
42 + Call mutable foo$4(mutable b$3)
43 + frozen $7 = "div"
44 + frozen $8 = JSX <frozen $7 a={readonly a$2} b={readonly b$3} ></frozen $7>
45 + Return frozen $8
46 +```
47 +
48 +## Code
49 +
50 +```javascript
51 +function Component$0(props$1) {
52 + a$2 = [];
53 + b$3 = {};
54 + foo$4(a$2, b$3);
55 + _$5 = <div a={a$2}></div>;
56 + foo$4(b$3);
57 + return <div a={a$2} b={b$3}></div>;
58 +}
59 +
60 +```
61 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/call.js new
+10
@@ -0,0 +1,10 @@
1 +function foo() {}
2 +
3 +function Component(props) {
4 + const a = [];
5 + const b = {};
6 + foo(a, b);
7 + let _ = <div a={a} />;
8 + foo(b);
9 + return <div a={a} b={b} />;
10 +}
compiler/forget/src/__tests__/fixtures/hir/component.expect.md new
+91
@@ -0,0 +1,91 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + const items = props.items;
7 + const maxItems = props.maxItems;
8 +
9 + const renderedItems = [];
10 + const seen = new Set();
11 + const max = Math.max(0, maxItems);
12 + for (const item of items) {
13 + if (item == null || seen.has(item)) {
14 + continue;
15 + }
16 + seen.add(item);
17 + renderedItems.push(<div>{item}</div>);
18 + if (renderedItems.length >= max) {
19 + break;
20 + }
21 + }
22 + const count = renderedItems.length;
23 + return (
24 + <div>
25 + <h1>{count} Items</h1>
26 + {renderedItems}
27 + </div>
28 + );
29 +}
30 +
31 +```
32 +
33 +## HIR
34 +
35 +```
36 +bb0:
37 + frozen items$2 = frozen props$1.items
38 + frozen maxItems$3 = frozen props$1.maxItems
39 + mutable renderedItems$4 = Array []
40 + mutable seen$5 = New mutable Set$6()
41 + frozen $9 = 0
42 + frozen max$7 = Call mutable Math$8.max(frozen $9, frozen maxItems$3)
43 + Goto bb1
44 +bb1:
45 + If (frozen items$2) then:bb3 else:bb2
46 +bb3:
47 + frozen $11 = null
48 + frozen $12 = Binary mutable item$10 == frozen $11
49 + If (frozen $12) then:bb8 else:bb9
50 +bb2:
51 + frozen count$17 = readonly renderedItems$4.length
52 + frozen $18 = "div"
53 + frozen $19 = "\n "
54 + frozen $20 = "h1"
55 + frozen $21 = " Items"
56 + frozen $22 = JSX <frozen $20>{frozen count$17}{frozen $21}</frozen $20>
57 + frozen $23 = "\n "
58 + frozen $24 = "\n "
59 + frozen $25 = JSX <frozen $18>{frozen $19}{frozen $22}{frozen $23}{readonly renderedItems$4}{frozen $24}</frozen $18>
60 + Return frozen $25
61 +bb8:
62 + frozen $13 = frozen $12
63 + Goto bb7
64 +bb9:
65 + mutable $13 = Call mutable seen$5.has(mutable item$10)
66 + Goto bb7
67 +bb7:
68 + If (frozen $13) then:bb1 else:bb4
69 +bb4:
70 + Call mutable seen$5.add(mutable item$10)
71 + frozen $14 = "div"
72 + mutable $15 = JSX <frozen $14>{mutable item$10}</frozen $14>
73 + Call mutable renderedItems$4.push(mutable $15)
74 + frozen $16 = Binary mutable renderedItems$4.length >= frozen max$7
75 + If (frozen $16) then:bb2 else:bb1
76 +```
77 +
78 +## Code
79 +
80 +```javascript
81 +function Component$0(props$1) {
82 + items$2 = props$1.items;
83 + maxItems$3 = props$1.maxItems;
84 + renderedItems$4 = [];
85 + seen$5 = new Set$6();
86 + max$7 = Math$8.max(0, maxItems$3);
87 + ("<<TODO: handle complex control flow in codegen>>");
88 +}
89 +
90 +```
91 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/component.js new
+25
@@ -0,0 +1,25 @@
1 +function Component(props) {
2 + const items = props.items;
3 + const maxItems = props.maxItems;
4 +
5 + const renderedItems = [];
6 + const seen = new Set();
7 + const max = Math.max(0, maxItems);
8 + for (const item of items) {
9 + if (item == null || seen.has(item)) {
10 + continue;
11 + }
12 + seen.add(item);
13 + renderedItems.push(<div>{item}</div>);
14 + if (renderedItems.length >= max) {
15 + break;
16 + }
17 + }
18 + const count = renderedItems.length;
19 + return (
20 + <div>
21 + <h1>{count} Items</h1>
22 + {renderedItems}
23 + </div>
24 + );
25 +}
compiler/forget/src/__tests__/fixtures/hir/conditional-break.expect.md new
+232
@@ -0,0 +1,232 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +/**
6 + * props.b does *not* influence `a`
7 + */
8 +function Component(props) {
9 + const a_DEBUG = [];
10 + a_DEBUG.push(props.a);
11 + if (props.b) {
12 + return null;
13 + }
14 + a_DEBUG.push(props.d);
15 + return a_DEBUG;
16 +}
17 +
18 +/**
19 + * props.b *does* influence `a`
20 + */
21 +function Component(props) {
22 + const a = [];
23 + a.push(props.a);
24 + if (props.b) {
25 + a.push(props.c);
26 + }
27 + a.push(props.d);
28 + return a;
29 +}
30 +
31 +/**
32 + * props.b *does* influence `a`, but only in a way that is never observable
33 + */
34 +function Component(props) {
35 + const a = [];
36 + a.push(props.a);
37 + if (props.b) {
38 + a.push(props.c);
39 + return null;
40 + }
41 + a.push(props.d);
42 + return a;
43 +}
44 +
45 +/**
46 + * props.b *does* influence `a`
47 + */
48 +function Component(props) {
49 + const a = [];
50 + a.push(props.a);
51 + if (props.b) {
52 + a.push(props.c);
53 + return a;
54 + }
55 + a.push(props.d);
56 + return a;
57 +}
58 +
59 +/**
60 + * props.b *does* influence `a`
61 + */
62 +function Component(props) {
63 + const a = [];
64 + a.push(props.a);
65 + label: {
66 + if (props.b) {
67 + break label;
68 + }
69 + a.push(props.c);
70 + }
71 + a.push(props.d);
72 + return a;
73 +}
74 +
75 +```
76 +
77 +## HIR
78 +
79 +```
80 +bb0:
81 + mutable a_DEBUG$2 = Array []
82 + Call mutable a_DEBUG$2.push(frozen props$1.a)
83 + If (frozen props$1.b) then:bb2 else:bb1
84 +bb2:
85 + frozen $3 = null
86 + Return frozen $3
87 +bb1:
88 + Call mutable a_DEBUG$2.push(frozen props$1.d)
89 + Return frozen a_DEBUG$2
90 +```
91 +
92 +## Code
93 +
94 +```javascript
95 +function Component$0(props$1) {
96 + a_DEBUG$2 = [];
97 + a_DEBUG$2.push(props$1.a);
98 + if (props$1.b) {
99 + return null;
100 + }
101 +
102 + a_DEBUG$2.push(props$1.d);
103 + return a_DEBUG$2;
104 +}
105 +
106 +```
107 +## HIR
108 +
109 +```
110 +bb0:
111 + mutable a$2 = Array []
112 + Call mutable a$2.push(frozen props$1.a)
113 + If (frozen props$1.b) then:bb2 else:bb1
114 +bb2:
115 + Call mutable a$2.push(frozen props$1.c)
116 + Goto bb1
117 +bb1:
118 + Call mutable a$2.push(frozen props$1.d)
119 + Return frozen a$2
120 +```
121 +
122 +## Code
123 +
124 +```javascript
125 +function Component$0(props$1) {
126 + a$2 = [];
127 + a$2.push(props$1.a);
128 + if (props$1.b) {
129 + a$2.push(props$1.c);
130 + ("<<TODO: handle complex control flow in codegen>>");
131 + }
132 +
133 + a$2.push(props$1.d);
134 + return a$2;
135 +}
136 +
137 +```
138 +## HIR
139 +
140 +```
141 +bb0:
142 + mutable a$2 = Array []
143 + Call mutable a$2.push(frozen props$1.a)
144 + If (frozen props$1.b) then:bb2 else:bb1
145 +bb2:
146 + Call mutable a$2.push(frozen props$1.c)
147 + frozen $3 = null
148 + Return frozen $3
149 +bb1:
150 + Call mutable a$2.push(frozen props$1.d)
151 + Return frozen a$2
152 +```
153 +
154 +## Code
155 +
156 +```javascript
157 +function Component$0(props$1) {
158 + a$2 = [];
159 + a$2.push(props$1.a);
160 + if (props$1.b) {
161 + a$2.push(props$1.c);
162 + return null;
163 + }
164 +
165 + a$2.push(props$1.d);
166 + return a$2;
167 +}
168 +
169 +```
170 +## HIR
171 +
172 +```
173 +bb0:
174 + mutable a$2 = Array []
175 + Call mutable a$2.push(frozen props$1.a)
176 + If (frozen props$1.b) then:bb2 else:bb1
177 +bb2:
178 + Call mutable a$2.push(frozen props$1.c)
179 + Return frozen a$2
180 +bb1:
181 + Call mutable a$2.push(frozen props$1.d)
182 + Return frozen a$2
183 +```
184 +
185 +## Code
186 +
187 +```javascript
188 +function Component$0(props$1) {
189 + a$2 = [];
190 + a$2.push(props$1.a);
191 + if (props$1.b) {
192 + a$2.push(props$1.c);
193 + return a$2;
194 + }
195 +
196 + a$2.push(props$1.d);
197 + return a$2;
198 +}
199 +
200 +```
201 +## HIR
202 +
203 +```
204 +bb0:
205 + mutable a$2 = Array []
206 + Call mutable a$2.push(frozen props$1.a)
207 + If (frozen props$1.b) then:bb1 else:bb2
208 +bb1:
209 + Call mutable a$2.push(frozen props$1.d)
210 + Return frozen a$2
211 +bb2:
212 + Call mutable a$2.push(frozen props$1.c)
213 + Goto bb1
214 +```
215 +
216 +## Code
217 +
218 +```javascript
219 +function Component$0(props$1) {
220 + a$2 = [];
221 + a$2.push(props$1.a);
222 + if (props$1.b) {
223 + a$2.push(props$1.d);
224 + return a$2;
225 + }
226 +
227 + a$2.push(props$1.c);
228 + ("<<TODO: handle complex control flow in codegen>>");
229 +}
230 +
231 +```
232 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/conditional-break.js new
+69
@@ -0,0 +1,69 @@
1 +/**
2 + * props.b does *not* influence `a`
3 + */
4 +function Component(props) {
5 + const a_DEBUG = [];
6 + a_DEBUG.push(props.a);
7 + if (props.b) {
8 + return null;
9 + }
10 + a_DEBUG.push(props.d);
11 + return a_DEBUG;
12 +}
13 +
14 +/**
15 + * props.b *does* influence `a`
16 + */
17 +function Component(props) {
18 + const a = [];
19 + a.push(props.a);
20 + if (props.b) {
21 + a.push(props.c);
22 + }
23 + a.push(props.d);
24 + return a;
25 +}
26 +
27 +/**
28 + * props.b *does* influence `a`, but only in a way that is never observable
29 + */
30 +function Component(props) {
31 + const a = [];
32 + a.push(props.a);
33 + if (props.b) {
34 + a.push(props.c);
35 + return null;
36 + }
37 + a.push(props.d);
38 + return a;
39 +}
40 +
41 +/**
42 + * props.b *does* influence `a`
43 + */
44 +function Component(props) {
45 + const a = [];
46 + a.push(props.a);
47 + if (props.b) {
48 + a.push(props.c);
49 + return a;
50 + }
51 + a.push(props.d);
52 + return a;
53 +}
54 +
55 +/**
56 + * props.b *does* influence `a`
57 + */
58 +function Component(props) {
59 + const a = [];
60 + a.push(props.a);
61 + label: {
62 + if (props.b) {
63 + break label;
64 + }
65 + a.push(props.c);
66 + }
67 + a.push(props.d);
68 + return a;
69 +}
compiler/forget/src/__tests__/fixtures/hir/conditional-on-mutable.expect.md new
+177
@@ -0,0 +1,177 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +// function Component$forget(props) {
6 +// scope_a: {
7 +// const a = [];
8 +// if (b) {
9 +// a.push(props.p0);
10 +// }
11 +// }
12 +// scope_b: {
13 +// const b = [];
14 +// if (props.p1) {
15 +// b.push(props.p2);
16 +// }
17 +// }
18 +// scope_return: {
19 +// return <Foo a={a} b={b} />;
20 +// }
21 +// }
22 +function Component(props) {
23 + const a = [];
24 + const b = [];
25 + if (b) {
26 + a.push(props.p0);
27 + }
28 + if (props.p1) {
29 + b.push(props.p2);
30 + }
31 + return <Foo a={a} b={b} />;
32 +}
33 +
34 +// function Component$forget(props) {
35 +// scope_a_b: {
36 +// const a = [];
37 +// const b = [];
38 +// if (mayMutate(b)) {
39 +// a.push(props.p0);
40 +// }
41 +// if (props.p1) {
42 +// b.push(props.p2);
43 +// }
44 +// }
45 +// scope_return: {
46 +// return <Foo a={a} b={b} />;
47 +// }
48 +// }
49 +function Component(props) {
50 + const a = [];
51 + const b = [];
52 + if (mayMutate(b)) {
53 + a.push(props.p0);
54 + }
55 + if (props.p1) {
56 + b.push(props.p2);
57 + }
58 + return <Foo a={a} b={b} />;
59 +}
60 +
61 +function Foo() {}
62 +function mayMutate() {}
63 +
64 +```
65 +
66 +## HIR
67 +
68 +```
69 +bb0:
70 + mutable a$2 = Array []
71 + mutable b$3 = Array []
72 + If (mutable b$3) then:bb2 else:bb1
73 +bb2:
74 + Call mutable a$2.push(frozen props$1.p0)
75 + Goto bb1
76 +bb1:
77 + If (frozen props$1.p1) then:bb4 else:bb3
78 +bb4:
79 + Call mutable b$3.push(frozen props$1.p2)
80 + Goto bb3
81 +bb3:
82 + frozen $5 = JSX <frozen Foo$4 a={readonly a$2} b={readonly b$3} ></frozen Foo$4>
83 + Return frozen $5
84 +```
85 +
86 +## Code
87 +
88 +```javascript
89 +function Component$0(props$1) {
90 + a$2 = [];
91 + b$3 = [];
92 + if (b$3) {
93 + a$2.push(props$1.p0);
94 + ("<<TODO: handle complex control flow in codegen>>");
95 + }
96 +
97 + if (props$1.p1) {
98 + b$3.push(props$1.p2);
99 + ("<<TODO: handle complex control flow in codegen>>");
100 + }
101 +
102 + return <Foo$4 a={a$2} b={b$3}></Foo$4>;
103 +}
104 +
105 +```
106 +## HIR
107 +
108 +```
109 +bb0:
110 + mutable a$2 = Array []
111 + mutable b$3 = Array []
112 + mutable $5 = Call mutable mayMutate$4(mutable b$3)
113 + If (mutable $5) then:bb2 else:bb1
114 +bb2:
115 + Call mutable a$2.push(frozen props$1.p0)
116 + Goto bb1
117 +bb1:
118 + If (frozen props$1.p1) then:bb4 else:bb3
119 +bb4:
120 + Call mutable b$3.push(frozen props$1.p2)
121 + Goto bb3
122 +bb3:
123 + frozen $7 = JSX <frozen Foo$6 a={readonly a$2} b={readonly b$3} ></frozen Foo$6>
124 + Return frozen $7
125 +```
126 +
127 +## Code
128 +
129 +```javascript
130 +function Component$0(props$1) {
131 + a$2 = [];
132 + b$3 = [];
133 + if (mayMutate$4(b$3)) {
134 + a$2.push(props$1.p0);
135 + ("<<TODO: handle complex control flow in codegen>>");
136 + }
137 +
138 + if (props$1.p1) {
139 + b$3.push(props$1.p2);
140 + ("<<TODO: handle complex control flow in codegen>>");
141 + }
142 +
143 + return <Foo$6 a={a$2} b={b$3}></Foo$6>;
144 +}
145 +
146 +```
147 +## HIR
148 +
149 +```
150 +bb0:
151 + Return
152 +```
153 +
154 +## Code
155 +
156 +```javascript
157 +function Foo$0() {
158 + return;
159 +}
160 +
161 +```
162 +## HIR
163 +
164 +```
165 +bb0:
166 + Return
167 +```
168 +
169 +## Code
170 +
171 +```javascript
172 +function mayMutate$0() {
173 + return;
174 +}
175 +
176 +```
177 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/conditional-on-mutable.js new
+58
@@ -0,0 +1,58 @@
1 +// function Component$forget(props) {
2 +// scope_a: {
3 +// const a = [];
4 +// if (b) {
5 +// a.push(props.p0);
6 +// }
7 +// }
8 +// scope_b: {
9 +// const b = [];
10 +// if (props.p1) {
11 +// b.push(props.p2);
12 +// }
13 +// }
14 +// scope_return: {
15 +// return <Foo a={a} b={b} />;
16 +// }
17 +// }
18 +function Component(props) {
19 + const a = [];
20 + const b = [];
21 + if (b) {
22 + a.push(props.p0);
23 + }
24 + if (props.p1) {
25 + b.push(props.p2);
26 + }
27 + return <Foo a={a} b={b} />;
28 +}
29 +
30 +// function Component$forget(props) {
31 +// scope_a_b: {
32 +// const a = [];
33 +// const b = [];
34 +// if (mayMutate(b)) {
35 +// a.push(props.p0);
36 +// }
37 +// if (props.p1) {
38 +// b.push(props.p2);
39 +// }
40 +// }
41 +// scope_return: {
42 +// return <Foo a={a} b={b} />;
43 +// }
44 +// }
45 +function Component(props) {
46 + const a = [];
47 + const b = [];
48 + if (mayMutate(b)) {
49 + a.push(props.p0);
50 + }
51 + if (props.p1) {
52 + b.push(props.p2);
53 + }
54 + return <Foo a={a} b={b} />;
55 +}
56 +
57 +function Foo() {}
58 +function mayMutate() {}
compiler/forget/src/__tests__/fixtures/hir/constructor.expect.md new
+61
@@ -0,0 +1,61 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Foo() {}
6 +
7 +function Component(props) {
8 + const a = [];
9 + const b = {};
10 + new Foo(a, b);
11 + let _ = <div a={a} />;
12 + new Foo(b);
13 + return <div a={a} b={b} />;
14 +}
15 +
16 +```
17 +
18 +## HIR
19 +
20 +```
21 +bb0:
22 + Return
23 +```
24 +
25 +## Code
26 +
27 +```javascript
28 +function Foo$0() {
29 + return;
30 +}
31 +
32 +```
33 +## HIR
34 +
35 +```
36 +bb0:
37 + mutable a$2 = Array []
38 + mutable b$3 = Object { }
39 + New mutable Foo$4(mutable a$2, mutable b$3)
40 + frozen $6 = "div"
41 + mutable _$5 = JSX <frozen $6 a={mutable a$2} ></frozen $6>
42 + New mutable Foo$4(mutable b$3)
43 + frozen $7 = "div"
44 + frozen $8 = JSX <frozen $7 a={readonly a$2} b={readonly b$3} ></frozen $7>
45 + Return frozen $8
46 +```
47 +
48 +## Code
49 +
50 +```javascript
51 +function Component$0(props$1) {
52 + a$2 = [];
53 + b$3 = {};
54 + new Foo$4(a$2, b$3);
55 + _$5 = <div a={a$2}></div>;
56 + new Foo$4(b$3);
57 + return <div a={a$2} b={b$3}></div>;
58 +}
59 +
60 +```
61 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/constructor.js new
+10
@@ -0,0 +1,10 @@
1 +function Foo() {}
2 +
3 +function Component(props) {
4 + const a = [];
5 + const b = {};
6 + new Foo(a, b);
7 + let _ = <div a={a} />;
8 + new Foo(b);
9 + return <div a={a} b={b} />;
10 +}
compiler/forget/src/__tests__/fixtures/hir/hook-call.expect.md new
+82
@@ -0,0 +1,82 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function useFreeze() {}
6 +function foo() {}
7 +
8 +function Component(props) {
9 + const x = [];
10 + const y = useFreeze(x);
11 + foo(y, x);
12 + return (
13 + <Component>
14 + {x}
15 + {y}
16 + </Component>
17 + );
18 +}
19 +
20 +```
21 +
22 +## HIR
23 +
24 +```
25 +bb0:
26 + Return
27 +```
28 +
29 +## Code
30 +
31 +```javascript
32 +function useFreeze$0() {
33 + return;
34 +}
35 +
36 +```
37 +## HIR
38 +
39 +```
40 +bb0:
41 + Return
42 +```
43 +
44 +## Code
45 +
46 +```javascript
47 +function foo$0() {
48 + return;
49 +}
50 +
51 +```
52 +## HIR
53 +
54 +```
55 +bb0:
56 + frozen x$2 = Array []
57 + frozen y$3 = Call frozen useFreeze$4(frozen x$2)
58 + Call mutable foo$5(frozen y$3, frozen x$2)
59 + frozen $6 = "\n "
60 + frozen $7 = "\n "
61 + frozen $8 = "\n "
62 + frozen $9 = JSX <frozen Component$0>{frozen $6}{frozen x$2}{frozen $7}{frozen y$3}{frozen $8}</frozen Component$0>
63 + Return frozen $9
64 +```
65 +
66 +## Code
67 +
68 +```javascript
69 +function Component$0(props$1) {
70 + x$2 = [];
71 + y$3 = useFreeze$4(x$2);
72 + foo$5(y$3, x$2);
73 + return (
74 + <Component$0>
75 + {x$2}
76 + {y$3}
77 + </Component$0>
78 + );
79 +}
80 +
81 +```
82 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/hook-call.js new
+14
@@ -0,0 +1,14 @@
1 +function useFreeze() {}
2 +function foo() {}
3 +
4 +function Component(props) {
5 + const x = [];
6 + const y = useFreeze(x);
7 + foo(y, x);
8 + return (
9 + <Component>
10 + {x}
11 + {y}
12 + </Component>
13 + );
14 +}
compiler/forget/src/__tests__/fixtures/hir/independent-across-if.expect.md new
+128
@@ -0,0 +1,128 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function compute() {}
6 +function mutate() {}
7 +function foo() {}
8 +function Foo() {}
9 +
10 +/**
11 + * Should produce 3 scopes:
12 + *
13 + * a: inputs=props.a & props.c; outputs=a
14 + * a = compute(props.a);
15 + * if (props.c)
16 + * mutate(a)
17 + * b: inputs=props.b & props.c; outputs=b
18 + * b = compute(props.b);
19 + * if (props.c)
20 + * mutate(b)
21 + * return: inputs=a, b outputs=return
22 + * return = <Foo a={a} b={b} />
23 + */
24 +function Component(props) {
25 + const a = compute(props.a);
26 + const b = compute(props.b);
27 + if (props.c) {
28 + mutate(a);
29 + mutate(b);
30 + }
31 + return <Foo a={a} b={b} />;
32 +}
33 +
34 +```
35 +
36 +## HIR
37 +
38 +```
39 +bb0:
40 + Return
41 +```
42 +
43 +## Code
44 +
45 +```javascript
46 +function compute$0() {
47 + return;
48 +}
49 +
50 +```
51 +## HIR
52 +
53 +```
54 +bb0:
55 + Return
56 +```
57 +
58 +## Code
59 +
60 +```javascript
61 +function mutate$0() {
62 + return;
63 +}
64 +
65 +```
66 +## HIR
67 +
68 +```
69 +bb0:
70 + Return
71 +```
72 +
73 +## Code
74 +
75 +```javascript
76 +function foo$0() {
77 + return;
78 +}
79 +
80 +```
81 +## HIR
82 +
83 +```
84 +bb0:
85 + Return
86 +```
87 +
88 +## Code
89 +
90 +```javascript
91 +function Foo$0() {
92 + return;
93 +}
94 +
95 +```
96 +## HIR
97 +
98 +```
99 +bb0:
100 + mutable a$2 = Call mutable compute$3(frozen props$1.a)
101 + mutable b$4 = Call mutable compute$3(frozen props$1.b)
102 + If (frozen props$1.c) then:bb2 else:bb1
103 +bb2:
104 + Call mutable mutate$5(mutable a$2)
105 + Call mutable mutate$5(mutable b$4)
106 + Goto bb1
107 +bb1:
108 + frozen $7 = JSX <frozen Foo$6 a={readonly a$2} b={readonly b$4} ></frozen Foo$6>
109 + Return frozen $7
110 +```
111 +
112 +## Code
113 +
114 +```javascript
115 +function Component$0(props$1) {
116 + a$2 = compute$3(props$1.a);
117 + b$4 = compute$3(props$1.b);
118 + if (props$1.c) {
119 + mutate$5(a$2);
120 + mutate$5(b$4);
121 + ("<<TODO: handle complex control flow in codegen>>");
122 + }
123 +
124 + return <Foo$6 a={a$2} b={b$4}></Foo$6>;
125 +}
126 +
127 +```
128 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/independent-across-if.js new
+28
@@ -0,0 +1,28 @@
1 +function compute() {}
2 +function mutate() {}
3 +function foo() {}
4 +function Foo() {}
5 +
6 +/**
7 + * Should produce 3 scopes:
8 + *
9 + * a: inputs=props.a & props.c; outputs=a
10 + * a = compute(props.a);
11 + * if (props.c)
12 + * mutate(a)
13 + * b: inputs=props.b & props.c; outputs=b
14 + * b = compute(props.b);
15 + * if (props.c)
16 + * mutate(b)
17 + * return: inputs=a, b outputs=return
18 + * return = <Foo a={a} b={b} />
19 + */
20 +function Component(props) {
21 + const a = compute(props.a);
22 + const b = compute(props.b);
23 + if (props.c) {
24 + mutate(a);
25 + mutate(b);
26 + }
27 + return <Foo a={a} b={b} />;
28 +}
compiler/forget/src/__tests__/fixtures/hir/independent.expect.md new
+92
@@ -0,0 +1,92 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +/**
6 + * Should produce 3 scopes:
7 + *
8 + * a: inputs=props.a, outputs=a
9 + * a = compute(props.a);
10 + * b: inputs=props.b, outputs=b
11 + * b = compute(props.b);
12 + * return: inputs=a, b outputs=return
13 + * return = <Foo a={a} b={b} />
14 + */
15 +function Component(props) {
16 + const a = compute(props.a);
17 + const b = compute(props.b);
18 + return <Foo a={a} b={b} />;
19 +}
20 +
21 +function compute() {}
22 +function foo() {}
23 +function Foo() {}
24 +
25 +```
26 +
27 +## HIR
28 +
29 +```
30 +bb0:
31 + frozen a$2 = Call mutable compute$3(frozen props$1.a)
32 + frozen b$4 = Call mutable compute$3(frozen props$1.b)
33 + frozen $6 = JSX <frozen Foo$5 a={frozen a$2} b={frozen b$4} ></frozen Foo$5>
34 + Return frozen $6
35 +```
36 +
37 +## Code
38 +
39 +```javascript
40 +function Component$0(props$1) {
41 + a$2 = compute$3(props$1.a);
42 + b$4 = compute$3(props$1.b);
43 + return <Foo$5 a={a$2} b={b$4}></Foo$5>;
44 +}
45 +
46 +```
47 +## HIR
48 +
49 +```
50 +bb0:
51 + Return
52 +```
53 +
54 +## Code
55 +
56 +```javascript
57 +function compute$0() {
58 + return;
59 +}
60 +
61 +```
62 +## HIR
63 +
64 +```
65 +bb0:
66 + Return
67 +```
68 +
69 +## Code
70 +
71 +```javascript
72 +function foo$0() {
73 + return;
74 +}
75 +
76 +```
77 +## HIR
78 +
79 +```
80 +bb0:
81 + Return
82 +```
83 +
84 +## Code
85 +
86 +```javascript
87 +function Foo$0() {
88 + return;
89 +}
90 +
91 +```
92 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/independent.js new
+19
@@ -0,0 +1,19 @@
1 +/**
2 + * Should produce 3 scopes:
3 + *
4 + * a: inputs=props.a, outputs=a
5 + * a = compute(props.a);
6 + * b: inputs=props.b, outputs=b
7 + * b = compute(props.b);
8 + * return: inputs=a, b outputs=return
9 + * return = <Foo a={a} b={b} />
10 + */
11 +function Component(props) {
12 + const a = compute(props.a);
13 + const b = compute(props.b);
14 + return <Foo a={a} b={b} />;
15 +}
16 +
17 +function compute() {}
18 +function foo() {}
19 +function Foo() {}
compiler/forget/src/__tests__/fixtures/hir/interdependent-across-if.expect.md new
+105
@@ -0,0 +1,105 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function compute() {}
6 +function foo() {}
7 +function Foo() {}
8 +
9 +/**
10 + * Should produce 1 scope:
11 + *
12 + * return: inputs=props.a & props.b & props.c; outputs=return
13 + * const a = compute(props.a);
14 + * const b = compute(props.b);
15 + * if (props.c)
16 + * foo(a, b);
17 + * return = <Foo a={a} b={b} />
18 + */
19 +function Component(props) {
20 + const a = compute(props.a);
21 + const b = compute(props.b);
22 + if (props.c) {
23 + foo(a, b);
24 + }
25 + return <Foo a={a} b={b} />;
26 +}
27 +
28 +```
29 +
30 +## HIR
31 +
32 +```
33 +bb0:
34 + Return
35 +```
36 +
37 +## Code
38 +
39 +```javascript
40 +function compute$0() {
41 + return;
42 +}
43 +
44 +```
45 +## HIR
46 +
47 +```
48 +bb0:
49 + Return
50 +```
51 +
52 +## Code
53 +
54 +```javascript
55 +function foo$0() {
56 + return;
57 +}
58 +
59 +```
60 +## HIR
61 +
62 +```
63 +bb0:
64 + Return
65 +```
66 +
67 +## Code
68 +
69 +```javascript
70 +function Foo$0() {
71 + return;
72 +}
73 +
74 +```
75 +## HIR
76 +
77 +```
78 +bb0:
79 + mutable a$2 = Call mutable compute$3(frozen props$1.a)
80 + mutable b$4 = Call mutable compute$3(frozen props$1.b)
81 + If (frozen props$1.c) then:bb2 else:bb1
82 +bb2:
83 + Call mutable foo$5(mutable a$2, mutable b$4)
84 + Goto bb1
85 +bb1:
86 + frozen $7 = JSX <frozen Foo$6 a={readonly a$2} b={readonly b$4} ></frozen Foo$6>
87 + Return frozen $7
88 +```
89 +
90 +## Code
91 +
92 +```javascript
93 +function Component$0(props$1) {
94 + a$2 = compute$3(props$1.a);
95 + b$4 = compute$3(props$1.b);
96 + if (props$1.c) {
97 + foo$5(a$2, b$4);
98 + ("<<TODO: handle complex control flow in codegen>>");
99 + }
100 +
101 + return <Foo$6 a={a$2} b={b$4}></Foo$6>;
102 +}
103 +
104 +```
105 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/interdependent-across-if.js new
+22
@@ -0,0 +1,22 @@
1 +function compute() {}
2 +function foo() {}
3 +function Foo() {}
4 +
5 +/**
6 + * Should produce 1 scope:
7 + *
8 + * return: inputs=props.a & props.b & props.c; outputs=return
9 + * const a = compute(props.a);
10 + * const b = compute(props.b);
11 + * if (props.c)
12 + * foo(a, b);
13 + * return = <Foo a={a} b={b} />
14 + */
15 +function Component(props) {
16 + const a = compute(props.a);
17 + const b = compute(props.b);
18 + if (props.c) {
19 + foo(a, b);
20 + }
21 + return <Foo a={a} b={b} />;
22 +}
compiler/forget/src/__tests__/fixtures/hir/interdependent.expect.md new
+94
@@ -0,0 +1,94 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +/**
6 + * Should produce 1 scope:
7 + *
8 + * return: inputs=props.a & props.b; outputs=return
9 + * const a = compute(props.a);
10 + * const b = compute(props.b);
11 + * foo(a, b);
12 + * return = <Foo a={a} b={b} />
13 + */
14 +function Component(props) {
15 + const a = compute(props.a);
16 + const b = compute(props.b);
17 + foo(a, b);
18 + return <Foo a={a} b={b} />;
19 +}
20 +
21 +function compute() {}
22 +function foo() {}
23 +function Foo() {}
24 +
25 +```
26 +
27 +## HIR
28 +
29 +```
30 +bb0:
31 + mutable a$2 = Call mutable compute$3(frozen props$1.a)
32 + mutable b$4 = Call mutable compute$3(frozen props$1.b)
33 + Call mutable foo$5(mutable a$2, mutable b$4)
34 + frozen $7 = JSX <frozen Foo$6 a={readonly a$2} b={readonly b$4} ></frozen Foo$6>
35 + Return frozen $7
36 +```
37 +
38 +## Code
39 +
40 +```javascript
41 +function Component$0(props$1) {
42 + a$2 = compute$3(props$1.a);
43 + b$4 = compute$3(props$1.b);
44 + foo$5(a$2, b$4);
45 + return <Foo$6 a={a$2} b={b$4}></Foo$6>;
46 +}
47 +
48 +```
49 +## HIR
50 +
51 +```
52 +bb0:
53 + Return
54 +```
55 +
56 +## Code
57 +
58 +```javascript
59 +function compute$0() {
60 + return;
61 +}
62 +
63 +```
64 +## HIR
65 +
66 +```
67 +bb0:
68 + Return
69 +```
70 +
71 +## Code
72 +
73 +```javascript
74 +function foo$0() {
75 + return;
76 +}
77 +
78 +```
79 +## HIR
80 +
81 +```
82 +bb0:
83 + Return
84 +```
85 +
86 +## Code
87 +
88 +```javascript
89 +function Foo$0() {
90 + return;
91 +}
92 +
93 +```
94 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/interdependent.js new
+19
@@ -0,0 +1,19 @@
1 +/**
2 + * Should produce 1 scope:
3 + *
4 + * return: inputs=props.a & props.b; outputs=return
5 + * const a = compute(props.a);
6 + * const b = compute(props.b);
7 + * foo(a, b);
8 + * return = <Foo a={a} b={b} />
9 + */
10 +function Component(props) {
11 + const a = compute(props.a);
12 + const b = compute(props.b);
13 + foo(a, b);
14 + return <Foo a={a} b={b} />;
15 +}
16 +
17 +function compute() {}
18 +function foo() {}
19 +function Foo() {}
compiler/forget/src/__tests__/fixtures/hir/property-assignment.expect.md new
+42
@@ -0,0 +1,42 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + const x = {};
7 + const y = [];
8 + x.y = y;
9 + const child = <Component data={y} />;
10 + x.y.push(props.p0);
11 + return <Component data={x}>{child}</Component>;
12 +}
13 +
14 +```
15 +
16 +## HIR
17 +
18 +```
19 +bb0:
20 + mutable x$2 = Object { }
21 + mutable y$3 = Array []
22 + mutable x$2.y = mutable y$3
23 + mutable child$4 = JSX <frozen Component$0 data={mutable y$3} ></frozen Component$0>
24 + Call mutable x$2.y.push(frozen props$1.p0)
25 + frozen $5 = JSX <frozen Component$0 data={readonly x$2} >{readonly child$4}</frozen Component$0>
26 + Return frozen $5
27 +```
28 +
29 +## Code
30 +
31 +```javascript
32 +function Component$0(props$1) {
33 + x$2 = {};
34 + y$3 = [];
35 + x$2 = y$3;
36 + child$4 = <Component$0 data={y$3}></Component$0>;
37 + x$2.y.push(props$1.p0);
38 + return <Component$0 data={x$2}>{child$4}</Component$0>;
39 +}
40 +
41 +```
42 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/property-assignment.js new
+8
@@ -0,0 +1,8 @@
1 +function Component(props) {
2 + const x = {};
3 + const y = [];
4 + x.y = y;
5 + const child = <Component data={y} />;
6 + x.y.push(props.p0);
7 + return <Component data={x}>{child}</Component>;
8 +}
compiler/forget/src/__tests__/fixtures/hir/reassignment-conditional.expect.md new
+58
@@ -0,0 +1,58 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + let x = [];
7 + x.push(props.p0);
8 + let y = x;
9 +
10 + if (props.p1) {
11 + x = [];
12 + }
13 +
14 + let _ = <Component x={x} />;
15 + y.push(props.p2);
16 +
17 + return <Component x={x} y={y} />;
18 +}
19 +
20 +```
21 +
22 +## HIR
23 +
24 +```
25 +bb0:
26 + mutable x$2 = Array []
27 + Call mutable x$2.push(frozen props$1.p0)
28 + mutable y$3 = mutable x$2
29 + If (frozen props$1.p1) then:bb2 else:bb1
30 +bb2:
31 + mutable x$2 = Array []
32 + Goto bb1
33 +bb1:
34 + mutable _$4 = JSX <frozen Component$0 x={mutable x$2} ></frozen Component$0>
35 + Call mutable y$3.push(frozen props$1.p2)
36 + frozen $5 = JSX <frozen Component$0 x={readonly x$2} y={readonly y$3} ></frozen Component$0>
37 + Return frozen $5
38 +```
39 +
40 +## Code
41 +
42 +```javascript
43 +function Component$0(props$1) {
44 + x$2 = [];
45 + x$2.push(props$1.p0);
46 + y$3 = x$2;
47 + if (props$1.p1) {
48 + x$2 = [];
49 + ("<<TODO: handle complex control flow in codegen>>");
50 + }
51 +
52 + _$4 = <Component$0 x={x$2}></Component$0>;
53 + y$3.push(props$1.p2);
54 + return <Component$0 x={x$2} y={y$3}></Component$0>;
55 +}
56 +
57 +```
58 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/reassignment-conditional.js new
+14
@@ -0,0 +1,14 @@
1 +function Component(props) {
2 + let x = [];
3 + x.push(props.p0);
4 + let y = x;
5 +
6 + if (props.p1) {
7 + x = [];
8 + }
9 +
10 + let _ = <Component x={x} />;
11 + y.push(props.p2);
12 +
13 + return <Component x={x} y={y} />;
14 +}
compiler/forget/src/__tests__/fixtures/hir/reassignment.expect.md new
+48
@@ -0,0 +1,48 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + let x = [];
7 + x.push(props.p0);
8 + let y = x;
9 +
10 + x = [];
11 + let _ = <Component x={x} />;
12 +
13 + y.push(props.p1);
14 +
15 + return <Component x={x} y={y} />;
16 +}
17 +
18 +```
19 +
20 +## HIR
21 +
22 +```
23 +bb0:
24 + mutable x$2 = Array []
25 + Call mutable x$2.push(frozen props$1.p0)
26 + mutable y$3 = mutable x$2
27 + frozen x$2 = Array []
28 + frozen _$4 = JSX <frozen Component$0 x={frozen x$2} ></frozen Component$0>
29 + Call mutable y$3.push(frozen props$1.p1)
30 + frozen $5 = JSX <frozen Component$0 x={frozen x$2} y={readonly y$3} ></frozen Component$0>
31 + Return frozen $5
32 +```
33 +
34 +## Code
35 +
36 +```javascript
37 +function Component$0(props$1) {
38 + x$2 = [];
39 + x$2.push(props$1.p0);
40 + y$3 = x$2;
41 + x$2 = [];
42 + _$4 = <Component$0 x={x$2}></Component$0>;
43 + y$3.push(props$1.p1);
44 + return <Component$0 x={x$2} y={y$3}></Component$0>;
45 +}
46 +
47 +```
48 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/reassignment.js new
+12
@@ -0,0 +1,12 @@
1 +function Component(props) {
2 + let x = [];
3 + x.push(props.p0);
4 + let y = x;
5 +
6 + x = [];
7 + let _ = <Component x={x} />;
8 +
9 + y.push(props.p1);
10 +
11 + return <Component x={x} y={y} />;
12 +}
compiler/forget/src/__tests__/fixtures/hir/simple.expect.md new
+41
@@ -0,0 +1,41 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo(x, y) {
6 + if (x) {
7 + return foo(false, y);
8 + }
9 + return [y * 10];
10 +}
11 +
12 +```
13 +
14 +## HIR
15 +
16 +```
17 +bb0:
18 + If (frozen x$1) then:bb2 else:bb1
19 +bb2:
20 + frozen $3 = false
21 + frozen $4 = Call mutable foo$0(frozen $3, frozen y$2)
22 + Return frozen $4
23 +bb1:
24 + frozen $5 = 10
25 + frozen $6 = Binary frozen y$2 * frozen $5
26 + frozen $7 = Array [frozen $6]
27 + Return frozen $7
28 +```
29 +
30 +## Code
31 +
32 +```javascript
33 +function foo$0(x$1, y$2) {
34 + if (x$1) {
35 + return foo$0(false, y$2);
36 + }
37 + return [y$2 * 10];
38 +}
39 +
40 +```
41 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/simple.js new
+6
@@ -0,0 +1,6 @@
1 +function foo(x, y) {
2 + if (x) {
3 + return foo(false, y);
4 + }
5 + return [y * 10];
6 +}
compiler/forget/src/__tests__/fixtures/hir/switch.expect.md new
+61
@@ -0,0 +1,61 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + let x = [];
7 + let y;
8 + switch (props.p0) {
9 + case true: {
10 + x.push(props.p2);
11 + y = [];
12 + }
13 + case false: {
14 + y = x;
15 + break;
16 + }
17 + }
18 + const child = <Component data={x} />;
19 + y.push(props.p4);
20 + return <Component data={y}>{child}</Component>;
21 +}
22 +
23 +```
24 +
25 +## HIR
26 +
27 +```
28 +bb0:
29 + mutable x$2 = Array []
30 + frozen y$3 = undefined
31 + frozen $4 = false
32 + frozen $5 = true
33 + Switch (frozen props$1.p0)
34 + Case frozen $5: bb4
35 + Case frozen $4: bb2
36 + Default: bb1
37 +bb4:
38 + Call mutable x$2.push(frozen props$1.p2)
39 + frozen y$3 = Array []
40 + Goto bb2
41 +bb2:
42 + mutable y$3 = mutable x$2
43 + Goto bb1
44 +bb1:
45 + frozen child$6 = JSX <frozen Component$0 data={readonly x$2} ></frozen Component$0>
46 + Call frozen y$3.push(frozen props$1.p4)
47 + frozen $7 = JSX <frozen Component$0 data={frozen y$3} >{frozen child$6}</frozen Component$0>
48 + Return frozen $7
49 +```
50 +
51 +## Code
52 +
53 +```javascript
54 +function Component$0(props$1) {
55 + x$2 = [];
56 + y$3 = undefined;
57 + ("<<TODO: handle switch in codegen>>");
58 +}
59 +
60 +```
61 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/switch.js new
+17
@@ -0,0 +1,17 @@
1 +function Component(props) {
2 + let x = [];
3 + let y;
4 + switch (props.p0) {
5 + case true: {
6 + x.push(props.p2);
7 + y = [];
8 + }
9 + case false: {
10 + y = x;
11 + break;
12 + }
13 + }
14 + const child = <Component data={x} />;
15 + y.push(props.p4);
16 + return <Component data={y}>{child}</Component>;
17 +}
compiler/forget/src/__tests__/hir-test.ts new
+97
@@ -0,0 +1,97 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +"use strict";
9 +
10 +import generate from "@babel/generator";
11 +import * as parser from "@babel/parser";
12 +import traverse from "@babel/traverse";
13 +import { graphviz, wasmFolder } from "@hpcc-js/wasm";
14 +import { writeFileSync } from "fs";
15 +import invariant from "invariant";
16 +import path from "path";
17 +import prettier from "prettier";
18 +import { lower } from "../HIR/BuildHIR";
19 +import codegen from "../HIR/Codegen";
20 +import { HIRFunction } from "../HIR/HIR";
21 +import inferLifetimes, { printGraph } from "../HIR/InferMutability";
22 +import printHIR from "../HIR/PrintHIR";
23 +import generateTestsFromFixtures from "./test-utils/generateTestsFromFixtures";
24 +
25 +function wrapWithTripleBackticks(s: string, ext?: string) {
26 + return `\`\`\`${ext ?? ""}
27 +${s}
28 +\`\`\``;
29 +}
30 +
31 +wasmFolder(
32 + path.join(__dirname, "..", "..", "node_modules", "@hpcc-js", "wasm", "dist")
33 +);
34 +
35 +describe("React Forget (HIR version)", () => {
36 + generateTestsFromFixtures(
37 + path.join(__dirname, "fixtures", "hir"),
38 + (input, file) => {
39 + const ast = parser.parse(input, {
40 + sourceFilename: file,
41 + plugins: ["typescript", "jsx"],
42 + });
43 + let items: Array<[string, string]> = [];
44 + traverse(ast, {
45 + FunctionDeclaration: {
46 + enter(nodePath) {
47 + const ir: HIRFunction = lower(nodePath);
48 + const lifetimeGraph = inferLifetimes(ir);
49 + const textHIR = printHIR(ir.body);
50 + const textLifetimeGraph = printGraph(lifetimeGraph);
51 + const graphvizFile = path.join(
52 + __dirname,
53 + "fixtures",
54 + "hir-svg",
55 + file + ".svg"
56 + );
57 + graphviz.layout(textLifetimeGraph, "svg", "dot").then((svg) => {
58 + writeFileSync(graphvizFile, svg);
59 + });
60 +
61 + const ast = codegen(ir);
62 + const text = prettier.format(
63 + generate(ast).code.replace("\n\n", "\n"),
64 + {
65 + semi: true,
66 + parser: "babel-ts",
67 + }
68 + );
69 + items.push([textHIR, text]);
70 + },
71 + },
72 + });
73 + invariant(
74 + items.length > 0,
75 + "Visitor failed, check that the input has a function"
76 + );
77 + const outputs = items.map(([hir, text]) => {
78 + return `
79 +## HIR
80 +
81 +${wrapWithTripleBackticks(hir)}
82 +
83 +## Code
84 +
85 +${wrapWithTripleBackticks(text, "javascript")}
86 + `.trim();
87 + });
88 + return `
89 +## Input
90 +
91 +${wrapWithTripleBackticks(input, "javascript")}
92 +
93 +${outputs.join("\n")}
94 + `;
95 + }
96 + );
97 +});
compiler/forget/tsconfig.json
+3 -1
@@ -10,7 +10,9 @@
10 "noUncheckedIndexedAccess": false,
11 "noUnusedParameters": false,
12 "useUnknownInCatchVariables": false,
13 - "target": "ES2015"
13 + "target": "ES2015",
14 + // ideally turn off only during dev, or on a per-file basis
15 + "noUnusedLocals": false
16 },
17 "exclude": ["node_modules"],
18 "include": ["src/**/*.ts"]
compiler/forget/yarn.lock
+57 -5
@@ -63,7 +63,7 @@
63 json5 "^2.2.1"
64 semver "^6.3.0"
65
66 -"@babel/generator@7.2.0", "@babel/generator@^7.1.6", "@babel/generator@^7.2.0", "@babel/generator@^7.7.2":
66 +"@babel/generator@7.2.0", "@babel/generator@^7.1.6", "@babel/generator@^7.19.3", "@babel/generator@^7.2.0", "@babel/generator@^7.7.2":
67 version "7.2.0"
68 resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.0.tgz#eaf3821fa0301d9d4aef88e63d4bcc19b73ba16c"
69 integrity sha512-BA75MVfRlFQG2EZgFYIwyT1r6xSkwfP2bdkY/kLZusEYWiJs4xCowab/alaEaT0wSvmVuXGqiefeBlP+7V1yKg==
@@ -126,6 +126,13 @@
126 "@babel/template" "^7.18.10"
127 "@babel/types" "^7.19.0"
128
129 +"@babel/helper-hoist-variables@^7.18.6":
130 + version "7.18.6"
131 + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
132 + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
133 + dependencies:
134 + "@babel/types" "^7.18.6"
135 +
136 "@babel/helper-member-expression-to-functions@^7.18.9":
137 version "7.18.9"
138 resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815"
@@ -234,6 +241,11 @@
241 resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.1.tgz#6f6d6c2e621aad19a92544cc217ed13f1aac5b4c"
242 integrity sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==
243
244 +"@babel/parser@^7.18.6", "@babel/parser@^7.19.3":
245 + version "7.19.3"
246 + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.3.tgz#8dd36d17c53ff347f9e55c328710321b49479a9a"
247 + integrity sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==
248 +
249 "@babel/plugin-syntax-async-generators@^7.8.4":
250 version "7.8.4"
251 resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
@@ -419,7 +431,7 @@
431 dependencies:
432 regenerator-runtime "^0.13.4"
433
422 -"@babel/template@^7.1.2", "@babel/template@^7.18.10", "@babel/template@^7.3.3":
434 +"@babel/template@^7.1.2", "@babel/template@^7.18.10":
435 version "7.18.10"
436 resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71"
437 integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==
@@ -428,7 +440,16 @@
440 "@babel/parser" "^7.18.10"
441 "@babel/types" "^7.18.10"
442
431 -"@babel/traverse@7.1.6", "@babel/traverse@^7.1.6", "@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.7.2":
443 +"@babel/template@^7.3.3":
444 + version "7.18.6"
445 + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31"
446 + integrity sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==
447 + dependencies:
448 + "@babel/code-frame" "^7.18.6"
449 + "@babel/parser" "^7.18.6"
450 + "@babel/types" "^7.18.6"
451 +
452 +"@babel/traverse@7.1.6", "@babel/traverse@^7.1.6", "@babel/traverse@^7.19.0", "@babel/traverse@^7.7.2":
453 version "7.1.6"
454 resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.1.6.tgz#c8db9963ab4ce5b894222435482bd8ea854b7b5c"
455 integrity sha512-CXedit6GpISz3sC2k2FsGCUpOhUqKdyL0lqNrImQojagnUMXf8hex4AxYFRuMkNGcvJX5QAFGzB5WJQmSv8SiQ==
@@ -443,6 +464,22 @@
464 globals "^11.1.0"
465 lodash "^4.17.10"
466
467 +"@babel/traverse@^7.19.1":
468 + version "7.19.3"
469 + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.19.3.tgz#3a3c5348d4988ba60884e8494b0592b2f15a04b4"
470 + integrity sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==
471 + dependencies:
472 + "@babel/code-frame" "^7.18.6"
473 + "@babel/generator" "^7.19.3"
474 + "@babel/helper-environment-visitor" "^7.18.9"
475 + "@babel/helper-function-name" "^7.19.0"
476 + "@babel/helper-hoist-variables" "^7.18.6"
477 + "@babel/helper-split-export-declaration" "^7.18.6"
478 + "@babel/parser" "^7.19.3"
479 + "@babel/types" "^7.19.3"
480 + debug "^4.1.0"
481 + globals "^11.1.0"
482 +
483 "@babel/types@7.7.4":
484 version "7.7.4"
485 resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.4.tgz#516570d539e44ddf308c07569c258ff94fde9193"
@@ -452,7 +489,15 @@
489 lodash "^4.17.13"
490 to-fast-properties "^2.0.0"
491
455 -"@babel/types@^7.0.0", "@babel/types@^7.1.6", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
492 +"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
493 + version "7.18.9"
494 + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.9.tgz#7148d64ba133d8d73a41b3172ac4b83a1452205f"
495 + integrity sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==
496 + dependencies:
497 + "@babel/helper-validator-identifier" "^7.18.6"
498 + to-fast-properties "^2.0.0"
499 +
500 +"@babel/types@^7.1.6", "@babel/types@^7.18.10", "@babel/types@^7.19.0", "@babel/types@^7.2.0":
501 version "7.19.0"
502 resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.0.tgz#75f21d73d73dc0351f3368d28db73465f4814600"
503 integrity sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==
@@ -482,6 +527,13 @@
527 dependencies:
528 "@jridgewell/trace-mapping" "0.3.9"
529
530 +"@hpcc-js/wasm@^1.15.0":
531 + version "1.16.5"
532 + resolved "https://registry.yarnpkg.com/@hpcc-js/wasm/-/wasm-1.16.5.tgz#4dbfd517b4f92ffe17922ea02a434be60c8aef26"
533 + integrity sha512-JarqNdfddZd519/GW5zVEpCpVGoojegQPxqezbPJv45gz3qBtbODt0KS+2/+XS9b3fPbwrNna2/XyUWz5/RZhw==
534 + dependencies:
535 + yargs "17.5.1"
536 +
537 "@istanbuljs/load-nyc-config@^1.0.0":
538 version "1.1.0"
539 resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
@@ -3157,7 +3209,7 @@ yargs-parser@^21.0.0, yargs-parser@^21.0.1:
3209 resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
3210 integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
3211
3160 -yargs@^17.3.1:
3212 +yargs@17.5.1, yargs@^17.3.1:
3213 version "17.5.1"
3214 resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e"
3215 integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==