@@ -16,31 +16,11 @@ use super::PeepholeOptimizations;
1616/// See `KeepVar` at the end of this file for `var` hoisting logic.
1717/// <https://github.com/google/closure-compiler/blob/v20240609/src/com/google/javascript/jscomp/PeepholeRemoveDeadCode.java>
1818impl < ' a > PeepholeOptimizations {
19- pub fn remove_dead_code_exit_statement ( stmt : & mut Statement < ' a > , ctx : & mut Ctx < ' a , ' _ > ) {
20- if let Some ( new_stmt) = match stmt {
21- Statement :: BlockStatement ( s) => Self :: try_optimize_block ( s, ctx) ,
22- Statement :: IfStatement ( s) => Self :: try_fold_if ( s, ctx) ,
23- Statement :: ForStatement ( s) => Self :: try_fold_for ( s, ctx) ,
24- Statement :: TryStatement ( s) => Self :: try_fold_try ( s, ctx) ,
25- Statement :: LabeledStatement ( s) => Self :: try_fold_labeled ( s, ctx) ,
26- Statement :: FunctionDeclaration ( f) => Self :: remove_unused_function_declaration ( f, ctx) ,
27- Statement :: ClassDeclaration ( c) => Self :: remove_unused_class_declaration ( c, ctx) ,
28- _ => None ,
29- } {
30- * stmt = new_stmt;
31- ctx. state . changed = true ;
32- }
33-
34- Self :: try_fold_expression_stmt ( stmt, ctx) ;
35- }
36-
3719 /// Remove block from single line blocks
3820 /// `{ block } -> block`
39- fn try_optimize_block (
40- stmt : & mut BlockStatement < ' a > ,
41- ctx : & Ctx < ' a , ' _ > ,
42- ) -> Option < Statement < ' a > > {
43- match stmt. body . len ( ) {
21+ pub fn try_optimize_block ( stmt : & mut Statement < ' a > , ctx : & mut Ctx < ' a , ' _ > ) {
22+ let Statement :: BlockStatement ( s) = stmt else { return } ;
23+ match s. body . len ( ) {
4424 0 => {
4525 let parent = ctx. parent ( ) ;
4626 if parent. is_while_statement ( )
@@ -52,34 +32,33 @@ impl<'a> PeepholeOptimizations {
5232 || parent. is_program ( )
5333 {
5434 // Remove the block if it is empty and the parent is a block statement.
55- return Some ( ctx. ast . statement_empty ( stmt. span ) ) ;
35+ * stmt = ctx. ast . statement_empty ( s. span ) ;
36+ ctx. state . changed = true ;
5637 }
57- None
5838 }
5939 1 => {
60- let s = & stmt . body [ 0 ] ;
61- if matches ! ( s , Statement :: VariableDeclaration ( decl) if !decl. kind. is_var( ) )
62- || matches ! ( s , Statement :: ClassDeclaration ( _) )
63- || matches ! ( s , Statement :: FunctionDeclaration ( _) )
40+ let first = & s . body [ 0 ] ;
41+ if matches ! ( first , Statement :: VariableDeclaration ( decl) if !decl. kind. is_var( ) )
42+ || matches ! ( first , Statement :: ClassDeclaration ( _) )
43+ || matches ! ( first , Statement :: FunctionDeclaration ( _) )
6444 {
65- return None ;
45+ return ;
6646 }
67- Some ( stmt. body . remove ( 0 ) )
47+ * stmt = s. body . remove ( 0 ) ;
48+ ctx. state . changed = true ;
6849 }
69- _ => None ,
50+ _ => { }
7051 }
7152 }
7253
73- fn try_fold_if ( if_stmt : & mut IfStatement < ' a > , ctx : & mut Ctx < ' a , ' _ > ) -> Option < Statement < ' a > > {
54+ pub fn try_fold_if ( stmt : & mut Statement < ' a > , ctx : & mut Ctx < ' a , ' _ > ) {
55+ let Statement :: IfStatement ( if_stmt) = stmt else { return } ;
7456 // Descend and remove `else` blocks first.
7557 match & mut if_stmt. alternate {
76- Some ( Statement :: IfStatement ( alternate) ) => {
77- if let Some ( new_stmt) = Self :: try_fold_if ( alternate, ctx) {
78- if matches ! ( new_stmt, Statement :: EmptyStatement ( _) ) {
79- if_stmt. alternate = None ;
80- } else {
81- if_stmt. alternate = Some ( new_stmt) ;
82- }
58+ Some ( Statement :: IfStatement ( _) ) => {
59+ Self :: try_fold_if ( if_stmt. alternate . as_mut ( ) . unwrap ( ) , ctx) ;
60+ if matches ! ( if_stmt. alternate, Some ( Statement :: EmptyStatement ( _) ) ) {
61+ if_stmt. alternate = None ;
8362 }
8463 }
8564 Some ( Statement :: BlockStatement ( s) ) if s. body . is_empty ( ) => {
@@ -119,7 +98,7 @@ impl<'a> PeepholeOptimizations {
11998 } else {
12099 if_stmt. consequent = var_stmt;
121100 }
122- return None ;
101+ return ;
123102 }
124103 if test_has_side_effects {
125104 if !has_var_stmt {
@@ -129,25 +108,21 @@ impl<'a> PeepholeOptimizations {
129108 if_stmt. consequent = ctx. ast . statement_empty ( if_stmt. consequent . span ( ) ) ;
130109 }
131110 }
132- return None ;
111+ return ;
133112 }
134- return Some ( if boolean {
113+ * stmt = if boolean {
135114 if_stmt. consequent . take_in ( ctx. ast )
115+ } else if let Some ( alternate) = if_stmt. alternate . take ( ) {
116+ alternate
136117 } else {
137- if_stmt. alternate . as_mut ( ) . map_or_else (
138- || ctx. ast . statement_empty ( if_stmt. span ) ,
139- |alternate| alternate. take_in ( ctx. ast ) ,
140- )
141- } ) ;
118+ ctx. ast . statement_empty ( if_stmt. span )
119+ } ;
120+ ctx. state . changed = true ;
142121 }
143- None
144122 }
145123
146- fn try_fold_for (
147- for_stmt : & mut ForStatement < ' a > ,
148-
149- ctx : & mut Ctx < ' a , ' _ > ,
150- ) -> Option < Statement < ' a > > {
124+ pub fn try_fold_for ( stmt : & mut Statement < ' a > , ctx : & mut Ctx < ' a , ' _ > ) {
125+ let Statement :: ForStatement ( for_stmt) = stmt else { return } ;
151126 if let Some ( init) = & mut for_stmt. init {
152127 if let Some ( init) = init. as_expression_mut ( ) {
153128 if Self :: remove_unused_expression ( init, ctx) {
@@ -166,14 +141,18 @@ impl<'a> PeepholeOptimizations {
166141 let test_boolean =
167142 for_stmt. test . as_ref ( ) . and_then ( |test| test. evaluate_value_to_boolean ( ctx) ) ;
168143 if for_stmt. test . as_ref ( ) . is_some_and ( |test| test. may_have_side_effects ( ctx) ) {
169- return None ;
144+ return ;
170145 }
171146 match test_boolean {
172- Some ( false ) => match & mut for_stmt. init {
173- Some ( ForStatementInit :: VariableDeclaration ( var_init ) ) => {
147+ Some ( false ) => match & for_stmt. init {
148+ Some ( ForStatementInit :: VariableDeclaration ( _ ) ) => {
174149 let mut keep_var = KeepVar :: new ( ctx. ast ) ;
175150 keep_var. visit_statement ( & for_stmt. body ) ;
176151 let mut var_decl = keep_var. get_variable_declaration ( ) ;
152+ let Some ( ForStatementInit :: VariableDeclaration ( var_init) ) = & mut for_stmt. init
153+ else {
154+ return ;
155+ } ;
177156 if var_init. kind . is_var ( ) {
178157 if let Some ( var_decl) = & mut var_decl {
179158 var_decl
@@ -183,28 +162,29 @@ impl<'a> PeepholeOptimizations {
183162 var_decl = Some ( var_init. take_in_box ( ctx. ast ) ) ;
184163 }
185164 }
186- Some ( var_decl. map_or_else (
165+ * stmt = var_decl. map_or_else (
187166 || ctx. ast . statement_empty ( for_stmt. span ) ,
188167 Statement :: VariableDeclaration ,
189- ) )
168+ ) ;
169+ ctx. state . changed = true ;
190170 }
191171 None => {
192172 let mut keep_var = KeepVar :: new ( ctx. ast ) ;
193173 keep_var. visit_statement ( & for_stmt. body ) ;
194- Some ( keep_var. get_variable_declaration ( ) . map_or_else (
174+ * stmt = keep_var. get_variable_declaration ( ) . map_or_else (
195175 || ctx. ast . statement_empty ( for_stmt. span ) ,
196176 Statement :: VariableDeclaration ,
197- ) )
177+ ) ;
178+ ctx. state . changed = true ;
198179 }
199- _ => None ,
180+ _ => { }
200181 } ,
201182 Some ( true ) => {
202183 // Remove the test expression.
203184 for_stmt. test = None ;
204185 ctx. state . changed = true ;
205- None
206186 }
207- None => None ,
187+ None => { }
208188 }
209189 }
210190
@@ -213,7 +193,8 @@ impl<'a> PeepholeOptimizations {
213193 /// ```js
214194 /// a: break a;
215195 /// ```
216- fn try_fold_labeled ( s : & mut LabeledStatement < ' a > , ctx : & Ctx < ' a , ' _ > ) -> Option < Statement < ' a > > {
196+ pub fn try_fold_labeled ( stmt : & mut Statement < ' a > , ctx : & mut Ctx < ' a , ' _ > ) {
197+ let Statement :: LabeledStatement ( s) = stmt else { return } ;
217198 let id = s. label . name . as_str ( ) ;
218199 // Check the first statement in the block, or just the `break [id] ` statement.
219200 // Check if we need to remove the whole block.
@@ -222,17 +203,20 @@ impl<'a> PeepholeOptimizations {
222203 if break_stmt. label . as_ref ( ) . is_some_and ( |l| l. name . as_str ( ) == id) => { }
223204 Statement :: BlockStatement ( block) if block. body . first ( ) . is_some_and ( |first| matches ! ( first, Statement :: BreakStatement ( break_stmt) if break_stmt. label. as_ref( ) . is_some_and( |l| l. name. as_str( ) == id) ) ) => { }
224205 Statement :: EmptyStatement ( _) => {
225- return Some ( ctx. ast . statement_empty ( s. span ) )
206+ * stmt = ctx. ast . statement_empty ( s. span ) ;
207+ ctx. state . changed =true ;
208+ return
226209 }
227- _ => return None ,
210+ _ => return
228211 }
229212 let mut var = KeepVar :: new ( ctx. ast ) ;
230213 var. visit_statement ( & s. body ) ;
231214 let var_decl = var. get_variable_declaration_statement ( ) ;
232- var_decl. unwrap_or_else ( || ctx. ast . statement_empty ( s. span ) ) . into ( )
215+ * stmt = var_decl. unwrap_or_else ( || ctx. ast . statement_empty ( s. span ) ) ;
216+ ctx. state . changed = true ;
233217 }
234218
235- fn try_fold_expression_stmt ( stmt : & mut Statement < ' a > , ctx : & mut Ctx < ' a , ' _ > ) {
219+ pub fn try_fold_expression_stmt ( stmt : & mut Statement < ' a > , ctx : & mut Ctx < ' a , ' _ > ) {
236220 let Statement :: ExpressionStatement ( expr_stmt) = stmt else { return } ;
237221 // We need to check if it is in arrow function with `expression: true`.
238222 // This is the only scenario where we can't remove it even if `ExpressionStatement`.
@@ -248,11 +232,13 @@ impl<'a> PeepholeOptimizations {
248232 }
249233 }
250234
251- fn try_fold_try ( s : & mut TryStatement < ' a > , ctx : & Ctx < ' a , ' _ > ) -> Option < Statement < ' a > > {
252- if let Some ( handler) = & mut s. handler {
235+ pub fn try_fold_try ( stmt : & mut Statement < ' a > , ctx : & mut Ctx < ' a , ' _ > ) {
236+ let Statement :: TryStatement ( s) = stmt else { return } ;
237+ if let Some ( handler) = & s. handler {
253238 if s. block . body . is_empty ( ) {
254239 let mut var = KeepVar :: new ( ctx. ast ) ;
255240 var. visit_block_statement ( & handler. body ) ;
241+ let Some ( handler) = & mut s. handler else { return } ;
256242 handler. body . body . clear ( ) ;
257243 if let Some ( var_decl) = var. get_variable_declaration_statement ( ) {
258244 handler. body . body . push ( var_decl) ;
@@ -269,15 +255,14 @@ impl<'a> PeepholeOptimizations {
269255 if s. block . body . is_empty ( )
270256 && s. handler . as_ref ( ) . is_none_or ( |handler| handler. body . body . is_empty ( ) )
271257 {
272- if let Some ( finalizer) = & mut s. finalizer {
258+ * stmt = if let Some ( finalizer) = & mut s. finalizer {
273259 let mut block = ctx. ast . block_statement ( finalizer. span , ctx. ast . vec ( ) ) ;
274260 std:: mem:: swap ( & mut * * finalizer, & mut block) ;
275- Some ( Statement :: BlockStatement ( ctx. ast . alloc ( block) ) )
261+ Statement :: BlockStatement ( ctx. ast . alloc ( block) )
276262 } else {
277- Some ( ctx. ast . statement_empty ( s. span ) )
278- }
279- } else {
280- None
263+ ctx. ast . statement_empty ( s. span )
264+ } ;
265+ ctx. state . changed = true ;
281266 }
282267 }
283268
0 commit comments