|
| 1 | +use oxc_allocator::TakeIn; |
1 | 2 | use oxc_ast::ast::*; |
2 | 3 |
|
3 | 4 | use crate::{CompressOptionsUnused, ctx::Ctx}; |
@@ -88,37 +89,47 @@ impl<'a> PeepholeOptimizations { |
88 | 89 |
|
89 | 90 | pub fn remove_unused_assignment_expression( |
90 | 91 | &self, |
91 | | - _e: &mut Expression<'a>, |
92 | | - _ctx: &mut Ctx<'a, '_>, |
| 92 | + e: &mut Expression<'a>, |
| 93 | + ctx: &mut Ctx<'a, '_>, |
93 | 94 | ) -> bool { |
94 | | - // let Expression::AssignmentExpression(assign_expr) = e else { return false }; |
95 | | - // if matches!( |
96 | | - // ctx.state.options.unused, |
97 | | - // CompressOptionsUnused::Keep | CompressOptionsUnused::KeepAssign |
98 | | - // ) { |
99 | | - // return false; |
100 | | - // } |
101 | | - // let Some(SimpleAssignmentTarget::AssignmentTargetIdentifier(ident)) = |
102 | | - // assign_expr.left.as_simple_assignment_target() |
103 | | - // else { |
104 | | - // return false; |
105 | | - // }; |
106 | | - // if Self::keep_top_level_var_in_script_mode(ctx) { |
107 | | - // return false; |
108 | | - // } |
109 | | - // let Some(reference_id) = ident.reference_id.get() else { return false }; |
110 | | - // let Some(symbol_id) = ctx.scoping().get_reference(reference_id).symbol_id() else { |
111 | | - // return false; |
112 | | - // }; |
113 | | - // // Keep error for assigning to `const foo = 1; foo = 2`. |
114 | | - // if ctx.scoping().symbol_flags(symbol_id).is_const_variable() { |
115 | | - // return false; |
116 | | - // } |
117 | | - // if !ctx.scoping().get_resolved_references(symbol_id).all(|r| !r.flags().is_read()) { |
118 | | - // return false; |
119 | | - // } |
120 | | - // *e = assign_expr.right.take_in(ctx.ast); |
121 | | - // state.changed = true; |
| 95 | + let Expression::AssignmentExpression(assign_expr) = e else { return false }; |
| 96 | + if matches!( |
| 97 | + ctx.state.options.unused, |
| 98 | + CompressOptionsUnused::Keep | CompressOptionsUnused::KeepAssign |
| 99 | + ) { |
| 100 | + return false; |
| 101 | + } |
| 102 | + let Some(SimpleAssignmentTarget::AssignmentTargetIdentifier(ident)) = |
| 103 | + assign_expr.left.as_simple_assignment_target() |
| 104 | + else { |
| 105 | + return false; |
| 106 | + }; |
| 107 | + if Self::keep_top_level_var_in_script_mode(ctx) { |
| 108 | + return false; |
| 109 | + } |
| 110 | + let Some(reference_id) = ident.reference_id.get() else { return false }; |
| 111 | + let Some(symbol_id) = ctx.scoping().get_reference(reference_id).symbol_id() else { |
| 112 | + return false; |
| 113 | + }; |
| 114 | + // Keep error for assigning to `const foo = 1; foo = 2`. |
| 115 | + if ctx.scoping().symbol_flags(symbol_id).is_const_variable() { |
| 116 | + return false; |
| 117 | + } |
| 118 | + let Some(symbol_value) = ctx.state.symbol_values.get_symbol_value(symbol_id) else { |
| 119 | + return false; |
| 120 | + }; |
| 121 | + // Cannot remove assignment to live bindings: `export let foo; foo = 1;`. |
| 122 | + if symbol_value.exported { |
| 123 | + return false; |
| 124 | + } |
| 125 | + if symbol_value.read_references_count > 0 { |
| 126 | + return false; |
| 127 | + } |
| 128 | + if symbol_value.for_statement_init { |
| 129 | + return false; |
| 130 | + } |
| 131 | + *e = assign_expr.right.take_in(ctx.ast); |
| 132 | + ctx.state.changed = true; |
122 | 133 | false |
123 | 134 | } |
124 | 135 |
|
@@ -180,33 +191,48 @@ mod test { |
180 | 191 | } |
181 | 192 |
|
182 | 193 | #[test] |
183 | | - #[ignore] |
184 | 194 | fn remove_unused_assignment_expression() { |
185 | 195 | let options = CompressOptions::smallest(); |
186 | | - test_options("var x = 1; x = 2;", "", &options); |
187 | | - test_options("var x = 1; x = 2;", "", &options); |
188 | | - test_options("var x = 1; x = foo();", "foo()", &options); |
189 | | - test_same_options("export let foo; foo = 0;", &options); |
| 196 | + // Vars are not handled yet due to TDZ. |
| 197 | + test_same_options("var x = 1; x = 2;", &options); |
| 198 | + test_same_options("var x = 1; x = foo();", &options); |
| 199 | + test_same_options("export var foo; foo = 0;", &options); |
190 | 200 | test_same_options("var x = 1; x = 2, foo(x)", &options); |
191 | 201 | test_same_options("function foo() { return t = x(); } foo();", &options); |
| 202 | + test_same_options("function foo() { var t; return t = x(); } foo();", &options); |
| 203 | + test_same_options("function foo(t) { return t = x(); } foo();", &options); |
| 204 | + |
| 205 | + test_options("let x = 1; x = 2;", "", &options); |
| 206 | + test_options("let x = 1; x = foo();", "foo()", &options); |
| 207 | + test_same_options("export let foo; foo = 0;", &options); |
| 208 | + test_same_options("let x = 1; x = 2, foo(x)", &options); |
| 209 | + test_same_options("function foo() { return t = x(); } foo();", &options); |
192 | 210 | test_options( |
193 | | - "function foo() { var t; return t = x(); } foo();", |
194 | | - "function foo() { return x(); } foo();", |
| 211 | + "function foo() { let t; return t = x(); } foo();", |
| 212 | + "function foo() { return x() } foo()", |
195 | 213 | &options, |
196 | 214 | ); |
197 | | - test_options( |
198 | | - "function foo(t) { return t = x(); } foo();", |
199 | | - "function foo(t) { return x(); } foo();", |
| 215 | + test_same_options("function foo(t) { return t = x(); } foo();", &options); |
| 216 | + |
| 217 | + test_same_options("for(let i;;) foo(i)", &options); |
| 218 | + test_same_options("for(let i in []) foo(i)", &options); |
| 219 | + |
| 220 | + test_options("var a; ({ a: a } = {})", "var a; ({ a } = {})", &options); |
| 221 | + test_options("var a; b = ({ a: a })", "var a; b = ({ a })", &options); |
| 222 | + |
| 223 | + test_options("let foo = {}; foo = 1", "", &options); |
| 224 | + |
| 225 | + test_same_options( |
| 226 | + "let bracketed = !1; for(;;) bracketed = !bracketed, log(bracketed)", |
200 | 227 | &options, |
201 | 228 | ); |
202 | 229 |
|
203 | 230 | let options = CompressOptions::smallest(); |
204 | 231 | let source_type = SourceType::cjs(); |
205 | 232 | test_same_options_source_type("var x = 1; x = 2;", source_type, &options); |
206 | 233 | test_same_options_source_type("var x = 1; x = 2, foo(x)", source_type, &options); |
207 | | - test_options_source_type( |
208 | | - "function foo() { var x = 1; x = 2; bar() } foo()", |
209 | | - "function foo() { bar() } foo()", |
| 234 | + test_same_options_source_type( |
| 235 | + "function foo() { var x = 1; x = 2, bar() } foo()", |
210 | 236 | source_type, |
211 | 237 | &options, |
212 | 238 | ); |
|
0 commit comments