@@ -68,7 +68,7 @@ impl<'a> Traverse<'a> for PeepholeMinimizeConditions {
68
68
69
69
if let Some ( folded_stmt) = match stmt {
70
70
// If the condition is a literal, we'll let other optimizations try to remove useless code.
71
- Statement :: IfStatement ( s ) if !s . test . is_literal ( ) => Self :: try_minimize_if ( stmt, ctx) ,
71
+ Statement :: IfStatement ( _ ) => Self :: try_minimize_if ( stmt, ctx) ,
72
72
_ => None ,
73
73
} {
74
74
* stmt = folded_stmt;
@@ -139,75 +139,108 @@ impl<'a> PeepholeMinimizeConditions {
139
139
ctx : & mut TraverseCtx < ' a > ,
140
140
) -> Option < Statement < ' a > > {
141
141
let Statement :: IfStatement ( if_stmt) = stmt else { unreachable ! ( ) } ;
142
- let then_branch = & if_stmt. consequent ;
143
- let else_branch = & if_stmt. alternate ;
144
- match else_branch {
145
- None => {
146
- if Self :: is_foldable_express_block ( & if_stmt. consequent ) {
147
- let right = Self :: get_block_expression ( & mut if_stmt. consequent , ctx) ;
148
- let test = ctx. ast . move_expression ( & mut if_stmt. test ) ;
149
- // `if(!x) foo()` -> `x || foo()`
150
- if let Expression :: UnaryExpression ( unary_expr) = test {
151
- if unary_expr. operator . is_not ( ) {
152
- let left = unary_expr. unbox ( ) . argument ;
142
+
143
+ // `if (x) foo()` -> `x && foo()`
144
+ if !if_stmt. test . is_literal ( ) {
145
+ let then_branch = & if_stmt. consequent ;
146
+ let else_branch = & if_stmt. alternate ;
147
+ match else_branch {
148
+ None => {
149
+ if Self :: is_foldable_express_block ( & if_stmt. consequent ) {
150
+ let right = Self :: get_block_expression ( & mut if_stmt. consequent , ctx) ;
151
+ let test = ctx. ast . move_expression ( & mut if_stmt. test ) ;
152
+ // `if(!x) foo()` -> `x || foo()`
153
+ if let Expression :: UnaryExpression ( unary_expr) = test {
154
+ if unary_expr. operator . is_not ( ) {
155
+ let left = unary_expr. unbox ( ) . argument ;
156
+ let logical_expr = ctx. ast . expression_logical (
157
+ if_stmt. span ,
158
+ left,
159
+ LogicalOperator :: Or ,
160
+ right,
161
+ ) ;
162
+ return Some (
163
+ ctx. ast . statement_expression ( if_stmt. span , logical_expr) ,
164
+ ) ;
165
+ }
166
+ } else {
167
+ // `if(x) foo()` -> `x && foo()`
153
168
let logical_expr = ctx. ast . expression_logical (
154
169
if_stmt. span ,
155
- left ,
156
- LogicalOperator :: Or ,
170
+ test ,
171
+ LogicalOperator :: And ,
157
172
right,
158
173
) ;
159
174
return Some ( ctx. ast . statement_expression ( if_stmt. span , logical_expr) ) ;
160
175
}
161
176
} else {
162
- // `if(x) foo()` -> `x && foo()`
163
- let logical_expr = ctx. ast . expression_logical (
177
+ // `if (x) if (y) z` -> `if (x && y) z`
178
+ if let Some ( Statement :: IfStatement ( then_if_stmt) ) =
179
+ then_branch. get_one_child ( )
180
+ {
181
+ if then_if_stmt. alternate . is_none ( ) {
182
+ let and_left = ctx. ast . move_expression ( & mut if_stmt. test ) ;
183
+ let Some ( then_if_stmt) = if_stmt. consequent . get_one_child_mut ( )
184
+ else {
185
+ unreachable ! ( )
186
+ } ;
187
+ let Statement :: IfStatement ( mut then_if_stmt) =
188
+ ctx. ast . move_statement ( then_if_stmt)
189
+ else {
190
+ unreachable ! ( )
191
+ } ;
192
+ let and_right = ctx. ast . move_expression ( & mut then_if_stmt. test ) ;
193
+ then_if_stmt. test = ctx. ast . expression_logical (
194
+ and_left. span ( ) ,
195
+ and_left,
196
+ LogicalOperator :: And ,
197
+ and_right,
198
+ ) ;
199
+ return Some ( Statement :: IfStatement ( then_if_stmt) ) ;
200
+ }
201
+ }
202
+ }
203
+ }
204
+ Some ( else_branch) => {
205
+ let then_branch_is_expression_block =
206
+ Self :: is_foldable_express_block ( then_branch) ;
207
+ let else_branch_is_expression_block =
208
+ Self :: is_foldable_express_block ( else_branch) ;
209
+ // `if(foo) bar else baz` -> `foo ? bar : baz`
210
+ if then_branch_is_expression_block && else_branch_is_expression_block {
211
+ let test = ctx. ast . move_expression ( & mut if_stmt. test ) ;
212
+ let consequent = Self :: get_block_expression ( & mut if_stmt. consequent , ctx) ;
213
+ let else_branch = if_stmt. alternate . as_mut ( ) . unwrap ( ) ;
214
+ let alternate = Self :: get_block_expression ( else_branch, ctx) ;
215
+ let expr = ctx. ast . expression_conditional (
164
216
if_stmt. span ,
165
217
test,
166
- LogicalOperator :: And ,
167
- right ,
218
+ consequent ,
219
+ alternate ,
168
220
) ;
169
- return Some ( ctx. ast . statement_expression ( if_stmt. span , logical_expr) ) ;
170
- }
171
- } else {
172
- // `if (x) if (y) z` -> `if (x && y) z`
173
- if let Some ( Statement :: IfStatement ( then_if_stmt) ) = then_branch. get_one_child ( )
174
- {
175
- if then_if_stmt. alternate . is_none ( ) {
176
- let and_left = ctx. ast . move_expression ( & mut if_stmt. test ) ;
177
- let Some ( then_if_stmt) = if_stmt. consequent . get_one_child_mut ( ) else {
178
- unreachable ! ( )
179
- } ;
180
- let Statement :: IfStatement ( mut then_if_stmt) =
181
- ctx. ast . move_statement ( then_if_stmt)
182
- else {
183
- unreachable ! ( )
184
- } ;
185
- let and_right = ctx. ast . move_expression ( & mut then_if_stmt. test ) ;
186
- then_if_stmt. test = ctx. ast . expression_logical (
187
- and_left. span ( ) ,
188
- and_left,
189
- LogicalOperator :: And ,
190
- and_right,
191
- ) ;
192
- return Some ( Statement :: IfStatement ( then_if_stmt) ) ;
193
- }
221
+ return Some ( ctx. ast . statement_expression ( if_stmt. span , expr) ) ;
194
222
}
195
223
}
196
224
}
197
- Some ( else_branch) => {
198
- let then_branch_is_expression_block = Self :: is_foldable_express_block ( then_branch) ;
199
- let else_branch_is_expression_block = Self :: is_foldable_express_block ( else_branch) ;
200
- // `if(foo) bar else baz` -> `foo ? bar : baz`
201
- if then_branch_is_expression_block && else_branch_is_expression_block {
202
- let test = ctx. ast . move_expression ( & mut if_stmt. test ) ;
203
- let consequent = Self :: get_block_expression ( & mut if_stmt. consequent , ctx) ;
204
- let else_branch = if_stmt. alternate . as_mut ( ) . unwrap ( ) ;
205
- let alternate = Self :: get_block_expression ( else_branch, ctx) ;
206
- let expr =
207
- ctx. ast . expression_conditional ( if_stmt. span , test, consequent, alternate) ;
208
- return Some ( ctx. ast . statement_expression ( if_stmt. span , expr) ) ;
209
- }
210
- }
225
+ }
226
+
227
+ // `if (x) {} else foo` -> `if (!x) foo`
228
+ if match & if_stmt. consequent {
229
+ Statement :: EmptyStatement ( _) => true ,
230
+ Statement :: BlockStatement ( block_stmt) => block_stmt. body . is_empty ( ) ,
231
+ _ => false ,
232
+ } && if_stmt. alternate . is_some ( )
233
+ {
234
+ return Some ( ctx. ast . statement_if (
235
+ if_stmt. span ,
236
+ ctx. ast . expression_unary (
237
+ if_stmt. test . span ( ) ,
238
+ UnaryOperator :: LogicalNot ,
239
+ ctx. ast . move_expression ( & mut if_stmt. test ) ,
240
+ ) ,
241
+ ctx. ast . move_statement ( if_stmt. alternate . as_mut ( ) . unwrap ( ) ) ,
242
+ None ,
243
+ ) ) ;
211
244
}
212
245
213
246
None
@@ -2047,4 +2080,14 @@ mod test {
2047
2080
test ( "typeof foo !== `number`" , "typeof foo != `number`" ) ;
2048
2081
test ( "`number` !== typeof foo" , "`number` != typeof foo" ) ;
2049
2082
}
2083
+
2084
+ #[ test]
2085
+ fn test_negate_empty_if_stmt_consequent ( ) {
2086
+ test ( "if (x) {} else { foo }" , "if (!x) { foo }" ) ;
2087
+ test ( "if (x) ;else { foo }" , "if (!x) { foo }" ) ;
2088
+ test ( "if (x) {;} else { foo }" , "if (!x) { foo }" ) ;
2089
+
2090
+ test_same ( "if (x) { var foo } else { bar }" ) ;
2091
+ test_same ( "if (x) foo; else { var bar }" ) ;
2092
+ }
2050
2093
}
0 commit comments