diff --git a/crates/swc/tests/fixture/issues-7xxx/7969/input/.swcrc b/crates/swc/tests/fixture/issues-7xxx/7969/input/.swcrc new file mode 100644 index 000000000000..63a5ce65cc71 --- /dev/null +++ b/crates/swc/tests/fixture/issues-7xxx/7969/input/.swcrc @@ -0,0 +1,72 @@ +{ + "jsc": { + "parser": { + "syntax": "ecmascript", + "jsx": false + }, + "target": "es2015", + "loose": false, + "minify": { + "compress": { + "arguments": false, + "arrows": true, + "booleans": true, + "booleans_as_integers": false, + "collapse_vars": true, + "comparisons": true, + "computed_props": true, + "conditionals": true, + "dead_code": true, + "directives": true, + "drop_console": false, + "drop_debugger": true, + "evaluate": true, + "expression": false, + "hoist_funs": false, + "hoist_props": true, + "hoist_vars": false, + "if_return": true, + "join_vars": true, + "keep_classnames": false, + "keep_fargs": true, + "keep_fnames": false, + "keep_infinity": false, + "loops": true, + "negate_iife": true, + "properties": true, + "reduce_funcs": false, + "reduce_vars": false, + "side_effects": true, + "switches": true, + "typeofs": true, + "unsafe": false, + "unsafe_arrows": false, + "unsafe_comps": false, + "unsafe_Function": false, + "unsafe_math": false, + "unsafe_symbols": false, + "unsafe_methods": false, + "unsafe_proto": false, + "unsafe_regexp": false, + "unsafe_undefined": false, + "unused": true, + "const_to_let": true, + "pristine_globals": true, + "passes": 1 + }, + "mangle": { + "toplevel": false, + "keep_classnames": false, + "keep_fnames": false, + "keep_private_props": false, + "ie8": false, + "safari10": false + } + } + }, + "module": { + "type": "es6" + }, + "minify": true, + "isModule": true +} \ No newline at end of file diff --git a/crates/swc/tests/fixture/issues-7xxx/7969/input/1.js b/crates/swc/tests/fixture/issues-7xxx/7969/input/1.js new file mode 100644 index 000000000000..68f9ed2ced2d --- /dev/null +++ b/crates/swc/tests/fixture/issues-7xxx/7969/input/1.js @@ -0,0 +1,14 @@ +let a = 0; +function f(arr) { + let b = a; + return `${arr.map((child) => { + a = b + "str"; + })}`; +} + +function g(arr) { + return f(arr); +} +globalThis.g = g; +g([1, 2, 3]) +console.log(a); \ No newline at end of file diff --git a/crates/swc/tests/fixture/issues-7xxx/7969/output/1.js b/crates/swc/tests/fixture/issues-7xxx/7969/output/1.js new file mode 100644 index 000000000000..f78235038291 --- /dev/null +++ b/crates/swc/tests/fixture/issues-7xxx/7969/output/1.js @@ -0,0 +1 @@ +let a=0;function g(l){var o;let t;return o=l,t=a,`${o.map(l=>{a=t+"str"})}`}globalThis.g=g,g([1,2,3]),console.log(a); diff --git a/crates/swc/tests/tsc-references/taggedTemplateStringsTypeArgumentInferenceES6.2.minified.js b/crates/swc/tests/tsc-references/taggedTemplateStringsTypeArgumentInferenceES6.2.minified.js index e2984e50e808..68d8549c3681 100644 --- a/crates/swc/tests/tsc-references/taggedTemplateStringsTypeArgumentInferenceES6.2.minified.js +++ b/crates/swc/tests/tsc-references/taggedTemplateStringsTypeArgumentInferenceES6.2.minified.js @@ -1,6 +1,5 @@ //// [taggedTemplateStringsTypeArgumentInferenceES6.ts] // Generic tag with one parameter -var anyVar; // Generic tag with argument of function type whose parameter is not of type parameter type but body/return type uses type parameter function someGenerics3(strs, producer) {} // 2 parameter generic tag with argument 1 of type parameter type and argument 2 of function type whose parameter is of type parameter type @@ -11,14 +10,16 @@ function someGenerics5(strs, n, f) {} function someGenerics6(strs, a, b, c) {} // Generic tag with multiple arguments of function types that each have parameters of different generic type function someGenerics7(strs, a, b, c) {} +someGenerics3`${()=>''}`, someGenerics3`${()=>void 0}`, someGenerics3`${()=>3}`, someGenerics4`${4}${()=>null}`, someGenerics4`${''}${()=>3}`, someGenerics4`${null}${null}`, someGenerics5`${4} ${()=>null}`, someGenerics5`${''}${()=>3}`, someGenerics5`${null}${null}`, someGenerics6`${(n)=>n}${(n)=>n}${(n)=>n}`, someGenerics6`${(n)=>n}${(n)=>n}${(n)=>n}`, someGenerics6`${(n)=>n}${(n)=>n}${(n)=>n}`, someGenerics7`${(n)=>n}${(n)=>n}${(n)=>n}`, someGenerics7`${(n)=>n}${(n)=>n}${(n)=>n}`, someGenerics7`${(n)=>n}${(n)=>n}${(n)=>n}`; +var anyVar, x = // Generic tag with argument of generic function type +(function(strs, n) { + return n; +})`${someGenerics7}`; // Generic tag with multiple parameters of generic type passed arguments with no best common type function someGenerics9(strs, a, b, c) { return null; } -someGenerics3`${()=>''}`, someGenerics3`${()=>void 0}`, someGenerics3`${()=>3}`, someGenerics4`${4}${()=>null}`, someGenerics4`${''}${()=>3}`, someGenerics4`${null}${null}`, someGenerics5`${4} ${()=>null}`, someGenerics5`${''}${()=>3}`, someGenerics5`${null}${null}`, someGenerics6`${(n)=>n}${(n)=>n}${(n)=>n}`, someGenerics6`${(n)=>n}${(n)=>n}${(n)=>n}`, someGenerics6`${(n)=>n}${(n)=>n}${(n)=>n}`, someGenerics7`${(n)=>n}${(n)=>n}${(n)=>n}`, someGenerics7`${(n)=>n}${(n)=>n}${(n)=>n}`, someGenerics7`${(n)=>n}${(n)=>n}${(n)=>n}`, // Generic tag with argument of generic function type -(function(strs, n) { - return n; -})`${someGenerics7}``${null}${null}${null}`, someGenerics9`${''}${0}${[]}`, someGenerics9`${void 0}${{ +x`${null}${null}${null}`, someGenerics9`${''}${0}${[]}`, someGenerics9`${void 0}${{ x: 6, z: new Date() }}${{ diff --git a/crates/swc/tests/tsc-references/taggedTemplateStringsWithManyCallAndMemberExpressionsES6.2.minified.js b/crates/swc/tests/tsc-references/taggedTemplateStringsWithManyCallAndMemberExpressionsES6.2.minified.js index e7d3e5ef6496..6bb58d6ee5c3 100644 --- a/crates/swc/tests/tsc-references/taggedTemplateStringsWithManyCallAndMemberExpressionsES6.2.minified.js +++ b/crates/swc/tests/tsc-references/taggedTemplateStringsWithManyCallAndMemberExpressionsES6.2.minified.js @@ -1,2 +1,3 @@ //// [taggedTemplateStringsWithManyCallAndMemberExpressionsES6.ts] -new new new (void 0)`abc${0}def`.member("hello")(42); +var f; +new new new f`abc${0}def`.member("hello")(42); diff --git a/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs b/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs index aa2d29ec3614..18bc9afd406a 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs @@ -1207,6 +1207,13 @@ impl Optimizer<'_> { Expr::Yield(..) | Expr::Await(..) => false, + Expr::Tpl(t) => t.exprs.iter().all(|e| self.is_skippable_for_seq(a, e)), + + Expr::TaggedTpl(t) => { + self.is_skippable_for_seq(a, &t.tag) + && t.tpl.exprs.iter().all(|e| self.is_skippable_for_seq(a, e)) + } + Expr::Unary(UnaryExpr { op: op!("!") | op!("void") | op!("typeof") | op!(unary, "-") | op!(unary, "+"), arg, @@ -1378,14 +1385,12 @@ impl Optimizer<'_> { exprs.iter().all(|e| self.is_skippable_for_seq(a, e)) } - Expr::TaggedTpl(..) | Expr::New(..) => { + Expr::New(..) => { // TODO(kdy1): We can optimize some known calls. false } - Expr::Tpl(Tpl { exprs, .. }) => exprs.iter().all(|e| self.is_skippable_for_seq(a, e)), - // Expressions without any effects Expr::This(_) | Expr::Fn(_) @@ -1523,7 +1528,9 @@ impl Optimizer<'_> { | Expr::Class(..) | Expr::Lit(..) | Expr::Await(..) - | Expr::Yield(..) => true, + | Expr::Yield(..) + | Expr::Tpl(..) + | Expr::TaggedTpl(..) => true, Expr::Unary(UnaryExpr { op: op!("delete"), .. }) => true, diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/7969/config.json b/crates/swc_ecma_minifier/tests/fixture/issues/7969/config.json new file mode 100644 index 000000000000..e24c2f770eb5 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/7969/config.json @@ -0,0 +1,46 @@ +{ + "arguments": false, + "arrows": true, + "booleans": true, + "booleans_as_integers": false, + "collapse_vars": true, + "comparisons": true, + "computed_props": true, + "conditionals": true, + "dead_code": true, + "directives": true, + "drop_console": false, + "drop_debugger": true, + "evaluate": true, + "expression": false, + "hoist_funs": false, + "hoist_props": true, + "hoist_vars": false, + "if_return": true, + "join_vars": true, + "keep_classnames": false, + "keep_fargs": true, + "keep_fnames": false, + "keep_infinity": false, + "loops": true, + "negate_iife": true, + "properties": true, + "reduce_funcs": false, + "reduce_vars": false, + "side_effects": true, + "switches": true, + "typeofs": true, + "unsafe": false, + "unsafe_arrows": false, + "unsafe_comps": false, + "unsafe_Function": false, + "unsafe_math": false, + "unsafe_symbols": false, + "unsafe_methods": false, + "unsafe_proto": false, + "unsafe_regexp": false, + "unsafe_undefined": false, + "unused": true, + "const_to_let": true, + "pristine_globals": true +} diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/7969/input.js b/crates/swc_ecma_minifier/tests/fixture/issues/7969/input.js new file mode 100644 index 000000000000..68f9ed2ced2d --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/7969/input.js @@ -0,0 +1,14 @@ +let a = 0; +function f(arr) { + let b = a; + return `${arr.map((child) => { + a = b + "str"; + })}`; +} + +function g(arr) { + return f(arr); +} +globalThis.g = g; +g([1, 2, 3]) +console.log(a); \ No newline at end of file diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/7969/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/7969/output.js new file mode 100644 index 000000000000..6f92a394b583 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/7969/output.js @@ -0,0 +1,17 @@ +let a = 0; +function f(arr) { + let b = a; + return `${arr.map((child)=>{ + a = b + "str"; + })}`; +} +function g(arr) { + return f(arr); +} +globalThis.g = g; +g([ + 1, + 2, + 3 +]); +console.log(a); diff --git a/crates/swc_ecma_minifier/tests/fixture/next/wrap-contracts/output.js b/crates/swc_ecma_minifier/tests/fixture/next/wrap-contracts/output.js index ff1347299d35..d7d4ba6cbf1d 100644 --- a/crates/swc_ecma_minifier/tests/fixture/next/wrap-contracts/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/next/wrap-contracts/output.js @@ -19083,8 +19083,8 @@ if (Array.isArray(value1)) { if (0 === value1.length) return '[]'; if (maximumDepth1 < stack1.length + 1) return '"[Array]"'; - stack1.push(value1); - let res1 = `\n${indentation1 += spacer1}`; + stack1.push(value1), indentation1 += spacer1; + let res1 = `\n${indentation1}`; const join1 = `,\n${indentation1}`, maximumValuesToStringify1 = Math.min(value1.length, maximumBreadth1); let i2 = 0; for(; i2 < maximumValuesToStringify1 - 1; i2++){