Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong compress for consecutive switch statements #9619

Closed
canalun opened this issue Oct 7, 2024 · 2 comments
Closed

Wrong compress for consecutive switch statements #9619

canalun opened this issue Oct 7, 2024 · 2 comments
Labels
Milestone

Comments

@canalun
Copy link
Contributor

canalun commented Oct 7, 2024

Describe the bug

The minifier compresses consecutive switch statements wrongly.

Input code

var a = (() => {
  switch ("production") {
    case "production":
      return "expected";
    default:
      return "unexpected1";
  }

  switch ("production") {
    case "production":
      return "unexpected2";
    default:
      return "unexpected3";
  }
})();

console.log(a);

Config

{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "jsx": false
    },
    "target": "es5",
    "loose": false,
    "minify": {
      "compress": {
        "arguments": false,
        "arrows": false,
        "booleans": false,
        "booleans_as_integers": false,
        "collapse_vars": false,
        "comparisons": false,
        "computed_props": false,
        "conditionals": false,
        "dead_code": true,
        "directives": false,
        "drop_console": false,
        "drop_debugger": false,
        "evaluate": false,
        "expression": false,
        "hoist_funs": false,
        "hoist_props": false,
        "hoist_vars": false,
        "if_return": true,
        "join_vars": false,
        "keep_classnames": false,
        "keep_fargs": false,
        "keep_fnames": false,
        "keep_infinity": false,
        "loops": false,
        "negate_iife": false,
        "properties": false,
        "reduce_funcs": false,
        "reduce_vars": false,
        "side_effects": false,
        "switches": true,
        "typeofs": false,
        "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": false,
        "pristine_globals": false,
        "passes": 1
      },
      "mangle": false
    }
  },
  "module": {
    "type": "es6"
  },
  "minify": false,
  "isModule": true
}

Playground link (or link to the minimal reproduction)

https://play.swc.rs/?version=1.7.28&code=H4sIAAAAAAAAA6WNQQoCMRAE73lFk1NyEdSby%2FqXMBl1IWSWZKKC7N%2BVoCieBK9dRdc5FASMcM5j3ONmgHqZlE5wdi4SG%2Bkk2fpOAAqV8Ql2fQYKaysZlq8zk3K0QweRD6El%2FbZafnnrLi7m3%2B77cfNrevtML975wRiSXCXxKsnRhcdwB02YIAgaAQAA&config=H4sIAAAAAAAAA32VO3LjMAyGe5%2FCozrNFrtFDrBdzsChSVCmVyQ1BOhYk%2FHdF6IkJ3FAdRY%2BQDB%2BPPRxOB67C5ru9fjBP%2Flh1BkhP57ZglMkfWNLByZoNNmP1L1s9IIzcnpAqKb7QjrSuQeqUfh7de%2BGlBA299UWfPRu%2BprQpDBmQPxiYyu%2FrwSIhN%2FjV5bTuwROKQ2g4x5SGpWPBD1kyc2kYdAjgrrqBg8smcckJplpIbBqzGmUHaL15FNku4AtaKtMsrNolMs35DMY8lcQ4zgdx0XkGlvYwqn0fe31M4erHoomKRRutTf8jwV4Th5JuSJqscCWEAttiOydykAlx58yXJKPrbB%2FAKzCoBGjDqJO1cPxaLXhbqiPjseXJoHzrIuFRuhZWeW9k%2BSd5YFMXkyZwRYDs75mBzfEQG9BgXM8NCJ%2B92TONe2TwjSNkJwUw33WYhULUM21XPm8HTv4L9dJ8qCtHkHTuU1xCqckrtUWDnROdseBu0GpjTMfjdvY5iVa4PkAK7oUrOBJ7XlpSVFSQ72eP%2BeD14RfqfohneSbMfK81z7%2BWm33x7EOOvafB2G514fVoQvJlgrXL8Hc9%2BV%2B%2F%2Bk%2BnbZr%2FcjaeXzbIudaDvf%2Fe2YcFlUGAAA%3D

SWC Info output

No response

Expected behavior

The below result is expected.

console.log("expected");

Actual behavior

I got the below code.

console.log("unexpected2");

Version

1.7.28

Additional context

I investigated it and have submitted a PR.
If my approach does not seem too off-track, could you possibly review it? :)

#9620

approach

Based on the debug log in the "investigation" section, I think it's necessary to process consecutive return statements properly in the place where if_return: Merging returns occurs, that is merge_if_returns().

Specifically, I found the below code, code A, is generated in the process, and then code A is converted into code B by merge_if_returns().

