@@ -20,46 +20,26 @@ impl<'a> PeepholeOptimizations {
2020 expr : & mut Expression < ' a > ,
2121 ctx : & mut Ctx < ' a , ' _ > ,
2222 ) {
23- let mut changed = false ;
24- loop {
25- let mut local_change = false ;
26- if let Some ( folded_expr) = match expr {
27- Expression :: UnaryExpression ( e) => self . try_minimize_not ( e, ctx) ,
28- Expression :: BinaryExpression ( e) => {
29- if Self :: try_compress_is_loose_boolean ( e, ctx) {
30- local_change = true ;
31- }
32- Self :: try_minimize_binary ( e, ctx)
33- }
34- Expression :: LogicalExpression ( e) => self . minimize_logical_expression ( e, ctx) ,
35- Expression :: ConditionalExpression ( logical_expr) => {
36- if self . try_fold_expr_in_boolean_context ( & mut logical_expr. test , ctx) {
37- local_change = true ;
38- }
39- self . try_minimize_conditional ( logical_expr, ctx)
40- }
41- Expression :: AssignmentExpression ( e) => {
42- if self . try_compress_normal_assignment_to_combined_logical_assignment ( e, ctx) {
43- local_change = true ;
44- }
45- if Self :: try_compress_normal_assignment_to_combined_assignment ( e, ctx) {
46- local_change = true ;
47- }
48- Self :: try_compress_assignment_to_update_expression ( e, ctx)
23+ match expr {
24+ Expression :: UnaryExpression ( _) => self . try_minimize_not ( expr, ctx) ,
25+ Expression :: BinaryExpression ( e) => {
26+ Self :: try_compress_is_loose_boolean ( e, ctx) ;
27+ Self :: try_minimize_binary ( expr, ctx) ;
28+ }
29+ Expression :: LogicalExpression ( _) => self . minimize_logical_expression ( expr, ctx) ,
30+ Expression :: ConditionalExpression ( logical_expr) => {
31+ self . try_fold_expr_in_boolean_context ( & mut logical_expr. test , ctx) ;
32+ if let Some ( changed) = self . try_minimize_conditional ( logical_expr, ctx) {
33+ * expr = changed;
34+ ctx. state . changed = true ;
4935 }
50- _ => None ,
51- } {
52- * expr = folded_expr;
53- local_change = true ;
5436 }
55- if local_change {
56- changed = true ;
57- } else {
58- break ;
37+ Expression :: AssignmentExpression ( e ) => {
38+ self . try_compress_normal_assignment_to_combined_logical_assignment ( e , ctx ) ;
39+ Self :: try_compress_normal_assignment_to_combined_assignment ( e , ctx ) ;
40+ Self :: try_compress_assignment_to_update_expression ( expr , ctx ) ;
5941 }
60- }
61- if changed {
62- ctx. state . changed = true ;
42+ _ => { }
6343 }
6444 }
6545
@@ -103,9 +83,9 @@ impl<'a> PeepholeOptimizations {
10383 }
10484 // "a op b" => "a op b"
10585 // "(a op b) op c" => "(a op b) op c"
106- let mut logic_expr = ctx. ast . logical_expression ( span, a, op, b) ;
107- self . minimize_logical_expression ( & mut logic_expr, ctx)
108- . unwrap_or_else ( || Expression :: LogicalExpression ( ctx . ast . alloc ( logic_expr) ) )
86+ let mut logic_expr = ctx. ast . expression_logical ( span, a, op, b) ;
87+ self . minimize_logical_expression ( & mut logic_expr, ctx) ;
88+ logic_expr
10989 }
11090
11191 // `typeof foo === 'number'` -> `typeof foo == 'number'`
@@ -115,17 +95,15 @@ impl<'a> PeepholeOptimizations {
11595 // ^^^^^^^^^^^^^^ `ctx.expression_value_type(&e.left).is_boolean()` is `true`.
11696 // `x >> +y !== 0` -> `x >> +y`
11797 // ^^^^^^^ ctx.expression_value_type(&e.left).is_number()` is `true`.
118- fn try_minimize_binary (
119- e : & mut BinaryExpression < ' a > ,
120- ctx : & mut Ctx < ' a , ' _ > ,
121- ) -> Option < Expression < ' a > > {
98+ fn try_minimize_binary ( expr : & mut Expression < ' a > , ctx : & mut Ctx < ' a , ' _ > ) {
99+ let Expression :: BinaryExpression ( e) = expr else { return } ;
122100 if !e. operator . is_equality ( ) {
123- return None ;
101+ return ;
124102 }
125103 let left = e. left . value_type ( ctx) ;
126104 let right = e. right . value_type ( ctx) ;
127105 if left. is_undetermined ( ) || right. is_undetermined ( ) {
128- return None ;
106+ return ;
129107 }
130108 if left == right {
131109 match e. operator {
@@ -139,12 +117,14 @@ impl<'a> PeepholeOptimizations {
139117 }
140118 }
141119 if !left. is_boolean ( ) {
142- return None ;
120+ return ;
143121 }
144122 if e. right . may_have_side_effects ( ctx) {
145- return None ;
123+ return ;
146124 }
147- let mut b = e. right . evaluate_value ( ctx) . and_then ( ConstantValue :: into_boolean) ?;
125+ let Some ( mut b) = e. right . evaluate_value ( ctx) . and_then ( ConstantValue :: into_boolean) else {
126+ return ;
127+ } ;
148128 match e. operator {
149129 BinaryOperator :: Inequality | BinaryOperator :: StrictInequality => {
150130 e. operator = BinaryOperator :: Equality ;
@@ -154,14 +134,15 @@ impl<'a> PeepholeOptimizations {
154134 e. operator = BinaryOperator :: Equality ;
155135 }
156136 BinaryOperator :: Equality => { }
157- _ => return None ,
137+ _ => return ,
158138 }
159- Some ( if b {
139+ * expr = if b {
160140 e. left . take_in ( ctx. ast )
161141 } else {
162142 let argument = e. left . take_in ( ctx. ast ) ;
163143 ctx. ast . expression_unary ( e. span , UnaryOperator :: LogicalNot , argument)
164- } )
144+ } ;
145+ ctx. state . changed = true ;
165146 }
166147
167148 /// Compress `foo == true` into `foo == 1`.
@@ -171,19 +152,19 @@ impl<'a> PeepholeOptimizations {
171152 ///
172153 /// In `IsLooselyEqual`, `true` and `false` are converted to `1` and `0` first.
173154 /// <https://tc39.es/ecma262/multipage/abstract-operations.html#sec-islooselyequal>
174- fn try_compress_is_loose_boolean ( e : & mut BinaryExpression < ' a > , ctx : & mut Ctx < ' a , ' _ > ) -> bool {
155+ fn try_compress_is_loose_boolean ( e : & mut BinaryExpression < ' a > , ctx : & mut Ctx < ' a , ' _ > ) {
175156 if !matches ! ( e. operator, BinaryOperator :: Equality | BinaryOperator :: Inequality ) {
176- return false ;
157+ return ;
177158 }
178-
179159 if let Some ( ConstantValue :: Boolean ( left_bool) ) = e. left . evaluate_value ( ctx) {
180160 e. left = ctx. ast . expression_numeric_literal (
181161 e. left . span ( ) ,
182162 if left_bool { 1.0 } else { 0.0 } ,
183163 None ,
184164 NumberBase :: Decimal ,
185165 ) ;
186- return true ;
166+ ctx. state . changed = true ;
167+ return ;
187168 }
188169 if let Some ( ConstantValue :: Boolean ( right_bool) ) = e. right . evaluate_value ( ctx) {
189170 e. right = ctx. ast . expression_numeric_literal (
@@ -192,9 +173,8 @@ impl<'a> PeepholeOptimizations {
192173 None ,
193174 NumberBase :: Decimal ,
194175 ) ;
195- return true ;
176+ ctx . state . changed = true ;
196177 }
197- false
198178 }
199179
200180 /// Returns the identifier or the assignment target's identifier of the given expression.
@@ -222,15 +202,15 @@ impl<'a> PeepholeOptimizations {
222202 & self ,
223203 expr : & mut AssignmentExpression < ' a > ,
224204 ctx : & mut Ctx < ' a , ' _ > ,
225- ) -> bool {
205+ ) {
226206 if ctx. options ( ) . target < ESTarget :: ES2020 {
227- return false ;
207+ return ;
228208 }
229209 if !matches ! ( expr. operator, AssignmentOperator :: Assign ) {
230- return false ;
210+ return ;
231211 }
232212
233- let Expression :: LogicalExpression ( logical_expr) = & mut expr. right else { return false } ;
213+ let Expression :: LogicalExpression ( logical_expr) = & mut expr. right else { return } ;
234214 // NOTE: if the right hand side is an anonymous function, applying this compression will
235215 // set the `name` property of that function.
236216 // Since codes relying on the fact that function's name is undefined should be rare,
@@ -241,64 +221,64 @@ impl<'a> PeepholeOptimizations {
241221 Expression :: Identifier ( read_id_ref) ,
242222 ) = ( & expr. left , & logical_expr. left )
243223 else {
244- return false ;
224+ return ;
245225 } ;
246226 // It should also early return when the reference might refer to a reference value created by a with statement
247227 // when the minifier supports with statements
248228 if write_id_ref. name != read_id_ref. name || ctx. is_global_reference ( write_id_ref) {
249- return false ;
229+ return ;
250230 }
251231
252232 let new_op = logical_expr. operator . to_assignment_operator ( ) ;
253233 expr. operator = new_op;
254234 expr. right = logical_expr. right . take_in ( ctx. ast ) ;
255- true
235+ ctx . state . changed = true ;
256236 }
257237
258238 /// Compress `a = a + b` to `a += b`
259239 fn try_compress_normal_assignment_to_combined_assignment (
260240 expr : & mut AssignmentExpression < ' a > ,
261241 ctx : & mut Ctx < ' a , ' _ > ,
262- ) -> bool {
242+ ) {
263243 if !matches ! ( expr. operator, AssignmentOperator :: Assign ) {
264- return false ;
244+ return ;
265245 }
266-
267- let Expression :: BinaryExpression ( binary_expr) = & mut expr. right else { return false } ;
268- let Some ( new_op) = binary_expr. operator . to_assignment_operator ( ) else { return false } ;
269-
246+ let Expression :: BinaryExpression ( binary_expr) = & mut expr. right else { return } ;
247+ let Some ( new_op) = binary_expr. operator . to_assignment_operator ( ) else { return } ;
270248 if !Self :: has_no_side_effect_for_evaluation_same_target ( & expr. left , & binary_expr. left , ctx)
271249 {
272- return false ;
250+ return ;
273251 }
274-
275252 expr. operator = new_op;
276253 expr. right = binary_expr. right . take_in ( ctx. ast ) ;
277- true
254+ ctx . state . changed = true ;
278255 }
279256
280257 /// Compress `a -= 1` to `--a` and `a -= -1` to `++a`
281258 #[ expect( clippy:: float_cmp) ]
282259 fn try_compress_assignment_to_update_expression (
283- expr : & mut AssignmentExpression < ' a > ,
260+ expr : & mut Expression < ' a > ,
284261 ctx : & mut Ctx < ' a , ' _ > ,
285- ) -> Option < Expression < ' a > > {
286- if !matches ! ( expr. operator, AssignmentOperator :: Subtraction ) {
287- return None ;
262+ ) {
263+ let Expression :: AssignmentExpression ( e) = expr else { return } ;
264+ if !matches ! ( e. operator, AssignmentOperator :: Subtraction ) {
265+ return ;
288266 }
289- let Expression :: NumericLiteral ( num) = & expr . right else {
290- return None ;
291- } ;
292- let target = expr . left . as_simple_assignment_target_mut ( ) ? ;
293- let operator = if num . value == 1.0 {
294- UpdateOperator :: Decrement
295- } else if num . value == - 1.0 {
296- UpdateOperator :: Increment
267+ let operator = if let Expression :: NumericLiteral ( num) = & e . right {
268+ if num . value == 1.0 {
269+ UpdateOperator :: Decrement
270+ } else if num . value == - 1.0 {
271+ UpdateOperator :: Increment
272+ } else {
273+ return ;
274+ }
297275 } else {
298- return None ;
276+ return ;
299277 } ;
278+ let Some ( target) = e. left . as_simple_assignment_target_mut ( ) else { return } ;
300279 let target = target. take_in ( ctx. ast ) ;
301- Some ( ctx. ast . expression_update ( expr. span , operator, true , target) )
280+ * expr = ctx. ast . expression_update ( e. span , operator, true , target) ;
281+ ctx. state . changed = true ;
302282 }
303283}
304284
0 commit comments