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);
Describe the bug
The minifier compresses consecutive switch statements wrongly.
Input code
Config
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.
Actual behavior
I got the below code.
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? :)
https://github.com/swc-project/swc/pull/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 ismerge_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()
.↓
merge_if_returns()
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