// code A

var a = function() {
  return void "production", void "production", "expected";
  return void "production", void "production", "unexpected2";
}();
console.log(a);

merge_if_returns()

// code B

var a = function() {
  return void "production", void "production", "expected", void "production", void "production", "unexpected2";
}();
console.log(a);

The PR makes merge_if_returns() check if it receives consecutive return statements.
If it does, it will do nothing, and dead code elimination works and delete the latter statement.

investigation

---- Input -----
var a = (() => {
  switch ("production") {
    case "production":
      return "expected";
    default:
      return "unexpected1";
  }

  switch ("production") {
    case "production":
      return "unexpected2";
    default:
      return "unexpected3";
  }
})();

console.log(a);

   INFO  Done in 125ns, kind: "perf"
    at crates/swc_timer/src/lib.rs:32
    in inline global defs
    in minify

   INFO  Done in 510.625µs, kind: "perf"
    at crates/swc_timer/src/lib.rs:32
    in precompress
    in minify

   INFO  Done in 1.145833ms, kind: "perf"
    at crates/swc_timer/src/lib.rs:32
    in remove dead code
    in minify

  DEBUG  ===== Start =====
var a = (()=>{
    switch("production"){
        case "production":
            return "expected";
        default:
            return "unexpected1";
    }
    switch("production"){
        case "production":
            return "unexpected2";
        default:
            return "unexpected3";
    }
})();
console.log(a);

    at crates/swc_ecma_minifier/src/compress/mod.rs:179
    in optimize with pass: 1
    in compress ast
    in minify

   INFO  compress: Running expression simplifier (pass = 1)
    at crates/swc_ecma_minifier/src/compress/mod.rs:184
    in optimize with pass: 1
    in compress ast
    in minify

   INFO  compress: expr_simplifier took 124.25µs (pass = 1)
    at crates/swc_ecma_minifier/src/compress/mod.rs:212
    in optimize with pass: 1
    in compress ast
    in minify

   INFO  Done in 410.5µs, kind: "perf"
    at crates/swc_timer/src/lib.rs:32
    in apply pure optimizer
    in optimize with pass: 1
    in compress ast
    in minify

   INFO  Done in 207.542µs, kind: "perf"
    at crates/swc_timer/src/lib.rs:32
    in analyze
    in apply full optimizer
    in optimize with pass: 1
    in compress ast
    in minify

  DEBUG  switches: Removing a constant switch, kind: "change"
    at crates/swc_ecma_minifier/src/compress/optimize/switches.rs:134
    in visit_mut_stmt with start: "switch(\"production\"){\n    case \"production\":\n        return \"expected\";\n    default:\n        return \"unexpected1\";\n}\n"
    in visit_mut_stmt
    in handle_stmt_likes
    in visit_mut_stmts
    in visit_mut_block_stmt
    in visit_mut_arrow_expr
    in visit_mut_call_expr
    in visit_mut_var_declarator
    in visit_mut_var_declarators
    in visit_mut_var_decl
    in visit_mut_decl
    in visit_mut_stmt
    in handle_stmt_likes
    in visit_mut_stmts
    in visit_mut_script
    in apply full optimizer
    in optimize with pass: 1
    in compress ast
    in minify

  DEBUG  switches: Removing a constant switch, kind: "change"
    at crates/swc_ecma_minifier/src/compress/optimize/switches.rs:134
    in visit_mut_stmt with start: "switch(\"production\"){\n    case \"production\":\n        return \"unexpected2\";\n    default:\n        return \"unexpected3\";\n}\n"
    in visit_mut_stmt
    in handle_stmt_likes
    in visit_mut_stmts
    in visit_mut_block_stmt
    in visit_mut_arrow_expr
    in visit_mut_call_expr
    in visit_mut_var_declarator
    in visit_mut_var_declarators
    in visit_mut_var_decl
    in visit_mut_decl
    in visit_mut_stmt
    in handle_stmt_likes
    in visit_mut_stmts
    in visit_mut_script
    in apply full optimizer
    in optimize with pass: 1
    in compress ast
    in minify

  DEBUG  if_return: Merging returns, kind: "change"
    at crates/swc_ecma_minifier/src/compress/optimize/if_return.rs:279
    in visit_mut_arrow_expr
    in visit_mut_call_expr
    in visit_mut_var_declarator
    in visit_mut_var_declarators
    in visit_mut_var_decl
    in visit_mut_decl
    in visit_mut_stmt
    in handle_stmt_likes
    in visit_mut_stmts
    in visit_mut_script
    in apply full optimizer
    in optimize with pass: 1
    in compress ast
    in minify

  DEBUG  if_return: Merging returns, kind: "change"
    at crates/swc_ecma_minifier/src/compress/optimize/if_return.rs:279
    in visit_mut_arrow_expr
    in visit_mut_call_expr
    in visit_mut_var_declarator
    in visit_mut_var_declarators
    in visit_mut_var_decl
    in visit_mut_decl
    in visit_mut_stmt
    in handle_stmt_likes
    in visit_mut_stmts
    in visit_mut_script
    in apply full optimizer
    in optimize with pass: 1
    in compress ast
    in minify

  DEBUG  if_return: Merging returns, kind: "change"
    at crates/swc_ecma_minifier/src/compress/optimize/if_return.rs:279
    in visit_mut_arrow_expr
    in visit_mut_call_expr
    in visit_mut_var_declarator
    in visit_mut_var_declarators
    in visit_mut_var_decl
    in visit_mut_decl
    in visit_mut_stmt
    in handle_stmt_likes
    in visit_mut_stmts
    in visit_mut_script
    in apply full optimizer
    in optimize with pass: 1
    in compress ast
    in minify

   INFO  Done in 1.501458ms, kind: "perf"
    at crates/swc_timer/src/lib.rs:32
    in apply full optimizer
    in optimize with pass: 1
    in compress ast
    in minify

   INFO  compress: dead_branch_remover took 101µs (pass = 1)
    at crates/swc_ecma_minifier/src/compress/mod.rs:302
    in optimize with pass: 1
    in compress ast
    in minify

  DEBUG  ===== Removed dead branches =====
