diff --git a/compiler/forget/crates/forget_build_hir/src/build.rs b/compiler/forget/crates/forget_build_hir/src/build.rs index 1878a4a1ed..c2ef985b3d 100644 --- a/compiler/forget/crates/forget_build_hir/src/build.rs +++ b/compiler/forget/crates/forget_build_hir/src/build.rs @@ -2,14 +2,15 @@ use std::collections::HashSet; use forget_diagnostics::Diagnostic; use forget_estree::{ - AssignmentTarget, BlockStatement, Expression, ExpressionOrSpread, ExpressionOrSuper, ForInit, - Function, IntoFunction, JsValue, Pattern, Statement, VariableDeclaration, - VariableDeclarationKind, + AssignmentPropertyOrRestElement, AssignmentTarget, BlockStatement, Expression, + ExpressionOrSpread, ExpressionOrSuper, ForInit, Function, IntoFunction, JsValue, Pattern, + Statement, VariableDeclaration, VariableDeclarationKind, }; use forget_hir::{ - BlockKind, BranchTerminal, Environment, ForTerminal, GotoKind, IdentifierOperand, - InstructionKind, InstructionValue, JSXAttribute, JSXElement, LValue, LoadGlobal, LoadLocal, - PlaceOrSpread, TerminalValue, + ArrayDestructureItem, BlockKind, BranchTerminal, Destructure, DestructurePattern, Environment, + ForTerminal, GotoKind, Identifier, IdentifierOperand, InstructionKind, InstructionValue, + JSXAttribute, JSXElement, LValue, LoadGlobal, LoadLocal, ObjectDestructureItem, + ObjectDestructureProperty, PlaceOrSpread, TerminalValue, }; use crate::builder::{Builder, LoopScope}; @@ -303,8 +304,8 @@ fn lower_variable_declaration( } } _ => { - return Err(Diagnostic::todo( - "Handle non-identifier variable declarations", + return Err(Diagnostic::invalid_syntax( + "Expected an identifier for variable declaration without an intializer. Destructuring requires an initial value", declaration.range, )); } @@ -543,6 +544,7 @@ fn lower_assignment( }) } +// TODO: change the success type to void, no caller uses it fn lower_assignment_pattern( env: &Environment, builder: &mut Builder, @@ -558,6 +560,147 @@ fn lower_assignment_pattern( value, })) } + Pattern::ArrayPattern(lvalue) => { + let mut items = Vec::with_capacity(lvalue.elements.len()); + let mut followups: Vec<(Identifier, &Pattern)> = Vec::new(); + for element in &lvalue.elements { + match element { + None => items.push(ArrayDestructureItem::Hole), + Some(Pattern::Identifier(element)) => { + let identifier = + lower_identifier_for_assignment(env, builder, kind, &element)?; + items.push(ArrayDestructureItem::Value(identifier)); + } + Some(Pattern::RestElement(element)) => { + if let Pattern::Identifier(element) = &element.argument { + let identifier = lower_identifier_for_assignment( + env, + builder, + kind, + element.as_ref(), + )?; + items.push(ArrayDestructureItem::Spread(identifier)); + } else { + let temporary = env.new_temporary(); + items.push(ArrayDestructureItem::Spread(IdentifierOperand { + identifier: temporary.clone(), + effect: None, + })); + followups.push((temporary, &element.argument)); + } + } + Some(element) => { + let temporary = env.new_temporary(); + items.push(ArrayDestructureItem::Value(IdentifierOperand { + identifier: temporary.clone(), + effect: None, + })); + followups.push((temporary, element)); + } + } + } + let temporary = builder.push(InstructionValue::Destructure(Destructure { + kind, + pattern: DestructurePattern::Array(items), + value, + })); + for (temporary, pattern) in followups { + lower_assignment_pattern( + env, + builder, + kind, + pattern, + IdentifierOperand { + identifier: temporary, + effect: None, + }, + )?; + } + temporary + } + Pattern::ObjectPattern(lvalue) => { + let mut properties = Vec::with_capacity(lvalue.properties.len()); + let mut followups: Vec<(Identifier, &Pattern)> = Vec::new(); + + for property in &lvalue.properties { + match property { + AssignmentPropertyOrRestElement::RestElement(property) => { + if let Pattern::Identifier(element) = &property.argument { + let identifier = lower_identifier_for_assignment( + env, + builder, + kind, + element.as_ref(), + )?; + properties.push(ObjectDestructureItem::Spread(identifier)); + } else { + let temporary = env.new_temporary(); + properties.push(ObjectDestructureItem::Spread(IdentifierOperand { + identifier: temporary.clone(), + effect: None, + })); + followups.push((temporary, &property.argument)); + } + } + AssignmentPropertyOrRestElement::AssignmentProperty(property) => { + if property.is_computed { + return Err(Diagnostic::todo( + "Handle computed properties in ObjectPattern", + property.range, + )); + } + let key = if let Expression::Identifier(key) = &property.key { + key.name.as_str() + } else { + return Err(Diagnostic::todo( + "Support non-identifier object keys in non-computed ObjectPattern", + property.range, + )); + }; + if let Pattern::Identifier(value) = &property.value { + let value = lower_identifier_for_assignment(env, builder, kind, value)?; + properties.push(ObjectDestructureItem::Property( + ObjectDestructureProperty { + name: key.to_string(), + value, + }, + )); + } else { + let temporary = env.new_temporary(); + properties.push(ObjectDestructureItem::Property( + ObjectDestructureProperty { + name: key.to_string(), + value: IdentifierOperand { + identifier: temporary.clone(), + effect: None, + }, + }, + )); + followups.push((temporary, &property.value)); + } + } + } + } + + let temporary = builder.push(InstructionValue::Destructure(Destructure { + kind, + pattern: DestructurePattern::Object(properties), + value, + })); + for (temporary, pattern) in followups { + lower_assignment_pattern( + env, + builder, + kind, + pattern, + IdentifierOperand { + identifier: temporary, + effect: None, + }, + )?; + } + temporary + } _ => todo!("lower assignment pattern for {:#?}", lvalue), }) } diff --git a/compiler/forget/crates/forget_fixtures/tests/fixtures/destructure-array.js b/compiler/forget/crates/forget_fixtures/tests/fixtures/destructure-array.js new file mode 100644 index 0000000000..680fb5daec --- /dev/null +++ b/compiler/forget/crates/forget_fixtures/tests/fixtures/destructure-array.js @@ -0,0 +1,5 @@ +function Component(a, b) { + const [c, , ...d] = a; + const [[[e]], ...[f]] = b; + return [c, d, e, f]; +} diff --git a/compiler/forget/crates/forget_fixtures/tests/fixtures/destructure-object.js b/compiler/forget/crates/forget_fixtures/tests/fixtures/destructure-object.js new file mode 100644 index 0000000000..9b3a45e4d4 --- /dev/null +++ b/compiler/forget/crates/forget_fixtures/tests/fixtures/destructure-object.js @@ -0,0 +1,15 @@ +function Component(a, b) { + const { + c, + d, + e: { e }, + f: { _f: f }, + g: { + g: { + g: { g, ...h }, + }, + }, + ...i + } = a; + return [c, d, e, f, g, h, i]; +} diff --git a/compiler/forget/crates/forget_fixtures/tests/fixtures_test.rs b/compiler/forget/crates/forget_fixtures/tests/fixtures_test.rs index 964fccda30..b138481805 100644 --- a/compiler/forget/crates/forget_fixtures/tests/fixtures_test.rs +++ b/compiler/forget/crates/forget_fixtures/tests/fixtures_test.rs @@ -38,6 +38,7 @@ fn fixtures() { match build(&environment, &fun.function) { Ok(mut fun) => { println!("ok build"); + fun.debug(); enter_ssa(&environment, &mut fun).unwrap(); println!("ok enter_ssa"); eliminate_redundant_phis(&environment, &mut fun); diff --git a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@constant-propagation-constant-if-condition.js.snap b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@constant-propagation-constant-if-condition.js.snap index 1b430c572b..ec42376514 100644 --- a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@constant-propagation-constant-if-condition.js.snap +++ b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@constant-propagation-constant-if-condition.js.snap @@ -45,29 +45,73 @@ function Component( ) entry bb0 bb0 (block) - [0] unknown $0 = 1 - [1] unknown $2 = StoreLocal Let unknown a$39 = unknown $0 - [2] unknown $4 = DeclareLocal Let unknown b$40 - [3] unknown $9 = 1 - [4] unknown $10 = 1 - [5] unknown $11 = true - [6] unknown $5 = true - [7] unknown $6 = StoreLocal Reassign unknown b$41 = unknown $5 - [8] unknown $13 = DeclareLocal Let unknown c$43 - [9] unknown $18 = true - [10] unknown $14 = "hello" - [11] unknown $15 = StoreLocal Reassign unknown c$45 = unknown $14 - [12] unknown $20 = DeclareLocal Let unknown d$47 - [13] unknown $25 = "hello" - [14] unknown $26 = "hello" - [15] unknown $27 = true - [16] unknown $21 = 42 - [17] unknown $22 = StoreLocal Reassign unknown d$49 = unknown $21 - [18] unknown $29 = DeclareLocal Let unknown e$51 - [19] unknown $34 = 42 - [20] unknown $35 = 42 - [21] unknown $36 = true - [22] unknown $30 = "ok" - [23] unknown $31 = StoreLocal Reassign unknown e$53 = unknown $30 - [24] unknown $37 = "ok" - [25] Return unknown $37 + [0] unknown $39 = 1 + [1] unknown $40 = StoreLocal Let unknown a$41 = unknown $39 + [2] unknown $42 = DeclareLocal Let unknown b$43 + [3] unknown $44 = LoadLocal unknown a$1 + [4] unknown $45 = 1 + [5] unknown $46 = Binary unknown $44 === unknown $45 + [6] If unknown $11 consequent=bb2 alternate=bb3 fallthrough=bb1 +bb2 (block) + predecessors: bb0 + [7] unknown $47 = true + [8] unknown $48 = StoreLocal Reassign unknown b$49 = unknown $47 + [9] Goto bb1 +bb3 (block) + predecessors: bb0 + [10] unknown $50 = false + [11] unknown $51 = StoreLocal Reassign unknown b$52 = unknown $50 + [12] Goto bb1 +bb1 (block) + predecessors: bb2, bb3 + [13] unknown $53 = DeclareLocal Let unknown c$54 + [14] unknown $55 = LoadLocal unknown b$3 + [15] If unknown $18 consequent=bb5 alternate=bb6 fallthrough=bb4 +bb5 (block) + predecessors: bb1 + [16] unknown $56 = "hello" + [17] unknown $57 = StoreLocal Reassign unknown c$58 = unknown $56 + [18] Goto bb4 +bb6 (block) + predecessors: bb1 + [19] unknown $59 = null + [20] unknown $60 = StoreLocal Reassign unknown c$61 = unknown $59 + [21] Goto bb4 +bb4 (block) + predecessors: bb5, bb6 + [22] unknown $62 = DeclareLocal Let unknown d$63 + [23] unknown $64 = LoadLocal unknown c$12 + [24] unknown $65 = "hello" + [25] unknown $66 = Binary unknown $64 === unknown $65 + [26] If unknown $27 consequent=bb8 alternate=bb9 fallthrough=bb7 +bb8 (block) + predecessors: bb4 + [27] unknown $67 = 42 + [28] unknown $68 = StoreLocal Reassign unknown d$69 = unknown $67 + [29] Goto bb7 +bb9 (block) + predecessors: bb4 + [30] unknown $70 = 42.001 + [31] unknown $71 = StoreLocal Reassign unknown d$72 = unknown $70 + [32] Goto bb7 +bb7 (block) + predecessors: bb8, bb9 + [33] unknown $73 = DeclareLocal Let unknown e$74 + [34] unknown $75 = LoadLocal unknown d$19 + [35] unknown $76 = 42 + [36] unknown $77 = Binary unknown $75 === unknown $76 + [37] If unknown $36 consequent=bb11 alternate=bb12 fallthrough=bb10 +bb11 (block) + predecessors: bb7 + [38] unknown $78 = "ok" + [39] unknown $79 = StoreLocal Reassign unknown e$80 = unknown $78 + [40] Goto bb10 +bb12 (block) + predecessors: bb7 + [41] unknown $81 = "nope" + [42] unknown $82 = StoreLocal Reassign unknown e$83 = unknown $81 + [43] Goto bb10 +bb10 (block) + predecessors: bb11, bb12 + [44] unknown $84 = LoadLocal unknown e$28 + [45] Return unknown $37 diff --git a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@constant-propagation.js.snap b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@constant-propagation.js.snap index d9c4c7e4c3..bece0ad33b 100644 --- a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@constant-propagation.js.snap +++ b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@constant-propagation.js.snap @@ -72,127 +72,125 @@ function Component( ) entry bb0 bb0 (block) - [0] unknown $2 = DeclareLocal Let unknown a$109 - [1] unknown $3 = LoadGlobal Math - [2] unknown $4 = StoreLocal Reassign unknown a$110 = unknown $3 - [3] unknown $5 = LoadGlobal Math - [4] unknown $7 = DeclareLocal Let unknown b$111 - [5] unknown $12 = LoadLocal unknown props$108 + [0] unknown $109 = DeclareLocal Let unknown a$110 + [1] unknown $111 = LoadGlobal Math + [2] unknown $112 = StoreLocal Reassign unknown a$113 = unknown $111 + [3] unknown $114 = LoadLocal unknown a$1 + [4] unknown $115 = DeclareLocal Let unknown b$116 + [5] unknown $117 = LoadLocal unknown props$0 [6] If unknown $12 consequent=bb2 alternate=bb3 fallthrough=bb1 bb2 (block) predecessors: bb0 - [7] unknown $8 = true - [8] unknown $9 = StoreLocal Reassign unknown b$112 = unknown $8 + [7] unknown $118 = true + [8] unknown $119 = StoreLocal Reassign unknown b$120 = unknown $118 [9] Goto bb1 bb3 (block) predecessors: bb0 - [10] unknown $10 = true - [11] unknown $11 = StoreLocal Reassign unknown b$113 = unknown $10 + [10] unknown $121 = true + [11] unknown $122 = StoreLocal Reassign unknown b$123 = unknown $121 [12] Goto bb1 bb1 (block) predecessors: bb2, bb3 - b$114: phi(bb2: b$112, bb3: b$113) - [13] unknown $13 = true - [14] unknown $15 = DeclareLocal Let unknown c$115 - [15] unknown $20 = LoadLocal unknown props$108 + [13] unknown $124 = LoadLocal unknown b$6 + [14] unknown $125 = DeclareLocal Let unknown c$126 + [15] unknown $127 = LoadLocal unknown props$0 [16] If unknown $20 consequent=bb5 alternate=bb6 fallthrough=bb4 bb5 (block) predecessors: bb1 - [17] unknown $16 = true - [18] unknown $17 = StoreLocal Reassign unknown c$117 = unknown $16 + [17] unknown $128 = true + [18] unknown $129 = StoreLocal Reassign unknown c$130 = unknown $128 [19] Goto bb4 bb6 (block) predecessors: bb1 - [20] unknown $18 = 42 - [21] unknown $19 = StoreLocal Reassign unknown c$118 = unknown $18 + [20] unknown $131 = 42 + [21] unknown $132 = StoreLocal Reassign unknown c$133 = unknown $131 [22] Goto bb4 bb4 (block) predecessors: bb5, bb6 - c$119: phi(bb5: c$117, bb6: c$118) - [23] unknown $21 = LoadLocal unknown c$119 - [24] unknown $22 = 42 - [25] unknown $23 = 1 - [26] unknown $24 = 43 - [27] unknown $25 = 42 - [28] unknown $26 = 1 - [29] unknown $27 = 41 - [30] unknown $28 = 42 - [31] unknown $29 = 2 - [32] unknown $30 = 84 - [33] unknown $31 = 42 - [34] unknown $32 = 2 - [35] unknown $33 = 21 - [36] unknown $34 = 0 - [37] unknown $35 = 1 - [38] unknown $36 = false - [39] unknown $37 = 0 - [40] unknown $38 = 1 - [41] unknown $39 = true - [42] unknown $40 = 0 - [43] unknown $41 = 1 - [44] unknown $42 = false - [45] unknown $43 = 0 - [46] unknown $44 = 1 - [47] unknown $45 = true - [48] unknown $46 = 0 - [49] unknown $47 = 0 - [50] unknown $48 = true - [51] unknown $49 = LoadGlobal NaN - [52] unknown $50 = LoadGlobal NaN - [53] unknown $51 = Binary unknown $49 == unknown $50 - [54] unknown $52 = LoadGlobal NaN - [55] unknown $53 = LoadGlobal NaN - [56] unknown $54 = Binary unknown $52 != unknown $53 - [57] unknown $55 = LoadGlobal NaN - [58] unknown $56 = LoadGlobal NaN - [59] unknown $57 = Binary unknown $55 !== unknown $56 - [60] unknown $58 = LoadGlobal NaN - [61] unknown $59 = LoadGlobal NaN - [62] unknown $60 = Binary unknown $58 !== unknown $59 - [63] unknown $61 = "hello" - [64] unknown $62 = "hello" - [65] unknown $63 = true - [66] unknown $64 = "hello" - [67] unknown $65 = "hello" - [68] unknown $66 = false - [69] unknown $67 = "hello" - [70] unknown $68 = "hello" - [71] unknown $69 = true - [72] unknown $70 = "hello" - [73] unknown $71 = "hello" - [74] unknown $72 = false - [75] unknown $73 = "hello" - [76] unknown $74 = "world" - [77] unknown $75 = false - [78] unknown $76 = "hello" - [79] unknown $77 = "world" - [80] unknown $78 = true - [81] unknown $79 = "hello" - [82] unknown $80 = "world" - [83] unknown $81 = false - [84] unknown $82 = "hello" - [85] unknown $83 = "world" - [86] unknown $84 = true - [87] unknown $85 = true - [88] unknown $86 = true - [89] unknown $87 = true - [90] unknown $88 = true - [91] unknown $89 = true - [92] unknown $90 = false - [93] unknown $91 = true - [94] unknown $92 = true - [95] unknown $93 = true - [96] unknown $94 = true - [97] unknown $95 = true - [98] unknown $96 = false - [99] unknown $97 = 5 - [100] unknown $98 = 60 - [101] unknown $99 = 300 - [102] unknown $100 = 60 - [103] unknown $101 = 18000 - [104] unknown $102 = 1000 - [105] unknown $103 = 18000000 - [106] unknown $105 = StoreLocal Let unknown x$120 = unknown $103 - [107] unknown $106 = 18000000 - [108] unknown $107 = + [23] unknown $134 = LoadLocal unknown c$14 + [24] unknown $135 = 42 + [25] unknown $136 = 1 + [26] unknown $137 = 43 + [27] unknown $138 = 42 + [28] unknown $139 = 1 + [29] unknown $140 = 41 + [30] unknown $141 = 42 + [31] unknown $142 = 2 + [32] unknown $143 = 84 + [33] unknown $144 = 42 + [34] unknown $145 = 2 + [35] unknown $146 = 21 + [36] unknown $147 = 0 + [37] unknown $148 = 1 + [38] unknown $149 = false + [39] unknown $150 = 0 + [40] unknown $151 = 1 + [41] unknown $152 = true + [42] unknown $153 = 0 + [43] unknown $154 = 1 + [44] unknown $155 = false + [45] unknown $156 = 0 + [46] unknown $157 = 1 + [47] unknown $158 = true + [48] unknown $159 = 0 + [49] unknown $160 = 0 + [50] unknown $161 = true + [51] unknown $162 = LoadGlobal NaN + [52] unknown $163 = LoadGlobal NaN + [53] unknown $164 = Binary unknown $162 == unknown $163 + [54] unknown $165 = LoadGlobal NaN + [55] unknown $166 = LoadGlobal NaN + [56] unknown $167 = Binary unknown $165 != unknown $166 + [57] unknown $168 = LoadGlobal NaN + [58] unknown $169 = LoadGlobal NaN + [59] unknown $170 = Binary unknown $168 !== unknown $169 + [60] unknown $171 = LoadGlobal NaN + [61] unknown $172 = LoadGlobal NaN + [62] unknown $173 = Binary unknown $171 !== unknown $172 + [63] unknown $174 = "hello" + [64] unknown $175 = "hello" + [65] unknown $176 = true + [66] unknown $177 = "hello" + [67] unknown $178 = "hello" + [68] unknown $179 = false + [69] unknown $180 = "hello" + [70] unknown $181 = "hello" + [71] unknown $182 = true + [72] unknown $183 = "hello" + [73] unknown $184 = "hello" + [74] unknown $185 = false + [75] unknown $186 = "hello" + [76] unknown $187 = "world" + [77] unknown $188 = false + [78] unknown $189 = "hello" + [79] unknown $190 = "world" + [80] unknown $191 = true + [81] unknown $192 = "hello" + [82] unknown $193 = "world" + [83] unknown $194 = false + [84] unknown $195 = "hello" + [85] unknown $196 = "world" + [86] unknown $197 = true + [87] unknown $198 = true + [88] unknown $199 = true + [89] unknown $200 = true + [90] unknown $201 = true + [91] unknown $202 = true + [92] unknown $203 = false + [93] unknown $204 = true + [94] unknown $205 = true + [95] unknown $206 = true + [96] unknown $207 = true + [97] unknown $208 = true + [98] unknown $209 = false + [99] unknown $210 = 5 + [100] unknown $211 = 60 + [101] unknown $212 = 300 + [102] unknown $213 = 60 + [103] unknown $214 = 18000 + [104] unknown $215 = 1000 + [105] unknown $216 = 18000000 + [106] unknown $217 = StoreLocal Let unknown x$218 = unknown $216 + [107] unknown $219 = LoadLocal unknown x$104 + [108] unknown $220 = [109] Return unknown $107 diff --git a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@destructure-array.js.snap b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@destructure-array.js.snap new file mode 100644 index 0000000000..655efb131a --- /dev/null +++ b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@destructure-array.js.snap @@ -0,0 +1,33 @@ +--- +source: crates/forget_fixtures/tests/fixtures_test.rs +expression: "format!(\"Input:\\n{input}\\n\\nOutput:\\n{output}\")" +input_file: crates/forget_fixtures/tests/fixtures/destructure-array.js +--- +Input: +function Component(a, b) { + const [c, , ...d] = a; + const [[[e]], ...[f]] = b; + return [c, d, e, f]; +} + + +Output: +function Component( + unknown a$22, + unknown b$23, +) +entry bb0 +bb0 (block) + [0] unknown $24 = LoadLocal unknown a$0 + [1] unknown $25 = Destructure [ unknown c$26, , ...unknown d$27 ] = unknown $24 + [2] unknown $28 = LoadLocal unknown b$1 + [3] unknown $29 = Destructure [ unknown $30, ...unknown $31 ] = unknown $28 + [4] unknown $32 = Destructure [ unknown $33 ] = unknown $30 + [5] unknown $34 = Destructure [ unknown e$35 ] = unknown $33 + [6] unknown $36 = Destructure [ unknown f$37 ] = unknown $31 + [7] unknown $38 = LoadLocal unknown c$3 + [8] unknown $39 = LoadLocal unknown d$4 + [9] unknown $40 = LoadLocal unknown e$12 + [10] unknown $41 = LoadLocal unknown f$14 + [11] unknown $42 = Array [unknown $38, unknown $39, unknown $40, unknown $41] + [12] Return unknown $20 diff --git a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@destructure-object.js.snap b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@destructure-object.js.snap new file mode 100644 index 0000000000..8d355e0c08 --- /dev/null +++ b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@destructure-object.js.snap @@ -0,0 +1,46 @@ +--- +source: crates/forget_fixtures/tests/fixtures_test.rs +expression: "format!(\"Input:\\n{input}\\n\\nOutput:\\n{output}\")" +input_file: crates/forget_fixtures/tests/fixtures/destructure-object.js +--- +Input: +function Component(a, b) { + const { + c, + d, + e: { e }, + f: { _f: f }, + g: { + g: { + g: { g, ...h }, + }, + }, + ...i + } = a; + return [c, d, e, f, g, h, i]; +} + + +Output: +function Component( + unknown a$30, + unknown b$31, +) +entry bb0 +bb0 (block) + [0] unknown $32 = LoadLocal unknown a$0 + [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 + [2] unknown $40 = Destructure { e: unknown e$41 } = unknown $36 + [3] unknown $42 = Destructure { _f: unknown f$43 } = unknown $37 + [4] unknown $44 = Destructure { g: unknown $45 } = unknown $38 + [5] unknown $46 = Destructure { g: unknown $47 } = unknown $45 + [6] unknown $48 = Destructure { g: unknown g$49, ...unknown h$50 } = unknown $47 + [7] unknown $51 = LoadLocal unknown c$3 + [8] unknown $52 = LoadLocal unknown d$4 + [9] unknown $53 = LoadLocal unknown e$10 + [10] unknown $54 = LoadLocal unknown f$12 + [11] unknown $55 = LoadLocal unknown g$18 + [12] unknown $56 = LoadLocal unknown h$19 + [13] unknown $57 = LoadLocal unknown i$8 + [14] unknown $58 = Array [unknown $51, unknown $52, unknown $53, unknown $54, unknown $55, unknown $56, unknown $57] + [15] Return unknown $28 diff --git a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@for-statement.js.snap b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@for-statement.js.snap index 6b6ed8dbea..9bee04cc82 100644 --- a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@for-statement.js.snap +++ b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@for-statement.js.snap @@ -18,37 +18,35 @@ function foo( ) entry bb0 bb0 (block) - [0] unknown $0 = 0 - [1] unknown $2 = StoreLocal Let unknown x$19 = unknown $0 + [0] unknown $19 = 0 + [1] unknown $20 = StoreLocal Let unknown x$21 = unknown $19 [2] For init=bb3 test=bb1 update=bb4 body=bb5 fallthrough=bb2 bb3 (loop) predecessors: bb0 - [3] unknown $3 = 0 - [4] unknown $5 = StoreLocal Let unknown i$20 = unknown $3 + [3] unknown $22 = 0 + [4] unknown $23 = StoreLocal Let unknown i$24 = unknown $22 [5] Goto bb1 bb1 (loop) predecessors: bb3, bb4 - i$21: phi(bb3: i$20, bb4: i$24) - x$22: phi(bb3: x$19, bb4: x$23) - [6] unknown $14 = LoadLocal unknown i$21 - [7] unknown $15 = 10 - [8] unknown $16 = Binary unknown $14 < unknown $15 + [6] unknown $25 = LoadLocal unknown i$4 + [7] unknown $26 = 10 + [8] unknown $27 = Binary unknown $25 < unknown $26 [9] Branch unknown $16 consequent=bb5 alternate=bb2 bb5 (block) predecessors: bb1 - [10] unknown $10 = LoadLocal unknown x$22 - [11] unknown $11 = LoadLocal unknown i$21 - [12] unknown $12 = Binary unknown $10 + unknown $11 - [13] unknown $13 = StoreLocal Reassign unknown x$23 = unknown $12 + [10] unknown $28 = LoadLocal unknown x$1 + [11] unknown $29 = LoadLocal unknown i$4 + [12] unknown $30 = Binary unknown $28 + unknown $29 + [13] unknown $31 = StoreLocal Reassign unknown x$32 = unknown $30 [14] Goto bb4 bb4 (loop) predecessors: bb5 - [15] unknown $6 = LoadLocal unknown i$21 - [16] unknown $7 = 1 - [17] unknown $8 = Binary unknown $6 + unknown $7 - [18] unknown $9 = StoreLocal Reassign unknown i$24 = unknown $8 + [15] unknown $33 = LoadLocal unknown i$4 + [16] unknown $34 = 1 + [17] unknown $35 = Binary unknown $33 + unknown $34 + [18] unknown $36 = StoreLocal Reassign unknown i$37 = unknown $35 [19] Goto bb1 bb2 (block) predecessors: bb1 - [20] unknown $17 = LoadLocal unknown x$22 + [20] unknown $38 = LoadLocal unknown x$1 [21] Return unknown $17 diff --git a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@function-expressions.js.snap b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@function-expressions.js.snap index a9289505c3..669e6cb557 100644 --- a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@function-expressions.js.snap +++ b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@function-expressions.js.snap @@ -33,62 +33,74 @@ function Component( ) entry bb0 bb0 (block) - [0] unknown $1 = 2 - [1] unknown $3 = StoreLocal Const unknown x$59 = unknown $1 - [2] unknown $54 = Function @deps[] @context[unknown x$59]: + [0] unknown $59 = 2 + [1] unknown $60 = StoreLocal Const unknown x$61 = unknown $59 + [2] unknown $62 = Function @deps[] @context[unknown x$61]: function foo( - unknown y$60, + unknown y$63, ) entry bb1 bb1 (block) - [0] unknown $5 = 1 - [1] unknown $7 = StoreLocal Let unknown a$61 = unknown $5 - [2] unknown $9 = DeclareLocal Let unknown b$62 - [3] unknown $16 = 1 - [4] unknown $17 = 1 - [5] unknown $18 = true - [6] unknown $10 = 5 - [7] unknown $11 = 3 - [8] unknown $12 = 8 - [9] unknown $13 = StoreLocal Reassign unknown b$63 = unknown $12 - [10] unknown $19 = 2 - [11] unknown $20 = LoadLocal unknown y$60 - [12] unknown $21 = Binary unknown $19 + unknown $20 - [13] unknown $22 = 1 - [14] unknown $23 = Binary unknown $21 + unknown $22 - [15] unknown $24 = 8 - [16] unknown $25 = Binary unknown $23 + unknown $24 - [17] unknown $48 = Function @deps[] @context[unknown x$59, unknown y$60, unknown a$61, unknown b$63]: + [0] unknown $64 = 1 + [1] unknown $65 = StoreLocal Let unknown a$66 = unknown $64 + [2] unknown $67 = DeclareLocal Let unknown b$68 + [3] unknown $69 = LoadLocal unknown a$6 + [4] unknown $70 = 1 + [5] unknown $71 = Binary unknown $69 === unknown $70 + [6] If unknown $18 consequent=bb3 alternate=bb4 fallthrough=bb2 + bb3 (block) + predecessors: bb1 + [7] unknown $72 = 5 + [8] unknown $73 = 3 + [9] unknown $74 = 8 + [10] unknown $75 = StoreLocal Reassign unknown b$76 = unknown $74 + [11] Goto bb2 + bb4 (block) + predecessors: bb1 + [12] unknown $77 = false + [13] unknown $78 = StoreLocal Reassign unknown b$79 = unknown $77 + [14] Goto bb2 + bb2 (block) + predecessors: bb3, bb4 + b$91: phi(bb3: b$76, bb4: b$79) + [15] unknown $80 = LoadLocal unknown x$2 + [16] unknown $81 = LoadLocal unknown y$4 + [17] unknown $82 = Binary unknown $80 + unknown $81 + [18] unknown $83 = LoadLocal unknown a$6 + [19] unknown $84 = Binary unknown $82 + unknown $83 + [20] unknown $85 = LoadLocal unknown b$8 + [21] unknown $86 = Binary unknown $84 + unknown $85 + [22] unknown $87 = Function @deps[] @context[unknown x$61, unknown y$63, unknown a$66, unknown b$91]: function bar( - unknown z$69, + unknown z$92, ) entry bb5 bb5 (block) - [0] unknown $27 = 2 - [1] unknown $29 = StoreLocal Let unknown c$70 = unknown $27 - [2] unknown $31 = DeclareLocal Let unknown d$71 - [3] unknown $32 = 3 - [4] unknown $33 = StoreLocal Reassign unknown d$72 = unknown $32 - [5] unknown $34 = LoadLocal unknown x$65 - [6] unknown $35 = LoadLocal unknown y$66 - [7] unknown $36 = Binary unknown $34 + unknown $35 - [8] unknown $37 = LoadLocal unknown a$67 - [9] unknown $38 = Binary unknown $36 + unknown $37 - [10] unknown $39 = LoadLocal unknown b$68 - [11] unknown $40 = Binary unknown $38 + unknown $39 - [12] unknown $41 = LoadLocal unknown z$69 - [13] unknown $42 = Binary unknown $40 + unknown $41 - [14] unknown $43 = 2 - [15] unknown $44 = Binary unknown $42 + unknown $43 - [16] unknown $45 = 3 - [17] unknown $46 = Binary unknown $44 + unknown $45 - [18] unknown $47 = + [0] unknown $93 = 2 + [1] unknown $94 = StoreLocal Let unknown c$95 = unknown $93 + [2] unknown $96 = DeclareLocal Let unknown d$97 + [3] unknown $98 = 3 + [4] unknown $99 = StoreLocal Reassign unknown d$100 = unknown $98 + [5] unknown $101 = LoadLocal unknown x$2 + [6] unknown $102 = LoadLocal unknown y$4 + [7] unknown $103 = Binary unknown $101 + unknown $102 + [8] unknown $104 = LoadLocal unknown a$6 + [9] unknown $105 = Binary unknown $103 + unknown $104 + [10] unknown $106 = LoadLocal unknown b$8 + [11] unknown $107 = Binary unknown $105 + unknown $106 + [12] unknown $108 = LoadLocal unknown z$26 + [13] unknown $109 = Binary unknown $107 + unknown $108 + [14] unknown $110 = LoadLocal unknown c$28 + [15] unknown $111 = Binary unknown $109 + unknown $110 + [16] unknown $112 = LoadLocal unknown d$30 + [17] unknown $113 = Binary unknown $111 + unknown $112 + [18] unknown $114 = [19] Return unknown $47 - [18] unknown $50 = StoreLocal Const unknown bar$73 = unknown $48 - [19] unknown $51 = LoadLocal unknown bar$73 - [20] unknown $52 = LoadGlobal foo - [21] unknown $53 = - [22] Return unknown $53 - [3] unknown $56 = StoreLocal Const unknown foo$74 = unknown $54 - [4] unknown $57 = + [23] unknown $115 = StoreLocal Const unknown bar$116 = unknown $87 + [24] unknown $117 = LoadLocal unknown bar$49 + [25] unknown $118 = LoadGlobal foo + [26] unknown $119 = + [27] Return unknown $53 + [3] unknown $120 = StoreLocal Const unknown foo$121 = unknown $62 + [4] unknown $122 = [5] Return unknown $57 diff --git a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@identifiers.js.snap b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@identifiers.js.snap index d1a21ccd3d..a5092e3585 100644 --- a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@identifiers.js.snap +++ b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@identifiers.js.snap @@ -28,14 +28,14 @@ function id( ) entry bb0 bb0 (block) - [0] unknown $1 = LoadGlobal Math - [1] unknown $2 = LoadGlobal id - [2] unknown $3 = true - [3] unknown $5 = StoreLocal Let unknown y$15 = unknown $3 - [4] unknown $6 = false - [5] unknown $7 = StoreLocal Reassign unknown y$16 = unknown $6 - [6] unknown $8 = false - [7] unknown $10 = DeclareLocal Let unknown z$17 - [8] unknown $11 = LoadLocal unknown z$17 - [9] unknown $12 = LoadLocal unknown x$14 + [0] unknown $15 = LoadGlobal Math + [1] unknown $16 = LoadGlobal id + [2] unknown $17 = true + [3] unknown $18 = StoreLocal Let unknown y$19 = unknown $17 + [4] unknown $20 = false + [5] unknown $21 = StoreLocal Reassign unknown y$22 = unknown $20 + [6] unknown $23 = LoadLocal unknown y$4 + [7] unknown $24 = DeclareLocal Let unknown z$25 + [8] unknown $26 = LoadLocal unknown z$9 + [9] unknown $27 = LoadLocal unknown x$0 [10] Return unknown $12 diff --git a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@if-statement.js.snap b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@if-statement.js.snap index 5dc5a510c2..068ebc7c41 100644 --- a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@if-statement.js.snap +++ b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@if-statement.js.snap @@ -23,18 +23,18 @@ function foo( ) entry bb0 bb0 (block) - [0] unknown $6 = LoadLocal unknown a$9 + [0] unknown $13 = LoadLocal unknown a$0 [1] If unknown $6 consequent=bb2 alternate=bb4 fallthrough=bb1 bb2 (block) predecessors: bb0 - [2] unknown $4 = LoadLocal unknown b$10 + [2] unknown $14 = LoadLocal unknown b$1 [3] Return unknown $4 bb4 (block) predecessors: bb0 - [4] unknown $5 = LoadLocal unknown c$11 + [4] unknown $15 = LoadLocal unknown c$2 [5] Goto bb1 bb1 (block) predecessors: bb4 - [6] unknown $7 = LoadLocal unknown d$12 - [7] unknown $8 = + [6] unknown $16 = LoadLocal unknown d$3 + [7] unknown $17 = [8] Return unknown $8 diff --git a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@simple-function.js.snap b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@simple-function.js.snap index dedf9480c7..01b2b50309 100644 --- a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@simple-function.js.snap +++ b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@simple-function.js.snap @@ -21,26 +21,26 @@ function Component( ) entry bb0 bb0 (block) - [0] unknown $1 = LoadGlobal Math - [1] unknown $2 = 0 - [2] unknown $4 = StoreLocal Let unknown b$24 = unknown $2 - [3] unknown $17 = Function @deps[] @context[unknown a$23, unknown b$24]: + [0] unknown $24 = LoadGlobal Math + [1] unknown $25 = 0 + [2] unknown $26 = StoreLocal Let unknown b$27 = unknown $25 + [3] unknown $28 = Function @deps[] @context[unknown a$23, unknown b$27]: function foo_( - unknown c$25, + unknown c$29, ) entry bb1 bb1 (block) - [0] unknown $6 = 1 - [1] unknown $8 = StoreLocal Let unknown d$26 = unknown $6 - [2] unknown $9 = LoadLocal unknown a$23 - [3] unknown $10 = 0 - [4] unknown $11 = Binary unknown $9 + unknown $10 - [5] unknown $12 = LoadLocal unknown c$25 - [6] unknown $13 = Binary unknown $11 + unknown $12 - [7] unknown $14 = 1 - [8] unknown $15 = Binary unknown $13 + unknown $14 + [0] unknown $30 = 1 + [1] unknown $31 = StoreLocal Let unknown d$32 = unknown $30 + [2] unknown $33 = LoadLocal unknown a$0 + [3] unknown $34 = LoadLocal unknown b$3 + [4] unknown $35 = Binary unknown $33 + unknown $34 + [5] unknown $36 = LoadLocal unknown c$5 + [6] unknown $37 = Binary unknown $35 + unknown $36 + [7] unknown $38 = LoadLocal unknown d$7 + [8] unknown $39 = Binary unknown $37 + unknown $38 [9] Return unknown $15 - [4] unknown $19 = StoreLocal Const unknown foo$27 = unknown $17 - [5] unknown $20 = LoadLocal unknown foo$27 - [6] unknown $21 = Call unknown $20() + [4] unknown $40 = StoreLocal Const unknown foo$41 = unknown $28 + [5] unknown $42 = LoadLocal unknown foo$18 + [6] unknown $43 = Call unknown $42() [7] Return unknown $21 diff --git a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@simple.js.snap b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@simple.js.snap index ea707453c4..2fdef00104 100644 --- a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@simple.js.snap +++ b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@simple.js.snap @@ -15,13 +15,13 @@ function test( ) entry bb0 bb0 (block) - [0] unknown $0 = true - [1] unknown $1 = false - [2] unknown $2 = null - [3] unknown $3 = 1 - [4] unknown $4 = 3.14 - [5] unknown $5 = "hello world!" - [6] unknown $6 = Array [unknown $5] - [7] unknown $7 = Array [unknown $0, unknown $1, unknown $2, unknown $3, unknown $4, ...unknown $6] - [8] unknown $8 = 2 + [0] unknown $10 = true + [1] unknown $11 = false + [2] unknown $12 = null + [3] unknown $13 = 1 + [4] unknown $14 = 3.14 + [5] unknown $15 = "hello world!" + [6] unknown $16 = Array [unknown $15] + [7] unknown $17 = Array [unknown $10, unknown $11, unknown $12, unknown $13, unknown $14, ...unknown $16] + [8] unknown $18 = 2 [9] Return unknown $8 diff --git a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@ssa-reassign-if.js.snap b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@ssa-reassign-if.js.snap index 7b13bd8a6e..aec0e87418 100644 --- a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@ssa-reassign-if.js.snap +++ b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@ssa-reassign-if.js.snap @@ -29,45 +29,42 @@ function Component( ) entry bb0 bb0 (block) - [0] unknown $3 = DeclareLocal Let unknown x$28 - [1] unknown $4 = 0 - [2] unknown $6 = StoreLocal Let unknown y$29 = unknown $4 - [3] unknown $7 = 10 - [4] unknown $9 = StoreLocal Let unknown z$30 = unknown $7 - [5] unknown $19 = LoadLocal unknown a$26 + [0] unknown $28 = DeclareLocal Let unknown x$29 + [1] unknown $30 = 0 + [2] unknown $31 = StoreLocal Let unknown y$32 = unknown $30 + [3] unknown $33 = 10 + [4] unknown $34 = StoreLocal Let unknown z$35 = unknown $33 + [5] unknown $36 = LoadLocal unknown a$0 [6] If unknown $19 consequent=bb2 alternate=bb6 fallthrough=bb1 bb2 (block) predecessors: bb0 - [7] unknown $10 = 1 - [8] unknown $11 = StoreLocal Reassign unknown x$31 = unknown $10 - [9] unknown $16 = LoadLocal unknown b$27 + [7] unknown $37 = 1 + [8] unknown $38 = StoreLocal Reassign unknown x$39 = unknown $37 + [9] unknown $40 = LoadLocal unknown b$1 [10] If unknown $16 consequent=bb4 alternate=bb5 fallthrough=bb3 bb4 (block) predecessors: bb2 - [11] unknown $12 = 20 - [12] unknown $13 = StoreLocal Reassign unknown z$32 = unknown $12 + [11] unknown $41 = 20 + [12] unknown $42 = StoreLocal Reassign unknown z$43 = unknown $41 [13] Goto bb3 bb5 (block) predecessors: bb2 - [14] unknown $14 = 30 - [15] unknown $15 = StoreLocal Reassign unknown z$33 = unknown $14 + [14] unknown $44 = 30 + [15] unknown $45 = StoreLocal Reassign unknown z$46 = unknown $44 [16] Goto bb3 bb3 (block) predecessors: bb4, bb5 - z$40: phi(bb4: z$32, bb5: z$33) [17] Goto bb1 bb6 (block) predecessors: bb0 - [18] unknown $17 = 2 - [19] unknown $18 = StoreLocal Reassign unknown x$34 = unknown $17 + [18] unknown $47 = 2 + [19] unknown $48 = StoreLocal Reassign unknown x$49 = unknown $47 [20] Goto bb1 bb1 (block) predecessors: bb3, bb6 - x$35: phi(bb3: x$31, bb6: x$34) - z$39: phi(bb3: z$40, bb6: z$30) - [21] unknown $20 = LoadLocal unknown x$35 - [22] unknown $21 = 0 - [23] unknown $22 = Binary unknown $20 + unknown $21 - [24] unknown $23 = LoadLocal unknown z$39 - [25] unknown $24 = Binary unknown $22 + unknown $23 + [21] unknown $50 = LoadLocal unknown x$2 + [22] unknown $51 = LoadLocal unknown y$5 + [23] unknown $52 = Binary unknown $50 + unknown $51 + [24] unknown $53 = LoadLocal unknown z$8 + [25] unknown $54 = Binary unknown $52 + unknown $53 [26] Return unknown $24 diff --git a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@use-memo.js.snap b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@use-memo.js.snap index fdc70a2d16..ed7e6ea5d8 100644 --- a/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@use-memo.js.snap +++ b/compiler/forget/crates/forget_fixtures/tests/snapshots/fixtures_test__fixtures@use-memo.js.snap @@ -18,17 +18,17 @@ function Component( ) entry bb0 bb0 (block) - [0] unknown $1 = LoadGlobal useMemo - [1] unknown $14 = DeclareLocal Let unknown t$12 + [0] unknown $11 = LoadGlobal useMemo + [1] unknown $20 = DeclareLocal Let unknown t$18 [2] Label block=bb1 fallthrough=bb6 bb1 (block) predecessors: bb0 - [3] unknown $2 = LoadGlobal y - [4] unknown $13 = StoreLocal Reassign unknown t$12 = unknown $2 + [3] unknown $13 = LoadGlobal y + [4] unknown $19 = StoreLocal Reassign unknown t$18 = unknown $2 [5] Goto bb6 bb6 (block) predecessors: bb1 - [6] unknown $5 = LoadLocal unknown t$12 - [7] unknown $7 = StoreLocal Const unknown x$11 = unknown $5 - [8] unknown $8 = LoadLocal unknown x$11 + [6] unknown $14 = LoadLocal unknown t$18 + [7] unknown $15 = StoreLocal Const unknown x$16 = unknown $14 + [8] unknown $17 = LoadLocal unknown x$6 [9] Return unknown $8 diff --git a/compiler/forget/crates/forget_hir/src/instruction.rs b/compiler/forget/crates/forget_hir/src/instruction.rs index b170d31f71..d87379d152 100644 --- a/compiler/forget/crates/forget_hir/src/instruction.rs +++ b/compiler/forget/crates/forget_hir/src/instruction.rs @@ -16,17 +16,20 @@ pub struct Instruction { impl Instruction { pub fn each_identifier_store(&mut self, mut f: F) -> () where - F: FnMut(&mut LValue) -> (), + F: FnMut(&mut IdentifierOperand) -> (), { match &mut self.value { InstructionValue::DeclareContext(instr) => { - f(&mut instr.lvalue); + f(&mut instr.lvalue.identifier); } InstructionValue::DeclareLocal(instr) => { - f(&mut instr.lvalue); + f(&mut instr.lvalue.identifier); } InstructionValue::StoreLocal(instr) => { - f(&mut instr.lvalue); + f(&mut instr.lvalue.identifier); + } + InstructionValue::Destructure(instr) => { + instr.pattern.each_operand(f); } InstructionValue::Array(_) | InstructionValue::Binary(_) @@ -43,18 +46,19 @@ impl Instruction { pub fn try_each_identifier_store(&mut self, mut f: F) -> Result<(), E> where - F: FnMut(&mut LValue) -> Result<(), E>, + F: FnMut(&mut IdentifierOperand) -> Result<(), E>, { match &mut self.value { InstructionValue::DeclareContext(instr) => { - f(&mut instr.lvalue)?; + f(&mut instr.lvalue.identifier)?; } InstructionValue::DeclareLocal(instr) => { - f(&mut instr.lvalue)?; + f(&mut instr.lvalue.identifier)?; } InstructionValue::StoreLocal(instr) => { - f(&mut instr.lvalue)?; + f(&mut instr.lvalue.identifier)?; } + InstructionValue::Destructure(instr) => instr.pattern.try_each_operand(f)?, InstructionValue::Array(_) | InstructionValue::Binary(_) | InstructionValue::Call(_) @@ -73,21 +77,23 @@ impl Instruction { where F: FnMut(&mut IdentifierOperand) -> (), { - match &mut self.value { - InstructionValue::LoadLocal(instr) => f(&mut instr.place), - InstructionValue::Array(_) - | InstructionValue::Binary(_) - | InstructionValue::Call(_) - | InstructionValue::DeclareContext(_) - | InstructionValue::DeclareLocal(_) - | InstructionValue::LoadContext(_) - | InstructionValue::LoadGlobal(_) - | InstructionValue::Primitive(_) - | InstructionValue::StoreLocal(_) - | InstructionValue::Function(_) - | InstructionValue::JSXElement(_) - | InstructionValue::Tombstone => {} - } + // match &mut self.value { + // InstructionValue::LoadLocal(instr) => f(&mut instr.place), + // InstructionValue::Array(_) + // | InstructionValue::Binary(_) + // | InstructionValue::Call(_) + // | InstructionValue::DeclareContext(_) + // | InstructionValue::DeclareLocal(_) + // | InstructionValue::Destructure(_) + // | InstructionValue::LoadContext(_) + // | InstructionValue::LoadGlobal(_) + // | InstructionValue::Primitive(_) + // | InstructionValue::StoreLocal(_) + // | InstructionValue::Function(_) + // | InstructionValue::JSXElement(_) + // | InstructionValue::Tombstone => {} + // } + self.each_operand(f); } pub fn each_operand(&mut self, mut f: F) -> () @@ -139,6 +145,9 @@ impl Instruction { } } } + InstructionValue::Destructure(value) => { + f(&mut value.value); + } InstructionValue::DeclareContext(_) | InstructionValue::LoadContext(_) | InstructionValue::LoadGlobal(_) @@ -162,7 +171,7 @@ pub enum InstructionValue { // Debugger(Debugger), DeclareContext(DeclareContext), DeclareLocal(DeclareLocal), - // Destructure(Destructure), + Destructure(Destructure), Function(FunctionExpression), JSXElement(JSXElement), // JsxFragment(JsxFragment), @@ -272,6 +281,94 @@ pub enum JSXAttribute { }, } +#[derive(Debug)] +pub struct Destructure { + pub kind: InstructionKind, + pub pattern: DestructurePattern, + pub value: IdentifierOperand, +} + +#[derive(Debug)] +pub enum DestructurePattern { + Array(Vec), + Object(Vec), +} + +impl DestructurePattern { + pub fn try_each_operand(&mut self, mut f: F) -> Result<(), E> + where + F: FnMut(&mut IdentifierOperand) -> Result<(), E>, + { + match self { + Self::Array(elements) => { + for item in elements { + match item { + ArrayDestructureItem::Hole => { /* no-op */ } + ArrayDestructureItem::Value(item) => f(item)?, + ArrayDestructureItem::Spread(item) => f(item)?, + } + } + } + Self::Object(properties) => { + for property in properties { + match property { + ObjectDestructureItem::Property(property) => { + f(&mut property.value)?; + } + ObjectDestructureItem::Spread(property) => f(property)?, + } + } + } + } + Ok(()) + } + pub fn each_operand(&mut self, mut f: F) -> () + where + F: FnMut(&mut IdentifierOperand) -> (), + { + match self { + Self::Array(elements) => { + for item in elements { + match item { + ArrayDestructureItem::Hole => { /* no-op */ } + ArrayDestructureItem::Value(item) => f(item), + ArrayDestructureItem::Spread(item) => f(item), + } + } + } + Self::Object(properties) => { + for property in properties { + match property { + ObjectDestructureItem::Property(property) => { + f(&mut property.value); + } + ObjectDestructureItem::Spread(property) => f(property), + } + } + } + } + } +} + +#[derive(Debug)] +pub enum ArrayDestructureItem { + Hole, + Value(IdentifierOperand), + Spread(IdentifierOperand), +} + +#[derive(Debug)] +pub enum ObjectDestructureItem { + Property(ObjectDestructureProperty), + Spread(IdentifierOperand), +} + +#[derive(Debug)] +pub struct ObjectDestructureProperty { + pub name: String, + pub value: IdentifierOperand, +} + #[derive(Clone, Debug)] pub struct IdentifierOperand { pub identifier: Identifier, diff --git a/compiler/forget/crates/forget_hir/src/print.rs b/compiler/forget/crates/forget_hir/src/print.rs index 178051ede3..e847b3f7fb 100644 --- a/compiler/forget/crates/forget_hir/src/print.rs +++ b/compiler/forget/crates/forget_hir/src/print.rs @@ -4,8 +4,9 @@ use forget_estree::JsValue; use forget_utils::ensure_sufficient_stack; use crate::{ - BasicBlock, Function, Identifier, IdentifierOperand, Instruction, InstructionValue, LValue, - Phi, PlaceOrSpread, Terminal, TerminalValue, HIR, + ArrayDestructureItem, BasicBlock, DestructurePattern, Function, Identifier, IdentifierOperand, + Instruction, InstructionValue, LValue, ObjectDestructureItem, Phi, PlaceOrSpread, Terminal, + TerminalValue, HIR, }; /// Trait for HIR types to describe how they print themselves. @@ -205,6 +206,12 @@ impl Print for InstructionValue { .collect(); write!(out, "{}", lines.join("\n"))?; } + InstructionValue::Destructure(value) => { + write!(out, "Destructure ")?; + value.pattern.print(hir, out)?; + write!(out, " = ")?; + value.value.print(hir, out)?; + } InstructionValue::Tombstone => { write!(out, "Tombstone!")?; } @@ -262,6 +269,54 @@ impl Print for Identifier { } } +impl Print for DestructurePattern { + fn print(&self, hir: &HIR, out: &mut impl Write) -> Result { + match self { + DestructurePattern::Array(items) => { + write!(out, "[ ")?; + for (index, item) in items.iter().enumerate() { + if index != 0 { + write!(out, ", ")?; + } + match item { + ArrayDestructureItem::Hole => { + write!(out, "")?; + } + ArrayDestructureItem::Value(item) => { + item.print(hir, out)?; + } + ArrayDestructureItem::Spread(item) => { + write!(out, "...")?; + item.print(hir, out)?; + } + } + } + write!(out, " ]")?; + } + DestructurePattern::Object(properties) => { + write!(out, "{{ ")?; + for (index, property) in properties.iter().enumerate() { + if index != 0 { + write!(out, ", ")?; + } + match property { + ObjectDestructureItem::Property(property) => { + write!(out, "{}: ", &property.name)?; + property.value.print(hir, out)?; + } + ObjectDestructureItem::Spread(property) => { + write!(out, "...")?; + property.print(hir, out)?; + } + } + } + write!(out, " }}")?; + } + } + Ok(()) + } +} + impl Print for Terminal { fn print(&self, hir: &HIR, out: &mut impl Write) -> Result { write!(out, " {} ", self.id)?; diff --git a/compiler/forget/crates/forget_semantic_analysis/src/analyzer.rs b/compiler/forget/crates/forget_semantic_analysis/src/analyzer.rs index e51515b648..c167c85d41 100644 --- a/compiler/forget/crates/forget_semantic_analysis/src/analyzer.rs +++ b/compiler/forget/crates/forget_semantic_analysis/src/analyzer.rs @@ -6,7 +6,8 @@ use forget_estree::{ }; use crate::{ - AstNode, DeclarationKind, LabelId, LabelKind, ReferenceKind, ScopeId, ScopeKind, ScopeManager, + AstNode, DeclarationKind, Label, LabelId, LabelKind, ReferenceKind, ScopeId, ScopeKind, + ScopeManager, }; pub fn analyze(ast: &Program) -> ScopeManager { @@ -43,18 +44,18 @@ impl Analyzer { assert_eq!(last, id); } - fn lookup_break(&self, name: Option<&str>) -> Option { + fn lookup_break(&self, name: Option<&str>) -> Option<&Label> { for id in self.labels.iter().rev() { let label = self.manager.label(*id); match (name, &label.name) { // If this is a labeled break, only return if an exact match // is in scope (Some(name), Some(label_name)) if name == label_name => { - return Some(label.id); + return Some(label); } // If this is an unlabeld break, return the innermost label id (None, _) => { - return Some(label.id); + return Some(label); } _ => { /* no-op */ } } @@ -62,22 +63,18 @@ impl Analyzer { None } - fn lookup_continue(&self, name: Option<&str>) -> Option { + fn lookup_continue(&self, name: Option<&str>) -> Option<&Label> { for id in self.labels.iter().rev() { let label = self.manager.label(*id); - // Skip labels that are not for loops, can only continue to a loop - if label.kind != LabelKind::Loop { - continue; - } match (name, &label.name) { // If this is a labeled break, only return if an exact match // is in scope (Some(name), Some(label_name)) if &name == label_name => { - return Some(label.id); + return Some(label); } // If this is an unlabeld break, return the innermost label id (None, _) => { - return Some(label.id); + return Some(label); } _ => { /* no-op */ } } @@ -425,16 +422,14 @@ impl Visitor for Analyzer { } fn visit_break_statement(&mut self, ast: &forget_estree::BreakStatement) { - if let Some(label_id) = - self.lookup_break(ast.label.as_ref().map(|ident| ident.name.as_str())) + if let Some(label) = self.lookup_break(ast.label.as_ref().map(|ident| ident.name.as_str())) { - self.manager - .node_labels - .insert(AstNode::from(ast), label_id); + let id = label.id; + self.manager.node_labels.insert(AstNode::from(ast), id); if let Some(label_node) = &ast.label { self.manager .node_labels - .insert(AstNode::from(label_node), label_id); + .insert(AstNode::from(label_node), id); } } else { self.manager.diagnostics.push(Diagnostic::invalid_syntax( @@ -462,21 +457,31 @@ impl Visitor for Analyzer { } fn visit_continue_statement(&mut self, ast: &forget_estree::ContinueStatement) { - if let Some(label_id) = + let range = ast + .label + .as_ref() + .map(|label| label.range) + .unwrap_or(ast.range); + if let Some(label) = self.lookup_continue(ast.label.as_ref().map(|ident| ident.name.as_str())) { - self.manager - .node_labels - .insert(AstNode::from(ast), label_id); + let id = label.id; + if label.kind != LabelKind::Loop { + self.manager.diagnostics.push(Diagnostic::invalid_syntax( + "Invalid continue statement, the named label must be for a loop", + range, + )); + } + self.manager.node_labels.insert(AstNode::from(ast), id); if let Some(label_node) = &ast.label { self.manager .node_labels - .insert(AstNode::from(label_node), label_id); + .insert(AstNode::from(label_node), id); } } else { self.manager.diagnostics.push(Diagnostic::invalid_syntax( "Non-syntactic continue, could not resolve continue target", - ast.range, + range, )); } } diff --git a/compiler/forget/crates/forget_ssa/src/eliminate_redundant_phis.rs b/compiler/forget/crates/forget_ssa/src/eliminate_redundant_phis.rs index 876e6e4e39..8d90721291 100644 --- a/compiler/forget/crates/forget_ssa/src/eliminate_redundant_phis.rs +++ b/compiler/forget/crates/forget_ssa/src/eliminate_redundant_phis.rs @@ -70,9 +70,7 @@ pub fn eliminate_redundant_phis(env: &Environment, fun: &mut Function) { for instr_ix in block.instructions.iter() { let instr = &mut hir.instructions[usize::from(*instr_ix)]; - instr.each_identifier_store(|store| { - rewrite(&rewrites, &mut store.identifier.identifier) - }); + instr.each_identifier_store(|store| rewrite(&rewrites, &mut store.identifier)); instr.each_identifier_load(|load| rewrite(&rewrites, &mut load.identifier)); if let InstructionValue::Function(fun) = &mut instr.value { diff --git a/compiler/forget/crates/forget_ssa/src/enter.rs b/compiler/forget/crates/forget_ssa/src/enter.rs index eeae6d6278..cda08d91c7 100644 --- a/compiler/forget/crates/forget_ssa/src/enter.rs +++ b/compiler/forget/crates/forget_ssa/src/enter.rs @@ -47,6 +47,7 @@ fn visit_instructions<'e, 'f>( builder.each_block(|block, builder| { for instr_ix in &block.instructions { let instr = &mut instructions[usize::from(*instr_ix)]; + builder.visit_store(&mut instr.lvalue)?; instr.try_each_identifier_store(|store| builder.visit_store(store))?; instr.each_identifier_load(|load| builder.visit_load(load)); @@ -139,8 +140,8 @@ impl<'e, 'f> Builder<'e, 'f> { self.env.next_identifier_id() } - fn visit_store(&mut self, lvalue: &mut LValue) -> Result<(), Diagnostic> { - let old_identifier = &lvalue.identifier.identifier; + fn visit_store(&mut self, lvalue: &mut IdentifierOperand) -> Result<(), Diagnostic> { + let old_identifier = &lvalue.identifier; // TODO: use Result (?) invariant(!self.unknown.contains(&old_identifier.id), || { Diagnostic::invariant( @@ -151,14 +152,14 @@ impl<'e, 'f> Builder<'e, 'f> { if self.context.contains(&old_identifier.id) { let new_identifier = self.get_id_at(self.current, old_identifier); - lvalue.identifier.identifier = new_identifier; + lvalue.identifier = new_identifier; return Ok(()); } let new_identifier = self.make_identifier(old_identifier); let state = self.states.get_mut(&self.current).unwrap(); state.defs.insert(old_identifier.id, new_identifier.clone()); - lvalue.identifier.identifier = new_identifier; + lvalue.identifier = new_identifier; Ok(()) }