diff --git a/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs b/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs index f285788f043c..d91c6a846bf1 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs @@ -345,6 +345,16 @@ impl Optimizer<'_> { self.changed = true; report_change!("evaluate: Evaluated an expression as `{}`", value); + if value.is_nan() { + *e = Ident::new( + "NaN".into(), + e.span(), + SyntaxContext::empty().apply_mark(self.marks.unresolved_mark), + ) + .into(); + return; + } + *e = Lit::Num(Number { span: e.span(), value, diff --git a/crates/swc_ecma_minifier/src/compress/util/mod.rs b/crates/swc_ecma_minifier/src/compress/util/mod.rs index 32571a586495..5cc58bc72f5d 100644 --- a/crates/swc_ecma_minifier/src/compress/util/mod.rs +++ b/crates/swc_ecma_minifier/src/compress/util/mod.rs @@ -512,10 +512,16 @@ pub(crate) fn eval_as_number(expr_ctx: &ExprCtx, e: &Expr) -> Option { if args.len() != 2 { return None; } - let first = eval_as_number(expr_ctx, &args[0].expr)?; - let second = eval_as_number(expr_ctx, &args[1].expr)?; + let base = eval_as_number(expr_ctx, &args[0].expr)?; + let exponent = eval_as_number(expr_ctx, &args[1].expr)?; - return Some(first.powf(second)); + // https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-numeric-types-number-exponentiate + // https://github.com/rust-lang/rust/issues/60468 + if exponent.is_nan() { + return Some(f64::NAN); + } + + return Some(base.powf(exponent)); } _ => {} diff --git a/crates/swc_ecma_minifier/tests/passing.txt b/crates/swc_ecma_minifier/tests/passing.txt index f454e7c65725..d55b19c0e816 100644 --- a/crates/swc_ecma_minifier/tests/passing.txt +++ b/crates/swc_ecma_minifier/tests/passing.txt @@ -535,11 +535,13 @@ evaluate/or/input.js evaluate/positive_zero/input.js evaluate/pow/input.js evaluate/pow_mixed/input.js +evaluate/pow_nan/input.js evaluate/pow_sequence/input.js evaluate/pow_sequence_with_constants_and_parens/input.js evaluate/pow_sequence_with_parens/input.js evaluate/pow_sequence_with_parens_evaluated/input.js evaluate/pow_sequence_with_parens_exact/input.js +evaluate/pow_spec/input.js evaluate/pow_with_number_constants/input.js evaluate/pow_with_right_side_evaluating_to_unary/input.js evaluate/prop_function/input.js @@ -1245,6 +1247,7 @@ pure_getters/collapse_vars_2_strict/input.js pure_getters/impure_getter_1/input.js pure_getters/issue_2110_1/input.js pure_getters/issue_2110_2/input.js +pure_getters/issue_2265_1/input.js pure_getters/issue_2265_2/input.js pure_getters/issue_2265_4/input.js pure_getters/issue_2313_1/input.js diff --git a/crates/swc_ecma_minifier/tests/postponed.txt b/crates/swc_ecma_minifier/tests/postponed.txt index 84af33795ad7..e30420344eab 100644 --- a/crates/swc_ecma_minifier/tests/postponed.txt +++ b/crates/swc_ecma_minifier/tests/postponed.txt @@ -111,7 +111,6 @@ pure_funcs/unary/input.js pure_getters/collapse_vars_1_true/input.js pure_getters/collapse_vars_2_true/input.js pure_getters/impure_getter_2/input.js -pure_getters/issue_2265_1/input.js pure_getters/issue_2265_3/input.js pure_getters/issue_2313_6/input.js pure_getters/issue_2838/input.js diff --git a/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_nan/config.json b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_nan/config.json new file mode 100644 index 000000000000..3205e065ae01 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_nan/config.json @@ -0,0 +1,3 @@ +{ + "evaluate": true +} diff --git a/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_nan/input.js b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_nan/input.js new file mode 100644 index 000000000000..3aaaee6dea32 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_nan/input.js @@ -0,0 +1 @@ +console.log(Math.pow(1, NaN)); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_nan/output.js b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_nan/output.js new file mode 100644 index 000000000000..89e3dd4ea485 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_nan/output.js @@ -0,0 +1 @@ +console.log(NaN); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_nan/output.mangleOnly.js b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_nan/output.mangleOnly.js new file mode 100644 index 000000000000..3aaaee6dea32 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_nan/output.mangleOnly.js @@ -0,0 +1 @@ +console.log(Math.pow(1, NaN)); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_nan/output.terser.js b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_nan/output.terser.js new file mode 100644 index 000000000000..e389ab1d5e2f --- /dev/null +++ b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_nan/output.terser.js @@ -0,0 +1 @@ +console.log(NaN); \ No newline at end of file diff --git a/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/config.json b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/config.json new file mode 100644 index 000000000000..3205e065ae01 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/config.json @@ -0,0 +1,3 @@ +{ + "evaluate": true +} diff --git a/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/expected.stdout b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/expected.stdout new file mode 100644 index 000000000000..e50f2f14c9f3 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/expected.stdout @@ -0,0 +1,81 @@ +NaN +NaN +NaN +NaN +1 +NaN +NaN +NaN +1 +NaN +Infinity +Infinity +Infinity +1 +Infinity +0 +0 +1 +NaN +Infinity +4 +2 +1 +1.4142135623730951 +0 +0.5 +1 +NaN +NaN +1 +1 +1 +1 +NaN +1 +1 +NaN +0 +0.25 +0.5 +1 +0.7071067811865476 +Infinity +2 +1 +NaN +0 +0 +0 +1 +0 +Infinity +Infinity +1 +NaN +Infinity +Infinity +-Infinity +1 +Infinity +0 +-0 +1 +NaN +NaN +1 +-1 +1 +NaN +NaN +-1 +1 +NaN +0 +0 +-0 +1 +0 +Infinity +-Infinity +1 diff --git a/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/input.js b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/input.js new file mode 100644 index 000000000000..562d5f9d153c --- /dev/null +++ b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/input.js @@ -0,0 +1,81 @@ +console.log(Math.pow(NaN, NaN)); +console.log(Math.pow(NaN, Infinity)); +console.log(Math.pow(NaN, 2)); +console.log(Math.pow(NaN, 1)); +console.log(Math.pow(NaN, 0)); +console.log(Math.pow(NaN, 0.5)); +console.log(Math.pow(NaN, -Infinity)); +console.log(Math.pow(NaN, -1)); +console.log(Math.pow(NaN, -0)); +console.log(Math.pow(Infinity, NaN)); +console.log(Math.pow(Infinity, Infinity)); +console.log(Math.pow(Infinity, 2)); +console.log(Math.pow(Infinity, 1)); +console.log(Math.pow(Infinity, 0)); +console.log(Math.pow(Infinity, 0.5)); +console.log(Math.pow(Infinity, -Infinity)); +console.log(Math.pow(Infinity, -1)); +console.log(Math.pow(Infinity, -0)); +console.log(Math.pow(2, NaN)); +console.log(Math.pow(2, Infinity)); +console.log(Math.pow(2, 2)); +console.log(Math.pow(2, 1)); +console.log(Math.pow(2, 0)); +console.log(Math.pow(2, 0.5)); +console.log(Math.pow(2, -Infinity)); +console.log(Math.pow(2, -1)); +console.log(Math.pow(2, -0)); +console.log(Math.pow(1, NaN)); +console.log(Math.pow(1, Infinity)); +console.log(Math.pow(1, 2)); +console.log(Math.pow(1, 1)); +console.log(Math.pow(1, 0)); +console.log(Math.pow(1, 0.5)); +console.log(Math.pow(1, -Infinity)); +console.log(Math.pow(1, -1)); +console.log(Math.pow(1, -0)); +console.log(Math.pow(0.5, NaN)); +console.log(Math.pow(0.5, Infinity)); +console.log(Math.pow(0.5, 2)); +console.log(Math.pow(0.5, 1)); +console.log(Math.pow(0.5, 0)); +console.log(Math.pow(0.5, 0.5)); +console.log(Math.pow(0.5, -Infinity)); +console.log(Math.pow(0.5, -1)); +console.log(Math.pow(0.5, -0)); +console.log(Math.pow(0, NaN)); +console.log(Math.pow(0, Infinity)); +console.log(Math.pow(0, 2)); +console.log(Math.pow(0, 1)); +console.log(Math.pow(0, 0)); +console.log(Math.pow(0, 0.5)); +console.log(Math.pow(0, -Infinity)); +console.log(Math.pow(0, -1)); +console.log(Math.pow(0, -0)); +console.log(Math.pow(-Infinity, NaN)); +console.log(Math.pow(-Infinity, Infinity)); +console.log(Math.pow(-Infinity, 2)); +console.log(Math.pow(-Infinity, 1)); +console.log(Math.pow(-Infinity, 0)); +console.log(Math.pow(-Infinity, 0.5)); +console.log(Math.pow(-Infinity, -Infinity)); +console.log(Math.pow(-Infinity, -1)); +console.log(Math.pow(-Infinity, -0)); +console.log(Math.pow(-1, NaN)); +console.log(Math.pow(-1, Infinity)); +console.log(Math.pow(-1, 2)); +console.log(Math.pow(-1, 1)); +console.log(Math.pow(-1, 0)); +console.log(Math.pow(-1, 0.5)); +console.log(Math.pow(-1, -Infinity)); +console.log(Math.pow(-1, -1)); +console.log(Math.pow(-1, -0)); +console.log(Math.pow(-0, NaN)); +console.log(Math.pow(-0, Infinity)); +console.log(Math.pow(-0, 2)); +console.log(Math.pow(-0, 1)); +console.log(Math.pow(-0, 0)); +console.log(Math.pow(-0, 0.5)); +console.log(Math.pow(-0, -Infinity)); +console.log(Math.pow(-0, -1)); +console.log(Math.pow(-0, -0)); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/output.js b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/output.js new file mode 100644 index 000000000000..3d1bf52a0c95 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/output.js @@ -0,0 +1,81 @@ +console.log(NaN); +console.log(Math.pow(NaN, 1 / 0)); +console.log(NaN); +console.log(NaN); +console.log(1); +console.log(NaN); +console.log(Math.pow(NaN, -1 / 0)); +console.log(NaN); +console.log(1); +console.log(Math.pow(1 / 0, NaN)); +console.log(Math.pow(1 / 0, 1 / 0)); +console.log(Math.pow(1 / 0, 2)); +console.log(Math.pow(1 / 0, 1)); +console.log(Math.pow(1 / 0, 0)); +console.log(Math.pow(1 / 0, 0.5)); +console.log(Math.pow(1 / 0, -1 / 0)); +console.log(Math.pow(1 / 0, -1)); +console.log(Math.pow(1 / 0, -0)); +console.log(NaN); +console.log(Math.pow(2, 1 / 0)); +console.log(4); +console.log(2); +console.log(1); +console.log(1.4142135623730951); +console.log(Math.pow(2, -1 / 0)); +console.log(0.5); +console.log(1); +console.log(NaN); +console.log(Math.pow(1, 1 / 0)); +console.log(1); +console.log(1); +console.log(1); +console.log(1); +console.log(Math.pow(1, -1 / 0)); +console.log(1); +console.log(1); +console.log(NaN); +console.log(Math.pow(0.5, 1 / 0)); +console.log(0.25); +console.log(0.5); +console.log(1); +console.log(0.7071067811865476); +console.log(Math.pow(0.5, -1 / 0)); +console.log(2); +console.log(1); +console.log(NaN); +console.log(Math.pow(0, 1 / 0)); +console.log(0); +console.log(0); +console.log(1); +console.log(0); +console.log(Math.pow(0, -1 / 0)); +console.log(Infinity); +console.log(1); +console.log(Math.pow(-1 / 0, NaN)); +console.log(Math.pow(-1 / 0, 1 / 0)); +console.log(Math.pow(-1 / 0, 2)); +console.log(Math.pow(-1 / 0, 1)); +console.log(Math.pow(-1 / 0, 0)); +console.log(Math.pow(-1 / 0, 0.5)); +console.log(Math.pow(-1 / 0, -1 / 0)); +console.log(Math.pow(-1 / 0, -1)); +console.log(Math.pow(-1 / 0, -0)); +console.log(NaN); +console.log(Math.pow(-1, 1 / 0)); +console.log(1); +console.log(-1); +console.log(1); +console.log(NaN); +console.log(Math.pow(-1, -1 / 0)); +console.log(-1); +console.log(1); +console.log(NaN); +console.log(Math.pow(-0, 1 / 0)); +console.log(0); +console.log(-0); +console.log(1); +console.log(0); +console.log(Math.pow(-0, -1 / 0)); +console.log(-Infinity); +console.log(1); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/output.mangleOnly.js b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/output.mangleOnly.js new file mode 100644 index 000000000000..562d5f9d153c --- /dev/null +++ b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/output.mangleOnly.js @@ -0,0 +1,81 @@ +console.log(Math.pow(NaN, NaN)); +console.log(Math.pow(NaN, Infinity)); +console.log(Math.pow(NaN, 2)); +console.log(Math.pow(NaN, 1)); +console.log(Math.pow(NaN, 0)); +console.log(Math.pow(NaN, 0.5)); +console.log(Math.pow(NaN, -Infinity)); +console.log(Math.pow(NaN, -1)); +console.log(Math.pow(NaN, -0)); +console.log(Math.pow(Infinity, NaN)); +console.log(Math.pow(Infinity, Infinity)); +console.log(Math.pow(Infinity, 2)); +console.log(Math.pow(Infinity, 1)); +console.log(Math.pow(Infinity, 0)); +console.log(Math.pow(Infinity, 0.5)); +console.log(Math.pow(Infinity, -Infinity)); +console.log(Math.pow(Infinity, -1)); +console.log(Math.pow(Infinity, -0)); +console.log(Math.pow(2, NaN)); +console.log(Math.pow(2, Infinity)); +console.log(Math.pow(2, 2)); +console.log(Math.pow(2, 1)); +console.log(Math.pow(2, 0)); +console.log(Math.pow(2, 0.5)); +console.log(Math.pow(2, -Infinity)); +console.log(Math.pow(2, -1)); +console.log(Math.pow(2, -0)); +console.log(Math.pow(1, NaN)); +console.log(Math.pow(1, Infinity)); +console.log(Math.pow(1, 2)); +console.log(Math.pow(1, 1)); +console.log(Math.pow(1, 0)); +console.log(Math.pow(1, 0.5)); +console.log(Math.pow(1, -Infinity)); +console.log(Math.pow(1, -1)); +console.log(Math.pow(1, -0)); +console.log(Math.pow(0.5, NaN)); +console.log(Math.pow(0.5, Infinity)); +console.log(Math.pow(0.5, 2)); +console.log(Math.pow(0.5, 1)); +console.log(Math.pow(0.5, 0)); +console.log(Math.pow(0.5, 0.5)); +console.log(Math.pow(0.5, -Infinity)); +console.log(Math.pow(0.5, -1)); +console.log(Math.pow(0.5, -0)); +console.log(Math.pow(0, NaN)); +console.log(Math.pow(0, Infinity)); +console.log(Math.pow(0, 2)); +console.log(Math.pow(0, 1)); +console.log(Math.pow(0, 0)); +console.log(Math.pow(0, 0.5)); +console.log(Math.pow(0, -Infinity)); +console.log(Math.pow(0, -1)); +console.log(Math.pow(0, -0)); +console.log(Math.pow(-Infinity, NaN)); +console.log(Math.pow(-Infinity, Infinity)); +console.log(Math.pow(-Infinity, 2)); +console.log(Math.pow(-Infinity, 1)); +console.log(Math.pow(-Infinity, 0)); +console.log(Math.pow(-Infinity, 0.5)); +console.log(Math.pow(-Infinity, -Infinity)); +console.log(Math.pow(-Infinity, -1)); +console.log(Math.pow(-Infinity, -0)); +console.log(Math.pow(-1, NaN)); +console.log(Math.pow(-1, Infinity)); +console.log(Math.pow(-1, 2)); +console.log(Math.pow(-1, 1)); +console.log(Math.pow(-1, 0)); +console.log(Math.pow(-1, 0.5)); +console.log(Math.pow(-1, -Infinity)); +console.log(Math.pow(-1, -1)); +console.log(Math.pow(-1, -0)); +console.log(Math.pow(-0, NaN)); +console.log(Math.pow(-0, Infinity)); +console.log(Math.pow(-0, 2)); +console.log(Math.pow(-0, 1)); +console.log(Math.pow(-0, 0)); +console.log(Math.pow(-0, 0.5)); +console.log(Math.pow(-0, -Infinity)); +console.log(Math.pow(-0, -1)); +console.log(Math.pow(-0, -0)); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/output.terser.js b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/output.terser.js new file mode 100644 index 000000000000..aed56a32b8ff --- /dev/null +++ b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/pow_spec/output.terser.js @@ -0,0 +1 @@ +console.log(Math.pow(NaN,NaN)),console.log(Math.pow(NaN,1/0)),console.log(Math.pow(NaN,2)),console.log(Math.pow(NaN,1)),console.log(Math.pow(NaN,0)),console.log(Math.pow(NaN,.5)),console.log(Math.pow(NaN,-1/0)),console.log(Math.pow(NaN,-1)),console.log(Math.pow(NaN,-0)),console.log(Math.pow(1/0,NaN)),console.log(Math.pow(1/0,1/0)),console.log(Math.pow(1/0,2)),console.log(Math.pow(1/0,1)),console.log(Math.pow(1/0,0)),console.log(Math.pow(1/0,.5)),console.log(Math.pow(1/0,-1/0)),console.log(Math.pow(1/0,-1)),console.log(Math.pow(1/0,-0)),console.log(Math.pow(2,NaN)),console.log(Math.pow(2,1/0)),console.log(Math.pow(2,2)),console.log(Math.pow(2,1)),console.log(Math.pow(2,0)),console.log(Math.pow(2,.5)),console.log(Math.pow(2,-1/0)),console.log(Math.pow(2,-1)),console.log(Math.pow(2,-0)),console.log(Math.pow(1,NaN)),console.log(Math.pow(1,1/0)),console.log(Math.pow(1,2)),console.log(Math.pow(1,1)),console.log(Math.pow(1,0)),console.log(Math.pow(1,.5)),console.log(Math.pow(1,-1/0)),console.log(Math.pow(1,-1)),console.log(Math.pow(1,-0)),console.log(Math.pow(.5,NaN)),console.log(Math.pow(.5,1/0)),console.log(Math.pow(.5,2)),console.log(Math.pow(.5,1)),console.log(Math.pow(.5,0)),console.log(Math.pow(.5,.5)),console.log(Math.pow(.5,-1/0)),console.log(Math.pow(.5,-1)),console.log(Math.pow(.5,-0)),console.log(Math.pow(0,NaN)),console.log(Math.pow(0,1/0)),console.log(Math.pow(0,2)),console.log(Math.pow(0,1)),console.log(Math.pow(0,0)),console.log(Math.pow(0,.5)),console.log(Math.pow(0,-1/0)),console.log(Math.pow(0,-1)),console.log(Math.pow(0,-0)),console.log(Math.pow(-1/0,NaN)),console.log(Math.pow(-1/0,1/0)),console.log(Math.pow(-1/0,2)),console.log(Math.pow(-1/0,1)),console.log(Math.pow(-1/0,0)),console.log(Math.pow(-1/0,.5)),console.log(Math.pow(-1/0,-1/0)),console.log(Math.pow(-1/0,-1)),console.log(Math.pow(-1/0,-0)),console.log(Math.pow(-1,NaN)),console.log(Math.pow(-1,1/0)),console.log(Math.pow(-1,2)),console.log(Math.pow(-1,1)),console.log(Math.pow(-1,0)),console.log(Math.pow(-1,.5)),console.log(Math.pow(-1,-1/0)),console.log(Math.pow(-1,-1)),console.log(Math.pow(-1,-0)),console.log(Math.pow(-0,NaN)),console.log(Math.pow(-0,1/0)),console.log(Math.pow(-0,2)),console.log(Math.pow(-0,1)),console.log(Math.pow(-0,0)),console.log(Math.pow(-0,.5)),console.log(Math.pow(-0,-1/0)),console.log(Math.pow(-0,-1)),console.log(Math.pow(-0,-0)); \ No newline at end of file