From 2224729a8fa6a0197625ec371341a2a8e6cc684f Mon Sep 17 00:00:00 2001 From: Levi Date: Sun, 3 Mar 2024 09:02:49 +1300 Subject: [PATCH 1/6] Only check `casted_to_number_on_add` if operator is add --- .../src/simplify/expr/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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..648e1e647083 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/expr/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/expr/mod.rs @@ -895,9 +895,11 @@ impl SimplifyExpr { right.as_pure_number(&self.expr_ctx), ); - if (lv.is_unknown() && rv.is_unknown()) - || !left.get_type().casted_to_number_on_add() + if (lv.is_unknown() && rv.is_unknown()) || op == op!(bin, "+") && + ( + !left.get_type().casted_to_number_on_add() || !right.get_type().casted_to_number_on_add() + ) { return Unknown; } From d313d34910a248b811e4e4fb6d1af4b4a786e820 Mon Sep 17 00:00:00 2001 From: Levi Date: Sun, 3 Mar 2024 09:03:04 +1300 Subject: [PATCH 2/6] Add unit test for arithmetic with string literals --- .../src/simplify/expr/tests.rs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) 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..df791ca243a4 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,27 @@ 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"); + + // Right side of expression is a string + fold("10 - '5'", "5"); + fold("4 / '2'", "2"); + fold("11 % '2'", "1"); + fold("10 ** '2'", "100"); + + // Both sides are strings + fold("'10' - '5'", "5"); + fold("'4' / '2'", "2"); + fold("'11' % '2'", "1"); + fold("'10' ** '2'", "100"); +} + #[test] fn test_not_fold_back_to_true_false() { fold("!0", "!0"); From 0d6042b8428d9aa82a1220f14bfb9dcc12175cf6 Mon Sep 17 00:00:00 2001 From: Levi Date: Sun, 3 Mar 2024 09:12:01 +1300 Subject: [PATCH 3/6] Run cargofmt --- .../src/simplify/expr/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) 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 648e1e647083..3fc880ecea34 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/expr/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/expr/mod.rs @@ -895,11 +895,10 @@ impl SimplifyExpr { right.as_pure_number(&self.expr_ctx), ); - if (lv.is_unknown() && rv.is_unknown()) || op == op!(bin, "+") && - ( - !left.get_type().casted_to_number_on_add() - || !right.get_type().casted_to_number_on_add() - ) + if (lv.is_unknown() && rv.is_unknown()) + || op == op!(bin, "+") + && (!left.get_type().casted_to_number_on_add() + || !right.get_type().casted_to_number_on_add()) { return Unknown; } From c0e080a844082a6d940ebe91d548b1ed0ce68d83 Mon Sep 17 00:00:00 2001 From: levi Date: Sun, 3 Mar 2024 21:44:56 +1300 Subject: [PATCH 4/6] Add `Infinity` to unit test --- .../src/simplify/expr/tests.rs | 3 +++ 1 file changed, 3 insertions(+) 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 df791ca243a4..ec87551abbcf 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs @@ -1321,18 +1321,21 @@ fn test_fold_arithmetic_with_strings() { fold("'4' / 2", "2"); fold("'11' % 2", "1"); fold("'10' ** 2", "100"); + fold("'Infinity' * 2", "Infinity"); // 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"); // Both sides are strings fold("'10' - '5'", "5"); fold("'4' / '2'", "2"); fold("'11' % '2'", "1"); fold("'10' ** '2'", "100"); + fold("'Infinity' * '2'", "Infinity"); } #[test] From 7d6091ad2ee99a068c64cbacd9d9cf7a6deabecb Mon Sep 17 00:00:00 2001 From: levi Date: Sun, 3 Mar 2024 21:47:14 +1300 Subject: [PATCH 5/6] Add `NaN` to unit test --- .../src/simplify/expr/tests.rs | 3 +++ 1 file changed, 3 insertions(+) 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 ec87551abbcf..472c4b3506bd 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs @@ -1322,6 +1322,7 @@ fn test_fold_arithmetic_with_strings() { 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"); @@ -1329,6 +1330,7 @@ fn test_fold_arithmetic_with_strings() { fold("11 % '2'", "1"); fold("10 ** '2'", "100"); fold("2 * 'Infinity'", "Infinity"); + fold("2 * 'NaN'", "NaN"); // Both sides are strings fold("'10' - '5'", "5"); @@ -1336,6 +1338,7 @@ fn test_fold_arithmetic_with_strings() { fold("'11' % '2'", "1"); fold("'10' ** '2'", "100"); fold("'Infinity' * '2'", "Infinity"); + fold("'NaN' * '2'", "NaN"); } #[test] From 45491271fa0a3f26cf2092bbd9072a18c4c48e17 Mon Sep 17 00:00:00 2001 From: levi Date: Mon, 4 Mar 2024 23:32:35 +1300 Subject: [PATCH 6/6] Add updated test files --- .../tsc-references/enumConstantMemberWithString.2.minified.js | 2 +- .../enumConstantMemberWithTemplateLiterals.2.minified.js | 2 +- 2 files changed, 2 insertions(+), 2 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";