@samitouri / QOS-React-1 / commits / a49335f72a

[rust] Support destructuring

Adds a `Destructure` instruction closely following the design of the TS-based compiler. The main change is fairly small: the TS compiler doesn't support rest spreads that are not identifiers, such as the `...y[]` in `const [x, ...[y]] = z`. I added support for this in the Rust compiler.

Joe Savona committed Aug 11, 2023 at 15:13 UTC a49335f72a84a76ac7b39f1e6b3a7701bd6e53f7
21 files changed +781 -333
compiler/forget/crates/forget_build_hir/src/build.rs
+151 -8
@@ -2,14 +2,15 @@ use std::collections::HashSet;
2
3 use forget_diagnostics::Diagnostic;
4 use forget_estree::{
5 - AssignmentTarget, BlockStatement, Expression, ExpressionOrSpread, ExpressionOrSuper, ForInit,
6 - Function, IntoFunction, JsValue, Pattern, Statement, VariableDeclaration,
7 - VariableDeclarationKind,
5 + AssignmentPropertyOrRestElement, AssignmentTarget, BlockStatement, Expression,
6 + ExpressionOrSpread, ExpressionOrSuper, ForInit, Function, IntoFunction, JsValue, Pattern,
7 + Statement, VariableDeclaration, VariableDeclarationKind,
8 };
9 use forget_hir::{
10 - BlockKind, BranchTerminal, Environment, ForTerminal, GotoKind, IdentifierOperand,
11 - InstructionKind, InstructionValue, JSXAttribute, JSXElement, LValue, LoadGlobal, LoadLocal,
12 - PlaceOrSpread, TerminalValue,
10 + ArrayDestructureItem, BlockKind, BranchTerminal, Destructure, DestructurePattern, Environment,
11 + ForTerminal, GotoKind, Identifier, IdentifierOperand, InstructionKind, InstructionValue,
12 + JSXAttribute, JSXElement, LValue, LoadGlobal, LoadLocal, ObjectDestructureItem,
13 + ObjectDestructureProperty, PlaceOrSpread, TerminalValue,
14 };
15
16 use crate::builder::{Builder, LoopScope};
@@ -303,8 +304,8 @@ fn lower_variable_declaration(
304 }
305 }
306 _ => {
306 - return Err(Diagnostic::todo(
307 - "Handle non-identifier variable declarations",
307 + return Err(Diagnostic::invalid_syntax(
308 + "Expected an identifier for variable declaration without an intializer. Destructuring requires an initial value",
309 declaration.range,
310 ));
311 }
@@ -543,6 +544,7 @@ fn lower_assignment(
544 })
545 }
546
547 +// TODO: change the success type to void, no caller uses it
548 fn lower_assignment_pattern(
549 env: &Environment,
550 builder: &mut Builder,
@@ -558,6 +560,147 @@ fn lower_assignment_pattern(
560 value,
561 }))
562 }
563 + Pattern::ArrayPattern(lvalue) => {
564 + let mut items = Vec::with_capacity(lvalue.elements.len());
565 + let mut followups: Vec<(Identifier, &Pattern)> = Vec::new();
566 + for element in &lvalue.elements {
567 + match element {
568 + None => items.push(ArrayDestructureItem::Hole),
569 + Some(Pattern::Identifier(element)) => {
570 + let identifier =
571 + lower_identifier_for_assignment(env, builder, kind, &element)?;
572 + items.push(ArrayDestructureItem::Value(identifier));
573 + }
574 + Some(Pattern::RestElement(element)) => {
575 + if let Pattern::Identifier(element) = &element.argument {
576 + let identifier = lower_identifier_for_assignment(
577 + env,
578 + builder,
579 + kind,
580 + element.as_ref(),
581 + )?;
582 + items.push(ArrayDestructureItem::Spread(identifier));
583 + } else {
584 + let temporary = env.new_temporary();
585 + items.push(ArrayDestructureItem::Spread(IdentifierOperand {
586 + identifier: temporary.clone(),
587 + effect: None,
588 + }));
589 + followups.push((temporary, &element.argument));
590 + }
591 + }
592 + Some(element) => {
593 + let temporary = env.new_temporary();
594 + items.push(ArrayDestructureItem::Value(IdentifierOperand {
595 + identifier: temporary.clone(),
596 + effect: None,
597 + }));
598 + followups.push((temporary, element));
599 + }
600 + }
601 + }
602 + let temporary = builder.push(InstructionValue::Destructure(Destructure {
603 + kind,
604 + pattern: DestructurePattern::Array(items),
605 + value,
606 + }));
607 + for (temporary, pattern) in followups {
608 + lower_assignment_pattern(
609 + env,
610 + builder,
611 + kind,
612 + pattern,
613 + IdentifierOperand {
614 + identifier: temporary,
615 + effect: None,
616 + },
617 + )?;
618 + }
619 + temporary
620 + }
621 + Pattern::ObjectPattern(lvalue) => {
622 + let mut properties = Vec::with_capacity(lvalue.properties.len());
623 + let mut followups: Vec<(Identifier, &Pattern)> = Vec::new();
624 +
625 + for property in &lvalue.properties {
626 + match property {
627 + AssignmentPropertyOrRestElement::RestElement(property) => {
628 + if let Pattern::Identifier(element) = &property.argument {
629 + let identifier = lower_identifier_for_assignment(
630 + env,
631 + builder,
632 + kind,
633 + element.as_ref(),
634 + )?;
635 + properties.push(ObjectDestructureItem::Spread(identifier));
636 + } else {
637 + let temporary = env.new_temporary();
638 + properties.push(ObjectDestructureItem::Spread(IdentifierOperand {
639 + identifier: temporary.clone(),
640 + effect: None,
641 + }));
642 + followups.push((temporary, &property.argument));
643 + }
644 + }
645 + AssignmentPropertyOrRestElement::AssignmentProperty(property) => {
646 + if property.is_computed {
647 + return Err(Diagnostic::todo(
648 + "Handle computed properties in ObjectPattern",
649 + property.range,
650 + ));
651 + }
652 + let key = if let Expression::Identifier(key) = &property.key {
653 + key.name.as_str()
654 + } else {
655 + return Err(Diagnostic::todo(
656 + "Support non-identifier object keys in non-computed ObjectPattern",
657 + property.range,
658 + ));
659 + };
660 + if let Pattern::Identifier(value) = &property.value {
661 + let value = lower_identifier_for_assignment(env, builder, kind, value)?;
662 + properties.push(ObjectDestructureItem::Property(
663 + ObjectDestructureProperty {
664 + name: key.to_string(),
665 + value,
666 + },
667 + ));
668 + } else {
669 + let temporary = env.new_temporary();
670 + properties.push(ObjectDestructureItem::Property(
671 + ObjectDestructureProperty {
672 + name: key.to_string(),
673 + value: IdentifierOperand {
674 + identifier: temporary.clone(),
675 + effect: None,
676 + },
677 + },
678 + ));
679 + followups.push((temporary, &property.value));
680 + }
681 + }
682 + }
683 + }
684 +
685 + let temporary = builder.push(InstructionValue::Destructure(Destructure {
686 + kind,
687 + pattern: DestructurePattern::Object(properties),
688 + value,
689 + }));
690 + for (temporary, pattern) in followups {
691 + lower_assignment_pattern(
692 + env,
693 + builder,
694 + kind,
695 + pattern,
696 + IdentifierOperand {
697 + identifier: temporary,
698 + effect: None,
699 + },
700 + )?;
701 + }
702 + temporary
703 + }
704 _ => todo!("lower assignment pattern for {:#?}", lvalue),
705 })
706 }
compiler/forget/crates/forget_fixtures/tests/fixtures/destructure-array.js new
+5
@@ -0,0 +1,5 @@
1 +function Component(a, b) {
2 + const [c, , ...d] = a;
3 + const [[[e]], ...[f]] = b;
4 + return [c, d, e, f];
5 +}
compiler/forget/crates/forget_fixtures/tests/fixtures/destructure-object.js new
+15
@@ -0,0 +1,15 @@
1 +function Component(a, b) {
2 + const {
3 + c,
4 + d,
5 + e: { e },
6 + f: { _f: f },
7 + g: {
8 + g: {
9 + g: { g, ...h },
10 + },
11 + },
12 + ...i
13 + } = a;
14 + return [c, d, e, f, g, h, i];
15 +}
compiler/forget/crates/forget_fixtures/tests/fixtures_test.rs
+1
@@ -38,6 +38,7 @@ fn fixtures() {
38 match build(&environment, &fun.function) {
39 Ok(mut fun) => {
40 println!("ok build");
41 + fun.debug();
42 enter_ssa(&environment, &mut fun).unwrap();
43 println!("ok enter_ssa");
44 eliminate_redundant_phis(&environment, &mut fun);
compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@constant-propagation-constant-if-condition.js.snap
+70 -26
@@ -45,29 +45,73 @@ function Component(
45 )
46 entry bb0
47 bb0 (block)
48 - [0] unknown $0 = 1
49 - [1] unknown $2 = StoreLocal Let unknown a$39 = unknown $0
50 - [2] unknown $4 = DeclareLocal Let unknown b$40
51 - [3] unknown $9 = 1
52 - [4] unknown $10 = 1
53 - [5] unknown $11 = true
54 - [6] unknown $5 = true
55 - [7] unknown $6 = StoreLocal Reassign unknown b$41 = unknown $5
56 - [8] unknown $13 = DeclareLocal Let unknown c$43
57 - [9] unknown $18 = true
58 - [10] unknown $14 = "hello"
59 - [11] unknown $15 = StoreLocal Reassign unknown c$45 = unknown $14
60 - [12] unknown $20 = DeclareLocal Let unknown d$47
61 - [13] unknown $25 = "hello"
62 - [14] unknown $26 = "hello"
63 - [15] unknown $27 = true
64 - [16] unknown $21 = 42
65 - [17] unknown $22 = StoreLocal Reassign unknown d$49 = unknown $21
66 - [18] unknown $29 = DeclareLocal Let unknown e$51
67 - [19] unknown $34 = 42
68 - [20] unknown $35 = 42
69 - [21] unknown $36 = true
70 - [22] unknown $30 = "ok"
71 - [23] unknown $31 = StoreLocal Reassign unknown e$53 = unknown $30
72 - [24] unknown $37 = "ok"
73 - [25] Return unknown $37
48 + [0] unknown $39 = 1
49 + [1] unknown $40 = StoreLocal Let unknown a$41 = unknown $39
50 + [2] unknown $42 = DeclareLocal Let unknown b$43
51 + [3] unknown $44 = LoadLocal unknown a$1
52 + [4] unknown $45 = 1
53 + [5] unknown $46 = Binary unknown $44 === unknown $45
54 + [6] If unknown $11 consequent=bb2 alternate=bb3 fallthrough=bb1
55 +bb2 (block)
56 + predecessors: bb0
57 + [7] unknown $47 = true
58 + [8] unknown $48 = StoreLocal Reassign unknown b$49 = unknown $47
59 + [9] Goto bb1
60 +bb3 (block)
61 + predecessors: bb0
62 + [10] unknown $50 = false
63 + [11] unknown $51 = StoreLocal Reassign unknown b$52 = unknown $50
64 + [12] Goto bb1
65 +bb1 (block)
66 + predecessors: bb2, bb3
67 + [13] unknown $53 = DeclareLocal Let unknown c$54
68 + [14] unknown $55 = LoadLocal unknown b$3
69 + [15] If unknown $18 consequent=bb5 alternate=bb6 fallthrough=bb4
70 +bb5 (block)
71 + predecessors: bb1
72 + [16] unknown $56 = "hello"
73 + [17] unknown $57 = StoreLocal Reassign unknown c$58 = unknown $56
74 + [18] Goto bb4
75 +bb6 (block)
76 + predecessors: bb1
77 + [19] unknown $59 = null
78 + [20] unknown $60 = StoreLocal Reassign unknown c$61 = unknown $59
79 + [21] Goto bb4
80 +bb4 (block)
81 + predecessors: bb5, bb6
82 + [22] unknown $62 = DeclareLocal Let unknown d$63
83 + [23] unknown $64 = LoadLocal unknown c$12
84 + [24] unknown $65 = "hello"
85 + [25] unknown $66 = Binary unknown $64 === unknown $65
86 + [26] If unknown $27 consequent=bb8 alternate=bb9 fallthrough=bb7
87 +bb8 (block)
88 + predecessors: bb4
89 + [27] unknown $67 = 42
90 + [28] unknown $68 = StoreLocal Reassign unknown d$69 = unknown $67
91 + [29] Goto bb7
92 +bb9 (block)
93 + predecessors: bb4
94 + [30] unknown $70 = 42.001
95 + [31] unknown $71 = StoreLocal Reassign unknown d$72 = unknown $70
96 + [32] Goto bb7
97 +bb7 (block)
98 + predecessors: bb8, bb9
99 + [33] unknown $73 = DeclareLocal Let unknown e$74
100 + [34] unknown $75 = LoadLocal unknown d$19
101 + [35] unknown $76 = 42
102 + [36] unknown $77 = Binary unknown $75 === unknown $76
103 + [37] If unknown $36 consequent=bb11 alternate=bb12 fallthrough=bb10
104 +bb11 (block)
105 + predecessors: bb7
106 + [38] unknown $78 = "ok"
107 + [39] unknown $79 = StoreLocal Reassign unknown e$80 = unknown $78
108 + [40] Goto bb10
109 +bb12 (block)
110 + predecessors: bb7
111 + [41] unknown $81 = "nope"
112 + [42] unknown $82 = StoreLocal Reassign unknown e$83 = unknown $81
113 + [43] Goto bb10
114 +bb10 (block)
115 + predecessors: bb11, bb12
116 + [44] unknown $84 = LoadLocal unknown e$28
117 + [45] Return unknown $37
compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@constant-propagation.js.snap
+103 -105
@@ -72,127 +72,125 @@ function Component(
72 )
73 entry bb0
74 bb0 (block)
75 - [0] unknown $2 = DeclareLocal Let unknown a$109
76 - [1] unknown $3 = LoadGlobal Math
77 - [2] unknown $4 = StoreLocal Reassign unknown a$110 = unknown $3
78 - [3] unknown $5 = LoadGlobal Math
79 - [4] unknown $7 = DeclareLocal Let unknown b$111
80 - [5] unknown $12 = LoadLocal unknown props$108
75 + [0] unknown $109 = DeclareLocal Let unknown a$110
76 + [1] unknown $111 = LoadGlobal Math
77 + [2] unknown $112 = StoreLocal Reassign unknown a$113 = unknown $111
78 + [3] unknown $114 = LoadLocal unknown a$1
79 + [4] unknown $115 = DeclareLocal Let unknown b$116
80 + [5] unknown $117 = LoadLocal unknown props$0
81 [6] If unknown $12 consequent=bb2 alternate=bb3 fallthrough=bb1
82 bb2 (block)
83 predecessors: bb0
84 - [7] unknown $8 = true
85 - [8] unknown $9 = StoreLocal Reassign unknown b$112 = unknown $8
84 + [7] unknown $118 = true
85 + [8] unknown $119 = StoreLocal Reassign unknown b$120 = unknown $118
86 [9] Goto bb1
87 bb3 (block)
88 predecessors: bb0
89 - [10] unknown $10 = true
90 - [11] unknown $11 = StoreLocal Reassign unknown b$113 = unknown $10
89 + [10] unknown $121 = true
90 + [11] unknown $122 = StoreLocal Reassign unknown b$123 = unknown $121
91 [12] Goto bb1
92 bb1 (block)
93 predecessors: bb2, bb3
94 - b$114: phi(bb2: b$112, bb3: b$113)
95 - [13] unknown $13 = true
96 - [14] unknown $15 = DeclareLocal Let unknown c$115
97 - [15] unknown $20 = LoadLocal unknown props$108
94 + [13] unknown $124 = LoadLocal unknown b$6
95 + [14] unknown $125 = DeclareLocal Let unknown c$126
96 + [15] unknown $127 = LoadLocal unknown props$0
97 [16] If unknown $20 consequent=bb5 alternate=bb6 fallthrough=bb4
98 bb5 (block)
99 predecessors: bb1
101 - [17] unknown $16 = true
102 - [18] unknown $17 = StoreLocal Reassign unknown c$117 = unknown $16
100 + [17] unknown $128 = true
101 + [18] unknown $129 = StoreLocal Reassign unknown c$130 = unknown $128
102 [19] Goto bb4
103 bb6 (block)
104 predecessors: bb1
106 - [20] unknown $18 = 42
107 - [21] unknown $19 = StoreLocal Reassign unknown c$118 = unknown $18
105 + [20] unknown $131 = 42
106 + [21] unknown $132 = StoreLocal Reassign unknown c$133 = unknown $131
107 [22] Goto bb4
108 bb4 (block)
109 predecessors: bb5, bb6
111 - c$119: phi(bb5: c$117, bb6: c$118)
112 - [23] unknown $21 = LoadLocal unknown c$119
113 - [24] unknown $22 = 42
114 - [25] unknown $23 = 1
115 - [26] unknown $24 = 43
116 - [27] unknown $25 = 42
117 - [28] unknown $26 = 1
118 - [29] unknown $27 = 41
119 - [30] unknown $28 = 42
120 - [31] unknown $29 = 2
121 - [32] unknown $30 = 84
122 - [33] unknown $31 = 42
123 - [34] unknown $32 = 2
124 - [35] unknown $33 = 21
125 - [36] unknown $34 = 0
126 - [37] unknown $35 = 1
127 - [38] unknown $36 = false
128 - [39] unknown $37 = 0
129 - [40] unknown $38 = 1
130 - [41] unknown $39 = true
131 - [42] unknown $40 = 0
132 - [43] unknown $41 = 1
133 - [44] unknown $42 = false
134 - [45] unknown $43 = 0
135 - [46] unknown $44 = 1
136 - [47] unknown $45 = true
137 - [48] unknown $46 = 0
138 - [49] unknown $47 = 0
139 - [50] unknown $48 = true
140 - [51] unknown $49 = LoadGlobal NaN
141 - [52] unknown $50 = LoadGlobal NaN
142 - [53] unknown $51 = Binary unknown $49 == unknown $50
143 - [54] unknown $52 = LoadGlobal NaN
144 - [55] unknown $53 = LoadGlobal NaN
145 - [56] unknown $54 = Binary unknown $52 != unknown $53
146 - [57] unknown $55 = LoadGlobal NaN
147 - [58] unknown $56 = LoadGlobal NaN
148 - [59] unknown $57 = Binary unknown $55 !== unknown $56
149 - [60] unknown $58 = LoadGlobal NaN
150 - [61] unknown $59 = LoadGlobal NaN
151 - [62] unknown $60 = Binary unknown $58 !== unknown $59
152 - [63] unknown $61 = "hello"
153 - [64] unknown $62 = "hello"
154 - [65] unknown $63 = true
155 - [66] unknown $64 = "hello"
156 - [67] unknown $65 = "hello"
157 - [68] unknown $66 = false
158 - [69] unknown $67 = "hello"
159 - [70] unknown $68 = "hello"
160 - [71] unknown $69 = true
161 - [72] unknown $70 = "hello"
162 - [73] unknown $71 = "hello"
163 - [74] unknown $72 = false
164 - [75] unknown $73 = "hello"
165 - [76] unknown $74 = "world"
166 - [77] unknown $75 = false
167 - [78] unknown $76 = "hello"
168 - [79] unknown $77 = "world"
169 - [80] unknown $78 = true
170 - [81] unknown $79 = "hello"
171 - [82] unknown $80 = "world"
172 - [83] unknown $81 = false
173 - [84] unknown $82 = "hello"
174 - [85] unknown $83 = "world"
175 - [86] unknown $84 = true
176 - [87] unknown $85 = true
177 - [88] unknown $86 = true
178 - [89] unknown $87 = true
179 - [90] unknown $88 = true
180 - [91] unknown $89 = true
181 - [92] unknown $90 = false
182 - [93] unknown $91 = true
183 - [94] unknown $92 = true
184 - [95] unknown $93 = true
185 - [96] unknown $94 = true
186 - [97] unknown $95 = true
187 - [98] unknown $96 = false
188 - [99] unknown $97 = 5
189 - [100] unknown $98 = 60
190 - [101] unknown $99 = 300
191 - [102] unknown $100 = 60
192 - [103] unknown $101 = 18000
193 - [104] unknown $102 = 1000
194 - [105] unknown $103 = 18000000
195 - [106] unknown $105 = StoreLocal Let unknown x$120 = unknown $103
196 - [107] unknown $106 = 18000000
197 - [108] unknown $107 = <undefined>
110 + [23] unknown $134 = LoadLocal unknown c$14
111 + [24] unknown $135 = 42
112 + [25] unknown $136 = 1
113 + [26] unknown $137 = 43
114 + [27] unknown $138 = 42
115 + [28] unknown $139 = 1
116 + [29] unknown $140 = 41
117 + [30] unknown $141 = 42
118 + [31] unknown $142 = 2
119 + [32] unknown $143 = 84
120 + [33] unknown $144 = 42
121 + [34] unknown $145 = 2
122 + [35] unknown $146 = 21
123 + [36] unknown $147 = 0
124 + [37] unknown $148 = 1
125 + [38] unknown $149 = false
126 + [39] unknown $150 = 0
127 + [40] unknown $151 = 1
128 + [41] unknown $152 = true
129 + [42] unknown $153 = 0
130 + [43] unknown $154 = 1
131 + [44] unknown $155 = false
132 + [45] unknown $156 = 0
133 + [46] unknown $157 = 1
134 + [47] unknown $158 = true
135 + [48] unknown $159 = 0
136 + [49] unknown $160 = 0
137 + [50] unknown $161 = true
138 + [51] unknown $162 = LoadGlobal NaN
139 + [52] unknown $163 = LoadGlobal NaN
140 + [53] unknown $164 = Binary unknown $162 == unknown $163
141 + [54] unknown $165 = LoadGlobal NaN
142 + [55] unknown $166 = LoadGlobal NaN
143 + [56] unknown $167 = Binary unknown $165 != unknown $166
144 + [57] unknown $168 = LoadGlobal NaN
145 + [58] unknown $169 = LoadGlobal NaN
146 + [59] unknown $170 = Binary unknown $168 !== unknown $169
147 + [60] unknown $171 = LoadGlobal NaN
148 + [61] unknown $172 = LoadGlobal NaN
149 + [62] unknown $173 = Binary unknown $171 !== unknown $172
150 + [63] unknown $174 = "hello"
151 + [64] unknown $175 = "hello"
152 + [65] unknown $176 = true
153 + [66] unknown $177 = "hello"
154 + [67] unknown $178 = "hello"
155 + [68] unknown $179 = false
156 + [69] unknown $180 = "hello"
157 + [70] unknown $181 = "hello"
158 + [71] unknown $182 = true
159 + [72] unknown $183 = "hello"
160 + [73] unknown $184 = "hello"
161 + [74] unknown $185 = false
162 + [75] unknown $186 = "hello"
163 + [76] unknown $187 = "world"
164 + [77] unknown $188 = false
165 + [78] unknown $189 = "hello"
166 + [79] unknown $190 = "world"
167 + [80] unknown $191 = true
168 + [81] unknown $192 = "hello"
169 + [82] unknown $193 = "world"
170 + [83] unknown $194 = false
171 + [84] unknown $195 = "hello"
172 + [85] unknown $196 = "world"
173 + [86] unknown $197 = true
174 + [87] unknown $198 = true
175 + [88] unknown $199 = true
176 + [89] unknown $200 = true
177 + [90] unknown $201 = true
178 + [91] unknown $202 = true
179 + [92] unknown $203 = false
180 + [93] unknown $204 = true
181 + [94] unknown $205 = true
182 + [95] unknown $206 = true
183 + [96] unknown $207 = true
184 + [97] unknown $208 = true
185 + [98] unknown $209 = false
186 + [99] unknown $210 = 5
187 + [100] unknown $211 = 60
188 + [101] unknown $212 = 300
189 + [102] unknown $213 = 60
190 + [103] unknown $214 = 18000
191 + [104] unknown $215 = 1000
192 + [105] unknown $216 = 18000000
193 + [106] unknown $217 = StoreLocal Let unknown x$218 = unknown $216
194 + [107] unknown $219 = LoadLocal unknown x$104
195 + [108] unknown $220 = <undefined>
196 [109] Return unknown $107
compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@destructure-array.js.snap new
+33
@@ -0,0 +1,33 @@
1 +---
2 +source: crates/forget_fixtures/tests/fixtures_test.rs
3 +expression: "format!(\"Input:\\n{input}\\n\\nOutput:\\n{output}\")"
4 +input_file: crates/forget_fixtures/tests/fixtures/destructure-array.js
5 +---
6 +Input:
7 +function Component(a, b) {
8 + const [c, , ...d] = a;
9 + const [[[e]], ...[f]] = b;
10 + return [c, d, e, f];
11 +}
12 +
13 +
14 +Output:
15 +function Component(
16 + unknown a$22,
17 + unknown b$23,
18 +)
19 +entry bb0
20 +bb0 (block)
21 + [0] unknown $24 = LoadLocal unknown a$0
22 + [1] unknown $25 = Destructure [ unknown c$26, <hole>, ...unknown d$27 ] = unknown $24
23 + [2] unknown $28 = LoadLocal unknown b$1
24 + [3] unknown $29 = Destructure [ unknown $30, ...unknown $31 ] = unknown $28
25 + [4] unknown $32 = Destructure [ unknown $33 ] = unknown $30
26 + [5] unknown $34 = Destructure [ unknown e$35 ] = unknown $33
27 + [6] unknown $36 = Destructure [ unknown f$37 ] = unknown $31
28 + [7] unknown $38 = LoadLocal unknown c$3
29 + [8] unknown $39 = LoadLocal unknown d$4
30 + [9] unknown $40 = LoadLocal unknown e$12
31 + [10] unknown $41 = LoadLocal unknown f$14
32 + [11] unknown $42 = Array [unknown $38, unknown $39, unknown $40, unknown $41]
33 + [12] Return unknown $20
compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@destructure-object.js.snap new
+46
@@ -0,0 +1,46 @@
1 +---
2 +source: crates/forget_fixtures/tests/fixtures_test.rs
3 +expression: "format!(\"Input:\\n{input}\\n\\nOutput:\\n{output}\")"
4 +input_file: crates/forget_fixtures/tests/fixtures/destructure-object.js
5 +---
6 +Input:
7 +function Component(a, b) {
8 + const {
9 + c,
10 + d,
11 + e: { e },
12 + f: { _f: f },
13 + g: {
14 + g: {
15 + g: { g, ...h },
16 + },
17 + },
18 + ...i
19 + } = a;
20 + return [c, d, e, f, g, h, i];
21 +}
22 +
23 +
24 +Output:
25 +function Component(
26 + unknown a$30,
27 + unknown b$31,
28 +)
29 +entry bb0
30 +bb0 (block)
31 + [0] unknown $32 = LoadLocal unknown a$0
32 + [1] unknown $33 = Destructure { c: unknown c$34, d: unknown d$35, e: unknown $36, f: unknown $37, g: unknown $38, ...unknown i$39 } = unknown $32
33 + [2] unknown $40 = Destructure { e: unknown e$41 } = unknown $36
34 + [3] unknown $42 = Destructure { _f: unknown f$43 } = unknown $37
35 + [4] unknown $44 = Destructure { g: unknown $45 } = unknown $38
36 + [5] unknown $46 = Destructure { g: unknown $47 } = unknown $45
37 + [6] unknown $48 = Destructure { g: unknown g$49, ...unknown h$50 } = unknown $47
38 + [7] unknown $51 = LoadLocal unknown c$3
39 + [8] unknown $52 = LoadLocal unknown d$4
40 + [9] unknown $53 = LoadLocal unknown e$10
41 + [10] unknown $54 = LoadLocal unknown f$12
42 + [11] unknown $55 = LoadLocal unknown g$18
43 + [12] unknown $56 = LoadLocal unknown h$19
44 + [13] unknown $57 = LoadLocal unknown i$8
45 + [14] unknown $58 = Array [unknown $51, unknown $52, unknown $53, unknown $54, unknown $55, unknown $56, unknown $57]
46 + [15] Return unknown $28
compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@for-statement.js.snap
+16 -18
@@ -18,37 +18,35 @@ function foo(
18 )
19 entry bb0
20 bb0 (block)
21 - [0] unknown $0 = 0
22 - [1] unknown $2 = StoreLocal Let unknown x$19 = unknown $0
21 + [0] unknown $19 = 0
22 + [1] unknown $20 = StoreLocal Let unknown x$21 = unknown $19
23 [2] For init=bb3 test=bb1 update=bb4 body=bb5 fallthrough=bb2
24 bb3 (loop)
25 predecessors: bb0
26 - [3] unknown $3 = 0
27 - [4] unknown $5 = StoreLocal Let unknown i$20 = unknown $3
26 + [3] unknown $22 = 0
27 + [4] unknown $23 = StoreLocal Let unknown i$24 = unknown $22
28 [5] Goto bb1
29 bb1 (loop)
30 predecessors: bb3, bb4
31 - i$21: phi(bb3: i$20, bb4: i$24)
32 - x$22: phi(bb3: x$19, bb4: x$23)
33 - [6] unknown $14 = LoadLocal unknown i$21
34 - [7] unknown $15 = 10
35 - [8] unknown $16 = Binary unknown $14 < unknown $15
31 + [6] unknown $25 = LoadLocal unknown i$4
32 + [7] unknown $26 = 10
33 + [8] unknown $27 = Binary unknown $25 < unknown $26
34 [9] Branch unknown $16 consequent=bb5 alternate=bb2
35 bb5 (block)
36 predecessors: bb1
39 - [10] unknown $10 = LoadLocal unknown x$22
40 - [11] unknown $11 = LoadLocal unknown i$21
41 - [12] unknown $12 = Binary unknown $10 + unknown $11
42 - [13] unknown $13 = StoreLocal Reassign unknown x$23 = unknown $12
37 + [10] unknown $28 = LoadLocal unknown x$1
38 + [11] unknown $29 = LoadLocal unknown i$4
39 + [12] unknown $30 = Binary unknown $28 + unknown $29
40 + [13] unknown $31 = StoreLocal Reassign unknown x$32 = unknown $30
41 [14] Goto bb4
42 bb4 (loop)
43 predecessors: bb5
46 - [15] unknown $6 = LoadLocal unknown i$21
47 - [16] unknown $7 = 1
48 - [17] unknown $8 = Binary unknown $6 + unknown $7
49 - [18] unknown $9 = StoreLocal Reassign unknown i$24 = unknown $8
44 + [15] unknown $33 = LoadLocal unknown i$4
45 + [16] unknown $34 = 1
46 + [17] unknown $35 = Binary unknown $33 + unknown $34
47 + [18] unknown $36 = StoreLocal Reassign unknown i$37 = unknown $35
48 [19] Goto bb1
49 bb2 (block)
50 predecessors: bb1
53 - [20] unknown $17 = LoadLocal unknown x$22
51 + [20] unknown $38 = LoadLocal unknown x$1
52 [21] Return unknown $17
compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@function-expressions.js.snap
+61 -49
@@ -33,62 +33,74 @@ function Component(
33 )
34 entry bb0
35 bb0 (block)
36 - [0] unknown $1 = 2
37 - [1] unknown $3 = StoreLocal Const unknown x$59 = unknown $1
38 - [2] unknown $54 = Function @deps[] @context[unknown x$59]:
36 + [0] unknown $59 = 2
37 + [1] unknown $60 = StoreLocal Const unknown x$61 = unknown $59
38 + [2] unknown $62 = Function @deps[] @context[unknown x$61]:
39 function foo(
40 - unknown y$60,
40 + unknown y$63,
41 )
42 entry bb1
43 bb1 (block)
44 - [0] unknown $5 = 1
45 - [1] unknown $7 = StoreLocal Let unknown a$61 = unknown $5
46 - [2] unknown $9 = DeclareLocal Let unknown b$62
47 - [3] unknown $16 = 1
48 - [4] unknown $17 = 1
49 - [5] unknown $18 = true
50 - [6] unknown $10 = 5
51 - [7] unknown $11 = 3
52 - [8] unknown $12 = 8
53 - [9] unknown $13 = StoreLocal Reassign unknown b$63 = unknown $12
54 - [10] unknown $19 = 2
55 - [11] unknown $20 = LoadLocal unknown y$60
56 - [12] unknown $21 = Binary unknown $19 + unknown $20
57 - [13] unknown $22 = 1
58 - [14] unknown $23 = Binary unknown $21 + unknown $22
59 - [15] unknown $24 = 8
60 - [16] unknown $25 = Binary unknown $23 + unknown $24
61 - [17] unknown $48 = Function @deps[] @context[unknown x$59, unknown y$60, unknown a$61, unknown b$63]:
44 + [0] unknown $64 = 1
45 + [1] unknown $65 = StoreLocal Let unknown a$66 = unknown $64
46 + [2] unknown $67 = DeclareLocal Let unknown b$68
47 + [3] unknown $69 = LoadLocal unknown a$6
48 + [4] unknown $70 = 1
49 + [5] unknown $71 = Binary unknown $69 === unknown $70
50 + [6] If unknown $18 consequent=bb3 alternate=bb4 fallthrough=bb2
51 + bb3 (block)
52 + predecessors: bb1
53 + [7] unknown $72 = 5
54 + [8] unknown $73 = 3
55 + [9] unknown $74 = 8
56 + [10] unknown $75 = StoreLocal Reassign unknown b$76 = unknown $74
57 + [11] Goto bb2
58 + bb4 (block)
59 + predecessors: bb1
60 + [12] unknown $77 = false
61 + [13] unknown $78 = StoreLocal Reassign unknown b$79 = unknown $77
62 + [14] Goto bb2
63 + bb2 (block)
64 + predecessors: bb3, bb4
65 + b$91: phi(bb3: b$76, bb4: b$79)
66 + [15] unknown $80 = LoadLocal unknown x$2
67 + [16] unknown $81 = LoadLocal unknown y$4
68 + [17] unknown $82 = Binary unknown $80 + unknown $81
69 + [18] unknown $83 = LoadLocal unknown a$6
70 + [19] unknown $84 = Binary unknown $82 + unknown $83
71 + [20] unknown $85 = LoadLocal unknown b$8
72 + [21] unknown $86 = Binary unknown $84 + unknown $85
73 + [22] unknown $87 = Function @deps[] @context[unknown x$61, unknown y$63, unknown a$66, unknown b$91]:
74 function bar(
63 - unknown z$69,
75 + unknown z$92,
76 )
77 entry bb5
78 bb5 (block)
67 - [0] unknown $27 = 2
68 - [1] unknown $29 = StoreLocal Let unknown c$70 = unknown $27
69 - [2] unknown $31 = DeclareLocal Let unknown d$71
70 - [3] unknown $32 = 3
71 - [4] unknown $33 = StoreLocal Reassign unknown d$72 = unknown $32
72 - [5] unknown $34 = LoadLocal unknown x$65
73 - [6] unknown $35 = LoadLocal unknown y$66
74 - [7] unknown $36 = Binary unknown $34 + unknown $35
75 - [8] unknown $37 = LoadLocal unknown a$67
76 - [9] unknown $38 = Binary unknown $36 + unknown $37
77 - [10] unknown $39 = LoadLocal unknown b$68
78 - [11] unknown $40 = Binary unknown $38 + unknown $39
79 - [12] unknown $41 = LoadLocal unknown z$69
80 - [13] unknown $42 = Binary unknown $40 + unknown $41
81 - [14] unknown $43 = 2
82 - [15] unknown $44 = Binary unknown $42 + unknown $43
83 - [16] unknown $45 = 3
84 - [17] unknown $46 = Binary unknown $44 + unknown $45
85 - [18] unknown $47 = <undefined>
79 + [0] unknown $93 = 2
80 + [1] unknown $94 = StoreLocal Let unknown c$95 = unknown $93
81 + [2] unknown $96 = DeclareLocal Let unknown d$97
82 + [3] unknown $98 = 3
83 + [4] unknown $99 = StoreLocal Reassign unknown d$100 = unknown $98
84 + [5] unknown $101 = LoadLocal unknown x$2
85 + [6] unknown $102 = LoadLocal unknown y$4
86 + [7] unknown $103 = Binary unknown $101 + unknown $102
87 + [8] unknown $104 = LoadLocal unknown a$6
88 + [9] unknown $105 = Binary unknown $103 + unknown $104
89 + [10] unknown $106 = LoadLocal unknown b$8
90 + [11] unknown $107 = Binary unknown $105 + unknown $106
91 + [12] unknown $108 = LoadLocal unknown z$26
92 + [13] unknown $109 = Binary unknown $107 + unknown $108
93 + [14] unknown $110 = LoadLocal unknown c$28
94 + [15] unknown $111 = Binary unknown $109 + unknown $110
95 + [16] unknown $112 = LoadLocal unknown d$30
96 + [17] unknown $113 = Binary unknown $111 + unknown $112
97 + [18] unknown $114 = <undefined>
98 [19] Return unknown $47
87 - [18] unknown $50 = StoreLocal Const unknown bar$73 = unknown $48
88 - [19] unknown $51 = LoadLocal unknown bar$73
89 - [20] unknown $52 = LoadGlobal foo
90 - [21] unknown $53 = <undefined>
91 - [22] Return unknown $53
92 - [3] unknown $56 = StoreLocal Const unknown foo$74 = unknown $54
93 - [4] unknown $57 = <undefined>
99 + [23] unknown $115 = StoreLocal Const unknown bar$116 = unknown $87
100 + [24] unknown $117 = LoadLocal unknown bar$49
101 + [25] unknown $118 = LoadGlobal foo
102 + [26] unknown $119 = <undefined>
103 + [27] Return unknown $53
104 + [3] unknown $120 = StoreLocal Const unknown foo$121 = unknown $62
105 + [4] unknown $122 = <undefined>
106 [5] Return unknown $57
compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@identifiers.js.snap
+10 -10
@@ -28,14 +28,14 @@ function id(
28 )
29 entry bb0
30 bb0 (block)
31 - [0] unknown $1 = LoadGlobal Math
32 - [1] unknown $2 = LoadGlobal id
33 - [2] unknown $3 = true
34 - [3] unknown $5 = StoreLocal Let unknown y$15 = unknown $3
35 - [4] unknown $6 = false
36 - [5] unknown $7 = StoreLocal Reassign unknown y$16 = unknown $6
37 - [6] unknown $8 = false
38 - [7] unknown $10 = DeclareLocal Let unknown z$17
39 - [8] unknown $11 = LoadLocal unknown z$17
40 - [9] unknown $12 = LoadLocal unknown x$14
31 + [0] unknown $15 = LoadGlobal Math
32 + [1] unknown $16 = LoadGlobal id
33 + [2] unknown $17 = true
34 + [3] unknown $18 = StoreLocal Let unknown y$19 = unknown $17
35 + [4] unknown $20 = false
36 + [5] unknown $21 = StoreLocal Reassign unknown y$22 = unknown $20
37 + [6] unknown $23 = LoadLocal unknown y$4
38 + [7] unknown $24 = DeclareLocal Let unknown z$25
39 + [8] unknown $26 = LoadLocal unknown z$9
40 + [9] unknown $27 = LoadLocal unknown x$0
41 [10] Return unknown $12
compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@if-statement.js.snap
+5 -5
@@ -23,18 +23,18 @@ function foo(
23 )
24 entry bb0
25 bb0 (block)
26 - [0] unknown $6 = LoadLocal unknown a$9
26 + [0] unknown $13 = LoadLocal unknown a$0
27 [1] If unknown $6 consequent=bb2 alternate=bb4 fallthrough=bb1
28 bb2 (block)
29 predecessors: bb0
30 - [2] unknown $4 = LoadLocal unknown b$10
30 + [2] unknown $14 = LoadLocal unknown b$1
31 [3] Return unknown $4
32 bb4 (block)
33 predecessors: bb0
34 - [4] unknown $5 = LoadLocal unknown c$11
34 + [4] unknown $15 = LoadLocal unknown c$2
35 [5] Goto bb1
36 bb1 (block)
37 predecessors: bb4
38 - [6] unknown $7 = LoadLocal unknown d$12
39 - [7] unknown $8 = <undefined>
38 + [6] unknown $16 = LoadLocal unknown d$3
39 + [7] unknown $17 = <undefined>
40 [8] Return unknown $8
compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@simple-function.js.snap
+17 -17
@@ -21,26 +21,26 @@ function Component(
21 )
22 entry bb0
23 bb0 (block)
24 - [0] unknown $1 = LoadGlobal Math
25 - [1] unknown $2 = 0
26 - [2] unknown $4 = StoreLocal Let unknown b$24 = unknown $2
27 - [3] unknown $17 = Function @deps[] @context[unknown a$23, unknown b$24]:
24 + [0] unknown $24 = LoadGlobal Math
25 + [1] unknown $25 = 0
26 + [2] unknown $26 = StoreLocal Let unknown b$27 = unknown $25
27 + [3] unknown $28 = Function @deps[] @context[unknown a$23, unknown b$27]:
28 function foo_(
29 - unknown c$25,
29 + unknown c$29,
30 )
31 entry bb1
32 bb1 (block)
33 - [0] unknown $6 = 1
34 - [1] unknown $8 = StoreLocal Let unknown d$26 = unknown $6
35 - [2] unknown $9 = LoadLocal unknown a$23
36 - [3] unknown $10 = 0
37 - [4] unknown $11 = Binary unknown $9 + unknown $10
38 - [5] unknown $12 = LoadLocal unknown c$25
39 - [6] unknown $13 = Binary unknown $11 + unknown $12
40 - [7] unknown $14 = 1
41 - [8] unknown $15 = Binary unknown $13 + unknown $14
33 + [0] unknown $30 = 1
34 + [1] unknown $31 = StoreLocal Let unknown d$32 = unknown $30
35 + [2] unknown $33 = LoadLocal unknown a$0
36 + [3] unknown $34 = LoadLocal unknown b$3
37 + [4] unknown $35 = Binary unknown $33 + unknown $34
38 + [5] unknown $36 = LoadLocal unknown c$5
39 + [6] unknown $37 = Binary unknown $35 + unknown $36
40 + [7] unknown $38 = LoadLocal unknown d$7
41 + [8] unknown $39 = Binary unknown $37 + unknown $38
42 [9] Return unknown $15
43 - [4] unknown $19 = StoreLocal Const unknown foo$27 = unknown $17
44 - [5] unknown $20 = LoadLocal unknown foo$27
45 - [6] unknown $21 = Call unknown $20()
43 + [4] unknown $40 = StoreLocal Const unknown foo$41 = unknown $28
44 + [5] unknown $42 = LoadLocal unknown foo$18
45 + [6] unknown $43 = Call unknown $42()
46 [7] Return unknown $21
compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@simple.js.snap
+9 -9
@@ -15,13 +15,13 @@ function test(
15 )
16 entry bb0
17 bb0 (block)
18 - [0] unknown $0 = true
19 - [1] unknown $1 = false
20 - [2] unknown $2 = null
21 - [3] unknown $3 = 1
22 - [4] unknown $4 = 3.14
23 - [5] unknown $5 = "hello world!"
24 - [6] unknown $6 = Array [unknown $5]
25 - [7] unknown $7 = Array [unknown $0, unknown $1, unknown $2, unknown $3, unknown $4, ...unknown $6]
26 - [8] unknown $8 = 2
18 + [0] unknown $10 = true
19 + [1] unknown $11 = false
20 + [2] unknown $12 = null
21 + [3] unknown $13 = 1
22 + [4] unknown $14 = 3.14
23 + [5] unknown $15 = "hello world!"
24 + [6] unknown $16 = Array [unknown $15]
25 + [7] unknown $17 = Array [unknown $10, unknown $11, unknown $12, unknown $13, unknown $14, ...unknown $16]
26 + [8] unknown $18 = 2
27 [9] Return unknown $8
compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@ssa-reassign-if.js.snap
+20 -23
@@ -29,45 +29,42 @@ function Component(
29 )
30 entry bb0
31 bb0 (block)
32 - [0] unknown $3 = DeclareLocal Let unknown x$28
33 - [1] unknown $4 = 0
34 - [2] unknown $6 = StoreLocal Let unknown y$29 = unknown $4
35 - [3] unknown $7 = 10
36 - [4] unknown $9 = StoreLocal Let unknown z$30 = unknown $7
37 - [5] unknown $19 = LoadLocal unknown a$26
32 + [0] unknown $28 = DeclareLocal Let unknown x$29
33 + [1] unknown $30 = 0
34 + [2] unknown $31 = StoreLocal Let unknown y$32 = unknown $30
35 + [3] unknown $33 = 10
36 + [4] unknown $34 = StoreLocal Let unknown z$35 = unknown $33
37 + [5] unknown $36 = LoadLocal unknown a$0
38 [6] If unknown $19 consequent=bb2 alternate=bb6 fallthrough=bb1
39 bb2 (block)
40 predecessors: bb0
41 - [7] unknown $10 = 1
42 - [8] unknown $11 = StoreLocal Reassign unknown x$31 = unknown $10
43 - [9] unknown $16 = LoadLocal unknown b$27
41 + [7] unknown $37 = 1
42 + [8] unknown $38 = StoreLocal Reassign unknown x$39 = unknown $37
43 + [9] unknown $40 = LoadLocal unknown b$1
44 [10] If unknown $16 consequent=bb4 alternate=bb5 fallthrough=bb3
45 bb4 (block)
46 predecessors: bb2
47 - [11] unknown $12 = 20
48 - [12] unknown $13 = StoreLocal Reassign unknown z$32 = unknown $12
47 + [11] unknown $41 = 20
48 + [12] unknown $42 = StoreLocal Reassign unknown z$43 = unknown $41
49 [13] Goto bb3
50 bb5 (block)
51 predecessors: bb2
52 - [14] unknown $14 = 30
53 - [15] unknown $15 = StoreLocal Reassign unknown z$33 = unknown $14
52 + [14] unknown $44 = 30
53 + [15] unknown $45 = StoreLocal Reassign unknown z$46 = unknown $44
54 [16] Goto bb3
55 bb3 (block)
56 predecessors: bb4, bb5
57 - z$40: phi(bb4: z$32, bb5: z$33)
57 [17] Goto bb1
58 bb6 (block)
59 predecessors: bb0
61 - [18] unknown $17 = 2
62 - [19] unknown $18 = StoreLocal Reassign unknown x$34 = unknown $17
60 + [18] unknown $47 = 2
61 + [19] unknown $48 = StoreLocal Reassign unknown x$49 = unknown $47
62 [20] Goto bb1
63 bb1 (block)
64 predecessors: bb3, bb6
66 - x$35: phi(bb3: x$31, bb6: x$34)
67 - z$39: phi(bb3: z$40, bb6: z$30)
68 - [21] unknown $20 = LoadLocal unknown x$35
69 - [22] unknown $21 = 0
70 - [23] unknown $22 = Binary unknown $20 + unknown $21
71 - [24] unknown $23 = LoadLocal unknown z$39
72 - [25] unknown $24 = Binary unknown $22 + unknown $23
65 + [21] unknown $50 = LoadLocal unknown x$2
66 + [22] unknown $51 = LoadLocal unknown y$5
67 + [23] unknown $52 = Binary unknown $50 + unknown $51
68 + [24] unknown $53 = LoadLocal unknown z$8
69 + [25] unknown $54 = Binary unknown $52 + unknown $53
70 [26] Return unknown $24
compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@use-memo.js.snap
+7 -7
@@ -18,17 +18,17 @@ function Component(
18 )
19 entry bb0
20 bb0 (block)
21 - [0] unknown $1 = LoadGlobal useMemo
22 - [1] unknown $14 = DeclareLocal Let unknown t$12
21 + [0] unknown $11 = LoadGlobal useMemo
22 + [1] unknown $20 = DeclareLocal Let unknown t$18
23 [2] Label block=bb1 fallthrough=bb6
24 bb1 (block)
25 predecessors: bb0
26 - [3] unknown $2 = LoadGlobal y
27 - [4] unknown $13 = StoreLocal Reassign unknown t$12 = unknown $2
26 + [3] unknown $13 = LoadGlobal y
27 + [4] unknown $19 = StoreLocal Reassign unknown t$18 = unknown $2
28 [5] Goto bb6
29 bb6 (block)
30 predecessors: bb1
31 - [6] unknown $5 = LoadLocal unknown t$12
32 - [7] unknown $7 = StoreLocal Const unknown x$11 = unknown $5
33 - [8] unknown $8 = LoadLocal unknown x$11
31 + [6] unknown $14 = LoadLocal unknown t$18
32 + [7] unknown $15 = StoreLocal Const unknown x$16 = unknown $14
33 + [8] unknown $17 = LoadLocal unknown x$6
34 [9] Return unknown $8
compiler/forget/crates/forget_hir/src/instruction.rs
+121 -24
@@ -16,17 +16,20 @@ pub struct Instruction {
16 impl Instruction {
17 pub fn each_identifier_store<F>(&mut self, mut f: F) -> ()
18 where
19 - F: FnMut(&mut LValue) -> (),
19 + F: FnMut(&mut IdentifierOperand) -> (),
20 {
21 match &mut self.value {
22 InstructionValue::DeclareContext(instr) => {
23 - f(&mut instr.lvalue);
23 + f(&mut instr.lvalue.identifier);
24 }
25 InstructionValue::DeclareLocal(instr) => {
26 - f(&mut instr.lvalue);
26 + f(&mut instr.lvalue.identifier);
27 }
28 InstructionValue::StoreLocal(instr) => {
29 - f(&mut instr.lvalue);
29 + f(&mut instr.lvalue.identifier);
30 + }
31 + InstructionValue::Destructure(instr) => {
32 + instr.pattern.each_operand(f);
33 }
34 InstructionValue::Array(_)
35 | InstructionValue::Binary(_)
@@ -43,18 +46,19 @@ impl Instruction {
46
47 pub fn try_each_identifier_store<F, E>(&mut self, mut f: F) -> Result<(), E>
48 where
46 - F: FnMut(&mut LValue) -> Result<(), E>,
49 + F: FnMut(&mut IdentifierOperand) -> Result<(), E>,
50 {
51 match &mut self.value {
52 InstructionValue::DeclareContext(instr) => {
50 - f(&mut instr.lvalue)?;
53 + f(&mut instr.lvalue.identifier)?;
54 }
55 InstructionValue::DeclareLocal(instr) => {
53 - f(&mut instr.lvalue)?;
56 + f(&mut instr.lvalue.identifier)?;
57 }
58 InstructionValue::StoreLocal(instr) => {
56 - f(&mut instr.lvalue)?;
59 + f(&mut instr.lvalue.identifier)?;
60 }
61 + InstructionValue::Destructure(instr) => instr.pattern.try_each_operand(f)?,
62 InstructionValue::Array(_)
63 | InstructionValue::Binary(_)
64 | InstructionValue::Call(_)
@@ -73,21 +77,23 @@ impl Instruction {
77 where
78 F: FnMut(&mut IdentifierOperand) -> (),
79 {
76 - match &mut self.value {
77 - InstructionValue::LoadLocal(instr) => f(&mut instr.place),
78 - InstructionValue::Array(_)
79 - | InstructionValue::Binary(_)
80 - | InstructionValue::Call(_)
81 - | InstructionValue::DeclareContext(_)
82 - | InstructionValue::DeclareLocal(_)
83 - | InstructionValue::LoadContext(_)
84 - | InstructionValue::LoadGlobal(_)
85 - | InstructionValue::Primitive(_)
86 - | InstructionValue::StoreLocal(_)
87 - | InstructionValue::Function(_)
88 - | InstructionValue::JSXElement(_)
89 - | InstructionValue::Tombstone => {}
90 - }
80 + // match &mut self.value {
81 + // InstructionValue::LoadLocal(instr) => f(&mut instr.place),
82 + // InstructionValue::Array(_)
83 + // | InstructionValue::Binary(_)
84 + // | InstructionValue::Call(_)
85 + // | InstructionValue::DeclareContext(_)
86 + // | InstructionValue::DeclareLocal(_)
87 + // | InstructionValue::Destructure(_)
88 + // | InstructionValue::LoadContext(_)
89 + // | InstructionValue::LoadGlobal(_)
90 + // | InstructionValue::Primitive(_)
91 + // | InstructionValue::StoreLocal(_)
92 + // | InstructionValue::Function(_)
93 + // | InstructionValue::JSXElement(_)
94 + // | InstructionValue::Tombstone => {}
95 + // }
96 + self.each_operand(f);
97 }
98
99 pub fn each_operand<F>(&mut self, mut f: F) -> ()
@@ -139,6 +145,9 @@ impl Instruction {
145 }
146 }
147 }
148 + InstructionValue::Destructure(value) => {
149 + f(&mut value.value);
150 + }
151 InstructionValue::DeclareContext(_)
152 | InstructionValue::LoadContext(_)
153 | InstructionValue::LoadGlobal(_)
@@ -162,7 +171,7 @@ pub enum InstructionValue {
171 // Debugger(Debugger),
172 DeclareContext(DeclareContext),
173 DeclareLocal(DeclareLocal),
165 - // Destructure(Destructure),
174 + Destructure(Destructure),
175 Function(FunctionExpression),
176 JSXElement(JSXElement),
177 // JsxFragment(JsxFragment),
@@ -272,6 +281,94 @@ pub enum JSXAttribute {
281 },
282 }
283
284 +#[derive(Debug)]
285 +pub struct Destructure {
286 + pub kind: InstructionKind,
287 + pub pattern: DestructurePattern,
288 + pub value: IdentifierOperand,
289 +}
290 +
291 +#[derive(Debug)]
292 +pub enum DestructurePattern {
293 + Array(Vec<ArrayDestructureItem>),
294 + Object(Vec<ObjectDestructureItem>),
295 +}
296 +
297 +impl DestructurePattern {
298 + pub fn try_each_operand<E, F>(&mut self, mut f: F) -> Result<(), E>
299 + where
300 + F: FnMut(&mut IdentifierOperand) -> Result<(), E>,
301 + {
302 + match self {
303 + Self::Array(elements) => {
304 + for item in elements {
305 + match item {
306 + ArrayDestructureItem::Hole => { /* no-op */ }
307 + ArrayDestructureItem::Value(item) => f(item)?,
308 + ArrayDestructureItem::Spread(item) => f(item)?,
309 + }
310 + }
311 + }
312 + Self::Object(properties) => {
313 + for property in properties {
314 + match property {
315 + ObjectDestructureItem::Property(property) => {
316 + f(&mut property.value)?;
317 + }
318 + ObjectDestructureItem::Spread(property) => f(property)?,
319 + }
320 + }
321 + }
322 + }
323 + Ok(())
324 + }
325 + pub fn each_operand<F>(&mut self, mut f: F) -> ()
326 + where
327 + F: FnMut(&mut IdentifierOperand) -> (),
328 + {
329 + match self {
330 + Self::Array(elements) => {
331 + for item in elements {
332 + match item {
333 + ArrayDestructureItem::Hole => { /* no-op */ }
334 + ArrayDestructureItem::Value(item) => f(item),
335 + ArrayDestructureItem::Spread(item) => f(item),
336 + }
337 + }
338 + }
339 + Self::Object(properties) => {
340 + for property in properties {
341 + match property {
342 + ObjectDestructureItem::Property(property) => {
343 + f(&mut property.value);
344 + }
345 + ObjectDestructureItem::Spread(property) => f(property),
346 + }
347 + }
348 + }
349 + }
350 + }
351 +}
352 +
353 +#[derive(Debug)]
354 +pub enum ArrayDestructureItem {
355 + Hole,
356 + Value(IdentifierOperand),
357 + Spread(IdentifierOperand),
358 +}
359 +
360 +#[derive(Debug)]
361 +pub enum ObjectDestructureItem {
362 + Property(ObjectDestructureProperty),
363 + Spread(IdentifierOperand),
364 +}
365 +
366 +#[derive(Debug)]
367 +pub struct ObjectDestructureProperty {
368 + pub name: String,
369 + pub value: IdentifierOperand,
370 +}
371 +
372 #[derive(Clone, Debug)]
373 pub struct IdentifierOperand {
374 pub identifier: Identifier,
compiler/forget/crates/forget_hir/src/print.rs
+57 -2
@@ -4,8 +4,9 @@ use forget_estree::JsValue;
4 use forget_utils::ensure_sufficient_stack;
5
6 use crate::{
7 - BasicBlock, Function, Identifier, IdentifierOperand, Instruction, InstructionValue, LValue,
8 - Phi, PlaceOrSpread, Terminal, TerminalValue, HIR,
7 + ArrayDestructureItem, BasicBlock, DestructurePattern, Function, Identifier, IdentifierOperand,
8 + Instruction, InstructionValue, LValue, ObjectDestructureItem, Phi, PlaceOrSpread, Terminal,
9 + TerminalValue, HIR,
10 };
11
12 /// Trait for HIR types to describe how they print themselves.
@@ -205,6 +206,12 @@ impl Print for InstructionValue {
206 .collect();
207 write!(out, "{}", lines.join("\n"))?;
208 }
209 + InstructionValue::Destructure(value) => {
210 + write!(out, "Destructure ")?;
211 + value.pattern.print(hir, out)?;
212 + write!(out, " = ")?;
213 + value.value.print(hir, out)?;
214 + }
215 InstructionValue::Tombstone => {
216 write!(out, "Tombstone!")?;
217 }
@@ -262,6 +269,54 @@ impl Print for Identifier {
269 }
270 }
271
272 +impl Print for DestructurePattern {
273 + fn print(&self, hir: &HIR, out: &mut impl Write) -> Result {
274 + match self {
275 + DestructurePattern::Array(items) => {
276 + write!(out, "[ ")?;
277 + for (index, item) in items.iter().enumerate() {
278 + if index != 0 {
279 + write!(out, ", ")?;
280 + }
281 + match item {
282 + ArrayDestructureItem::Hole => {
283 + write!(out, "<hole>")?;
284 + }
285 + ArrayDestructureItem::Value(item) => {
286 + item.print(hir, out)?;
287 + }
288 + ArrayDestructureItem::Spread(item) => {
289 + write!(out, "...")?;
290 + item.print(hir, out)?;
291 + }
292 + }
293 + }
294 + write!(out, " ]")?;
295 + }
296 + DestructurePattern::Object(properties) => {
297 + write!(out, "{{ ")?;
298 + for (index, property) in properties.iter().enumerate() {
299 + if index != 0 {
300 + write!(out, ", ")?;
301 + }
302 + match property {
303 + ObjectDestructureItem::Property(property) => {
304 + write!(out, "{}: ", &property.name)?;
305 + property.value.print(hir, out)?;
306 + }
307 + ObjectDestructureItem::Spread(property) => {
308 + write!(out, "...")?;
309 + property.print(hir, out)?;
310 + }
311 + }
312 + }
313 + write!(out, " }}")?;
314 + }
315 + }
316 + Ok(())
317 + }
318 +}
319 +
320 impl Print for Terminal {
321 fn print(&self, hir: &HIR, out: &mut impl Write) -> Result {
322 write!(out, " {} ", self.id)?;
compiler/forget/crates/forget_semantic_analysis/src/analyzer.rs
+28 -23
@@ -6,7 +6,8 @@ use forget_estree::{
6 };
7
8 use crate::{
9 - AstNode, DeclarationKind, LabelId, LabelKind, ReferenceKind, ScopeId, ScopeKind, ScopeManager,
9 + AstNode, DeclarationKind, Label, LabelId, LabelKind, ReferenceKind, ScopeId, ScopeKind,
10 + ScopeManager,
11 };
12
13 pub fn analyze(ast: &Program) -> ScopeManager {
@@ -43,18 +44,18 @@ impl Analyzer {
44 assert_eq!(last, id);
45 }
46
46 - fn lookup_break(&self, name: Option<&str>) -> Option<LabelId> {
47 + fn lookup_break(&self, name: Option<&str>) -> Option<&Label> {
48 for id in self.labels.iter().rev() {
49 let label = self.manager.label(*id);
50 match (name, &label.name) {
51 // If this is a labeled break, only return if an exact match
52 // is in scope
53 (Some(name), Some(label_name)) if name == label_name => {
53 - return Some(label.id);
54 + return Some(label);
55 }
56 // If this is an unlabeld break, return the innermost label id
57 (None, _) => {
57 - return Some(label.id);
58 + return Some(label);
59 }
60 _ => { /* no-op */ }
61 }
@@ -62,22 +63,18 @@ impl Analyzer {
63 None
64 }
65
65 - fn lookup_continue(&self, name: Option<&str>) -> Option<LabelId> {
66 + fn lookup_continue(&self, name: Option<&str>) -> Option<&Label> {
67 for id in self.labels.iter().rev() {
68 let label = self.manager.label(*id);
68 - // Skip labels that are not for loops, can only continue to a loop
69 - if label.kind != LabelKind::Loop {
70 - continue;
71 - }
69 match (name, &label.name) {
70 // If this is a labeled break, only return if an exact match
71 // is in scope
72 (Some(name), Some(label_name)) if &name == label_name => {
76 - return Some(label.id);
73 + return Some(label);
74 }
75 // If this is an unlabeld break, return the innermost label id
76 (None, _) => {
80 - return Some(label.id);
77 + return Some(label);
78 }
79 _ => { /* no-op */ }
80 }
@@ -425,16 +422,14 @@ impl Visitor for Analyzer {
422 }
423
424 fn visit_break_statement(&mut self, ast: &forget_estree::BreakStatement) {
428 - if let Some(label_id) =
429 - self.lookup_break(ast.label.as_ref().map(|ident| ident.name.as_str()))
425 + if let Some(label) = self.lookup_break(ast.label.as_ref().map(|ident| ident.name.as_str()))
426 {
431 - self.manager
432 - .node_labels
433 - .insert(AstNode::from(ast), label_id);
427 + let id = label.id;
428 + self.manager.node_labels.insert(AstNode::from(ast), id);
429 if let Some(label_node) = &ast.label {
430 self.manager
431 .node_labels
437 - .insert(AstNode::from(label_node), label_id);
432 + .insert(AstNode::from(label_node), id);
433 }
434 } else {
435 self.manager.diagnostics.push(Diagnostic::invalid_syntax(
@@ -462,21 +457,31 @@ impl Visitor for Analyzer {
457 }
458
459 fn visit_continue_statement(&mut self, ast: &forget_estree::ContinueStatement) {
465 - if let Some(label_id) =
460 + let range = ast
461 + .label
462 + .as_ref()
463 + .map(|label| label.range)
464 + .unwrap_or(ast.range);
465 + if let Some(label) =
466 self.lookup_continue(ast.label.as_ref().map(|ident| ident.name.as_str()))
467 {
468 - self.manager
469 - .node_labels
470 - .insert(AstNode::from(ast), label_id);
468 + let id = label.id;
469 + if label.kind != LabelKind::Loop {
470 + self.manager.diagnostics.push(Diagnostic::invalid_syntax(
471 + "Invalid continue statement, the named label must be for a loop",
472 + range,
473 + ));
474 + }
475 + self.manager.node_labels.insert(AstNode::from(ast), id);
476 if let Some(label_node) = &ast.label {
477 self.manager
478 .node_labels
474 - .insert(AstNode::from(label_node), label_id);
479 + .insert(AstNode::from(label_node), id);
480 }
481 } else {
482 self.manager.diagnostics.push(Diagnostic::invalid_syntax(
483 "Non-syntactic continue, could not resolve continue target",
479 - ast.range,
484 + range,
485 ));
486 }
487 }
compiler/forget/crates/forget_ssa/src/eliminate_redundant_phis.rs
+1 -3
@@ -70,9 +70,7 @@ pub fn eliminate_redundant_phis(env: &Environment, fun: &mut Function) {
70
71 for instr_ix in block.instructions.iter() {
72 let instr = &mut hir.instructions[usize::from(*instr_ix)];
73 - instr.each_identifier_store(|store| {
74 - rewrite(&rewrites, &mut store.identifier.identifier)
75 - });
73 + instr.each_identifier_store(|store| rewrite(&rewrites, &mut store.identifier));
74 instr.each_identifier_load(|load| rewrite(&rewrites, &mut load.identifier));
75
76 if let InstructionValue::Function(fun) = &mut instr.value {
compiler/forget/crates/forget_ssa/src/enter.rs
+5 -4
@@ -47,6 +47,7 @@ fn visit_instructions<'e, 'f>(
47 builder.each_block(|block, builder| {
48 for instr_ix in &block.instructions {
49 let instr = &mut instructions[usize::from(*instr_ix)];
50 + builder.visit_store(&mut instr.lvalue)?;
51 instr.try_each_identifier_store(|store| builder.visit_store(store))?;
52 instr.each_identifier_load(|load| builder.visit_load(load));
53
@@ -139,8 +140,8 @@ impl<'e, 'f> Builder<'e, 'f> {
140 self.env.next_identifier_id()
141 }
142
142 - fn visit_store(&mut self, lvalue: &mut LValue) -> Result<(), Diagnostic> {
143 - let old_identifier = &lvalue.identifier.identifier;
143 + fn visit_store(&mut self, lvalue: &mut IdentifierOperand) -> Result<(), Diagnostic> {
144 + let old_identifier = &lvalue.identifier;
145 // TODO: use Result (?)
146 invariant(!self.unknown.contains(&old_identifier.id), || {
147 Diagnostic::invariant(
@@ -151,14 +152,14 @@ impl<'e, 'f> Builder<'e, 'f> {
152
153 if self.context.contains(&old_identifier.id) {
154 let new_identifier = self.get_id_at(self.current, old_identifier);
154 - lvalue.identifier.identifier = new_identifier;
155 + lvalue.identifier = new_identifier;
156 return Ok(());
157 }
158
159 let new_identifier = self.make_identifier(old_identifier);
160 let state = self.states.get_mut(&self.current).unwrap();
161 state.defs.insert(old_identifier.id, new_identifier.clone());
161 - lvalue.identifier.identifier = new_identifier;
162 + lvalue.identifier = new_identifier;
163 Ok(())
164 }
165