var a#2 = ()=>{
    return void "production", void "production", "expected", void "production", void "production", "unexpected2";
}();
console#1.log(a#2);

==== ===== ===== ===== ======
var a#2 = ()=>{
    return "expected", "unexpected2";
}();
console#1.log(a#2);

    at crates/swc_ecma_minifier/src/compress/mod.rs:314
    in optimize with pass: 1
    in compress ast
    in minify

   INFO  Done in 2.994583ms, kind: "perf"
    at crates/swc_timer/src/lib.rs:32
    in optimize with pass: 1
    in compress ast
    in minify

  DEBUG  ===== Done =====
var a#2 = ()=>{
    return "expected", "unexpected2";
}();
console#1.log(a#2);

    at crates/swc_ecma_minifier/src/compress/mod.rs:146
    in optimize with pass: 2
    in compress ast
    in minify

   INFO  Done in 19.792µs, kind: "perf"
    at crates/swc_timer/src/lib.rs:32
    in optimize with pass: 2
    in compress ast
    in minify

   INFO  Done in 3.055542ms, kind: "perf"
    at crates/swc_timer/src/lib.rs:32
    in compress ast
    in minify

  DEBUG  arrows: Optimizing the body of an arrow, kind: "change"
    at crates/swc_ecma_minifier/src/compress/pure/arrows.rs:52
    in postcompress
    in minify

   INFO  Done in 51.542µs, kind: "perf"
    at crates/swc_timer/src/lib.rs:32
    in postcompress
    in minify

   INFO  Done in 5.809292ms, kind: "perf"
    at crates/swc_timer/src/lib.rs:32
    in minify

   INFO  optimize(/Users/XXXXX/swc/crates/swc_ecma_minifier/tests/fixture/issues/XXXXX/input.js) took 5.907625ms
    at crates/swc_ecma_minifier/tests/compress.rs:254

  DEBUG  Renaming `a#2` to `a`
    at crates/swc_ecma_transforms_base/src/rename/analyzer/scope.rs:161

   INFO  process(/Users/XXXXX/swc/crates/swc_ecma_minifier/tests/fixture/issues/XXXXX/input.js) took 8.09675ms
    at crates/swc_ecma_minifier/tests/compress.rs:267

---- Output -----
var a = (()=>"unexpected2")();
console.log(a);
@canalun
Copy link
Contributor Author

canalun commented Oct 7, 2024

I submitted the PR and added the link to it in the above description :)

@kdy1 kdy1 closed this as completed in 8263da1 Oct 7, 2024
@kdy1 kdy1 added this to the Planned milestone Oct 7, 2024
@kdy1 kdy1 modified the milestones: Planned, v1.7.31 Oct 8, 2024
@swc-bot
Copy link
Collaborator

swc-bot commented Nov 7, 2024

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@swc-project swc-project locked as resolved and limited conversation to collaborators Nov 7, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Development

No branches or pull requests

3 participants