@@ -68,6 +68,7 @@ impl<'a> PeepholeOptimizations {
68
68
"abs" | "ceil" | "floor" | "round" | "fround" | "trunc" | "sign" => {
69
69
Self :: try_fold_math_unary ( * span, arguments, name, object, ctx)
70
70
}
71
+ "min" | "max" => Self :: try_fold_math_variadic ( * span, arguments, name, object, ctx) ,
71
72
_ => None ,
72
73
} ;
73
74
if let Some ( replacement) = replacement {
@@ -357,7 +358,7 @@ impl<'a> PeepholeOptimizations {
357
358
}
358
359
359
360
fn validate_arguments ( args : & Arguments , expected_len : usize ) -> bool {
360
- args. len ( ) == expected_len && args. iter ( ) . all ( Argument :: is_expression)
361
+ ( args. len ( ) == expected_len) && args. iter ( ) . all ( Argument :: is_expression)
361
362
}
362
363
363
364
/// `Math.pow(a, b)` -> `+(a) ** +b`
@@ -490,6 +491,46 @@ impl<'a> PeepholeOptimizations {
490
491
Some ( ctx. ast . expression_numeric_literal ( span, result, None , NumberBase :: Decimal ) )
491
492
}
492
493
494
+ fn try_fold_math_variadic (
495
+ span : Span ,
496
+ arguments : & Arguments ,
497
+ name : & str ,
498
+ object : & Expression < ' a > ,
499
+ ctx : Ctx < ' a , ' _ > ,
500
+ ) -> Option < Expression < ' a > > {
501
+ if !Self :: validate_global_reference ( object, "Math" , ctx) {
502
+ return None ;
503
+ }
504
+ let numbers = arguments
505
+ . iter ( )
506
+ . map ( |arg| arg. as_expression ( ) . map ( |e| ctx. get_side_free_number_value ( e) ) ?)
507
+ . collect :: < Option < Vec < _ > > > ( ) ?;
508
+ let result = if numbers. iter ( ) . any ( |n| n. is_nan ( ) ) {
509
+ f64:: NAN
510
+ } else {
511
+ match name {
512
+ // TODO
513
+ // see <https://github.com/rust-lang/rust/issues/83984>, we can't use `min` and `max` here due to inconsistency
514
+ "min" => numbers. iter ( ) . copied ( ) . fold ( f64:: INFINITY , |a, b| {
515
+ if a < b || ( ( a == 0f64 ) && ( b == 0f64 ) && ( a. to_bits ( ) > b. to_bits ( ) ) ) {
516
+ a
517
+ } else {
518
+ b
519
+ }
520
+ } ) ,
521
+ "max" => numbers. iter ( ) . copied ( ) . fold ( f64:: NEG_INFINITY , |a, b| {
522
+ if a > b || ( ( a == 0f64 ) && ( b == 0f64 ) && ( a. to_bits ( ) < b. to_bits ( ) ) ) {
523
+ a
524
+ } else {
525
+ b
526
+ }
527
+ } ) ,
528
+ _ => return None ,
529
+ }
530
+ } ;
531
+ Some ( ctx. ast . expression_numeric_literal ( span, result, None , NumberBase :: Decimal ) )
532
+ }
533
+
493
534
/// `[].concat(a).concat(b)` -> `[].concat(a, b)`
494
535
/// `"".concat(a).concat(b)` -> `"".concat(a, b)`
495
536
fn try_fold_concat_chain ( & mut self , node : & mut Expression < ' a > , ctx : Ctx < ' a , ' _ > ) {
@@ -1289,25 +1330,33 @@ mod test {
1289
1330
}
1290
1331
1291
1332
#[ test]
1292
- #[ ignore]
1293
1333
fn test_fold_math_functions_max ( ) {
1294
- test_same ( "Math.max(Math.random(), 1)" ) ;
1334
+ test_same_value ( "Math.max(Math.random(), 1)" ) ;
1295
1335
1296
- test ( "Math.max()" , "-Infinity" ) ;
1297
- test ( "Math.max(0)" , "0" ) ;
1298
- test ( "Math.max(0, 1)" , "1" ) ;
1299
- test ( "Math.max(0, 1, -1, 200)" , "200" ) ;
1336
+ test_value ( "Math.max()" , "-Infinity" ) ;
1337
+ test_value ( "Math.max(0)" , "0" ) ;
1338
+ test_value ( "Math.max(0, 1)" , "1" ) ;
1339
+ test_value ( "Math.max(0, 1, -1, 200)" , "200" ) ;
1340
+ test_value ( "Math.max(0, -1, -Infinity)" , "0" ) ;
1341
+ test_value ( "Math.max(0, -1, -Infinity, NaN)" , "NaN" ) ;
1342
+ test_value ( "Math.max(0, -0)" , "0" ) ;
1343
+ test_value ( "Math.max(-0, 0)" , "0" ) ;
1344
+ test_same_value ( "Math.max(...a, 1)" ) ;
1300
1345
}
1301
1346
1302
1347
#[ test]
1303
- #[ ignore]
1304
1348
fn test_fold_math_functions_min ( ) {
1305
- test_same ( "Math.min(Math.random(), 1)" ) ;
1306
-
1307
- test ( "Math.min()" , "Infinity" ) ;
1308
- test ( "Math.min(3)" , "3" ) ;
1309
- test ( "Math.min(0, 1)" , "0" ) ;
1310
- test ( "Math.min(0, 1, -1, 200)" , "-1" ) ;
1349
+ test_same_value ( "Math.min(Math.random(), 1)" ) ;
1350
+
1351
+ test_value ( "Math.min()" , "Infinity" ) ;
1352
+ test_value ( "Math.min(3)" , "3" ) ;
1353
+ test_value ( "Math.min(0, 1)" , "0" ) ;
1354
+ test_value ( "Math.min(0, 1, -1, 200)" , "-1" ) ;
1355
+ test_value ( "Math.min(0, -1, -Infinity)" , "-Infinity" ) ;
1356
+ test_value ( "Math.min(0, -1, -Infinity, NaN)" , "NaN" ) ;
1357
+ test_value ( "Math.min(0, -0)" , "-0" ) ;
1358
+ test_value ( "Math.min(-0, 0)" , "-0" ) ;
1359
+ test_same_value ( "Math.min(...a, 1)" ) ;
1311
1360
}
1312
1361
1313
1362
#[ test]
0 commit comments