From 7e05adf0fac77455c60e8cd42720c48831f98f5f Mon Sep 17 00:00:00 2001 From: Levi Date: Tue, 5 Mar 2024 00:25:54 +1300 Subject: [PATCH] feat(es/minifier): Allow `expr_simplifier` to do arithmetic with string literals (#8683) **Description:** This PR implements the feature described for the issue in #8682. **Related issue:** - Closes #8682. --- ...enumConstantMemberWithString.2.minified.js | 2 +- ...ntMemberWithTemplateLiterals.2.minified.js | 2 +- .../src/simplify/expr/mod.rs | 5 ++-- .../src/simplify/expr/tests.rs | 27 +++++++++++++++++++ 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/crates/swc/tests/tsc-references/enumConstantMemberWithString.2.minified.js b/crates/swc/tests/tsc-references/enumConstantMemberWithString.2.minified.js index da9113fe5296..79e3fbf55c30 100644 --- a/crates/swc/tests/tsc-references/enumConstantMemberWithString.2.minified.js +++ b/crates/swc/tests/tsc-references/enumConstantMemberWithString.2.minified.js @@ -1,3 +1,3 @@ //// [enumConstantMemberWithString.ts] var T1, T2, T3, T4, T5, T11, T21, T31; -(T11 = T1 || (T1 = {})).a = "1", T11.b = "12", T11.c = "123", T11[T11.d = "a" - "a"] = "d", T11.e = "a1", (T21 = T2 || (T2 = {})).a = "1", T21.b = "12", (T31 = T3 || (T3 = {})).a = "1", T31.b = "12", T31[T31.c = 1] = "c", T31[T31.d = 3] = "d", (T4 || (T4 = {})).a = "1", (T5 || (T5 = {})).a = "12"; +(T11 = T1 || (T1 = {})).a = "1", T11.b = "12", T11.c = "123", T11[T11.d = NaN] = "d", T11.e = "a1", (T21 = T2 || (T2 = {})).a = "1", T21.b = "12", (T31 = T3 || (T3 = {})).a = "1", T31.b = "12", T31[T31.c = 1] = "c", T31[T31.d = 3] = "d", (T4 || (T4 = {})).a = "1", (T5 || (T5 = {})).a = "12"; diff --git a/crates/swc/tests/tsc-references/enumConstantMemberWithTemplateLiterals.2.minified.js b/crates/swc/tests/tsc-references/enumConstantMemberWithTemplateLiterals.2.minified.js index a79a8f04e579..ce6ef711efa9 100644 --- a/crates/swc/tests/tsc-references/enumConstantMemberWithTemplateLiterals.2.minified.js +++ b/crates/swc/tests/tsc-references/enumConstantMemberWithTemplateLiterals.2.minified.js @@ -1,3 +1,3 @@ //// [enumConstantMemberWithTemplateLiterals.ts] var T1, T2, T3, T4, T5, T6, T21, T41, T51, T61; -(T1 || (T1 = {})).a = "1", (T21 = T2 || (T2 = {})).a = "1", T21.b = "2", T21[T21.c = 3] = "c", (T3 || (T3 = {})).a = "11", (T41 = T4 || (T4 = {})).a = "1", T41.b = "11", T41.c = "12", T41.d = "21", T41.e = "211", (T51 = T5 || (T5 = {})).a = "1", T51.b = "12", T51.c = "123", T51[T51.d = 1] = "d", T51[T51.e = "1" - "1"] = "e", T51.f = "11", T51.g = "123", T51[T51.h = 1] = "h", (T61 = T6 || (T6 = {}))[T61.a = 1] = "a", T61[T61.b = 2] = "b"; +(T1 || (T1 = {})).a = "1", (T21 = T2 || (T2 = {})).a = "1", T21.b = "2", T21[T21.c = 3] = "c", (T3 || (T3 = {})).a = "11", (T41 = T4 || (T4 = {})).a = "1", T41.b = "11", T41.c = "12", T41.d = "21", T41.e = "211", (T51 = T5 || (T5 = {})).a = "1", T51.b = "12", T51.c = "123", T51[T51.d = 1] = "d", T51[T51.e = 0] = "e", T51.f = "11", T51.g = "123", T51[T51.h = 1] = "h", (T61 = T6 || (T6 = {}))[T61.a = 1] = "a", T61[T61.b = 2] = "b"; diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/expr/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/expr/mod.rs index 175324c9ac88..3fc880ecea34 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/expr/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/expr/mod.rs @@ -896,8 +896,9 @@ impl SimplifyExpr { ); if (lv.is_unknown() && rv.is_unknown()) - || !left.get_type().casted_to_number_on_add() - || !right.get_type().casted_to_number_on_add() + || op == op!(bin, "+") + && (!left.get_type().casted_to_number_on_add() + || !right.get_type().casted_to_number_on_add()) { return Unknown; } diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs b/crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs index 55a6c7ef91aa..472c4b3506bd 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs @@ -1314,6 +1314,33 @@ fn test_fold_literals_as_numbers() { fold("x/false", "x/0"); // should we add an error check? :) } +#[test] +fn test_fold_arithmetic_with_strings() { + // Left side of expression is a string + fold("'10' - 5", "5"); + fold("'4' / 2", "2"); + fold("'11' % 2", "1"); + fold("'10' ** 2", "100"); + fold("'Infinity' * 2", "Infinity"); + fold("'NaN' * 2", "NaN"); + + // Right side of expression is a string + fold("10 - '5'", "5"); + fold("4 / '2'", "2"); + fold("11 % '2'", "1"); + fold("10 ** '2'", "100"); + fold("2 * 'Infinity'", "Infinity"); + fold("2 * 'NaN'", "NaN"); + + // Both sides are strings + fold("'10' - '5'", "5"); + fold("'4' / '2'", "2"); + fold("'11' % '2'", "1"); + fold("'10' ** '2'", "100"); + fold("'Infinity' * '2'", "Infinity"); + fold("'NaN' * '2'", "NaN"); +} + #[test] fn test_not_fold_back_to_true_false() { fold("!0", "!0");