Repository: swc-project/swc (language: rust)

Issue:
minifier: Leaving `break` in labeled statements inside of switch statement can result in an invalid program
### Describe the bug

The minifier currently does not remove break statements inside labeled statement after removing `switch` statement.  

When a `break` statement followed by an additional statement(e.g., `console.log(1)`), inside a labeled statement appears within the execution path leading into a `switch` statement, the minifier does not remove the `break` statement.

This can lead to syntax errors in case where the `break` statement remains without a valid enclosing loop or `switch` statement, resulting in an illegal break usage.

### Input code

```typescript
switch (0) {
    default:
        x : break;
        console.log(1);
}
```

### Config

```json
{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "jsx": false
    },
    "target": "es2022",
    "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
      }
      
      
    }
  },
  "module": {
    "type": "es6"
  },
  "minify": false,
  "isModule": false
}
```

### Playground link (or link to the minimal reproduction)

https://play.swc.rs/?version=1.10.9&code=H4sIAAAAAAAAAysuzyxJzlDQMNBUqOZSAIKU1LTE0pwSKzAHBCoUrBSSilITs63hQsn5ecX5Oal6OfnpGoaa1ly1AJr6ADtGAAAA&config=H4sIAAAAAAAAA32UwZLaMAyG730KJuceOhx66AP0ts%2FgMbYczDpWxpJZMju8exUnsHRROAX06ZdsSdbnj92uO5Hr%2Fuw%2B5af8GW0hKPf%2FYqEps72IpQM3WHIljtz9vNETzSjYRNBM14V0bEsP3FS0%2F7Xfr4ouIRLcFKttiDmG6TGnw2EsQPRgE6uErANkpv%2F1Kyv4MQMu9dF%2BQExg8wtiLJmYGXooWmCHKdmRwJxtUaLMJ7UlEmopZlgZvBkLjirPPnLELDmfqQfrjUMPCooFHMczaDLJJbJMcj3lPg17ONS%2Bb33%2BpoazTdWykhMurSVyWiXqESOxCTVrJVzgRg0WuBb3uzIGU4Bryc%2B6E8a80ZN3AKlAskTZDqDFbR5B5mlLHV4qYw4ysjwpXOZbu2WGXopqYgxKZefKQOGodbOArw7myjrtOCveKB9FDwZCkFlRQtNHZHfUkvI0AgYFSH9t0KZqAeb%2BCjf4%2FCBe4L9yS9YHbPUYLB%2B3KU3DAdOLBAPwEf0LB2kF4zYusiUu4zav2YOMBnjVpVIDz0tAHgCjSW1fPs2GPA%2BJaPqEh681sTpc1%2B%2FjZ7a1LdwN6GvbAetun9u6bOTf3ZfTbfnez9tFerspl8V%2B%2FQdL7qcXKAYAAA%3D%3D

### SWC Info output

_No response_

### Expected behavior

There should be nothing.

### Actual behavior

```javascript
break;
```

### Version

1.10.9

### Additional context

_No response_


Discussion / hints:

Fix patch:
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/switches.rs b/crates/swc_ecma_minifier/src/compress/optimize/switches.rs
index ca47bc3044c1..8ca36657745e 100644
--- a/crates/swc_ecma_minifier/src/compress/optimize/switches.rs
+++ b/crates/swc_ecma_minifier/src/compress/optimize/switches.rs
@@ -560,6 +560,12 @@ fn remove_last_break(stmt: &mut Vec<Stmt>) -> bool {
 }
 
 fn contains_nested_break(case: &SwitchCase) -> bool {
+    // wait for DCE to work
+    let terminator = case.cons.iter().rposition(|s| s.terminates());
+    if terminator.is_some_and(|t| t != case.cons.len() - 1) {
+        return true;
+    }
+
     let mut v = BreakFinder {
         top_level: true,
         nested_unlabelled_break: false,


Test patch:
diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/9922/1/input.js b/crates/swc_ecma_minifier/tests/fixture/issues/9922/1/input.js
new file mode 100644
index 000000000000..aca1f2de81d8
--- /dev/null
+++ b/crates/swc_ecma_minifier/tests/fixture/issues/9922/1/input.js
@@ -0,0 +1,5 @@
+switch (0) {
+    default:
+        x: break;
+        console.log(1);
+}
diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/9922/1/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/9922/1/output.js
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/9922/2/input.js b/crates/swc_ecma_minifier/tests/fixture/issues/9922/2/input.js
new file mode 100644
index 000000000000..70f20f967057
--- /dev/null
+++ b/crates/swc_ecma_minifier/tests/fixture/issues/9922/2/input.js
@@ -0,0 +1,8 @@
+switch (g()) {
+    case 1:
+        y: break;
+        console.log(2);
+    default:
+        x: break;
+        console.log(1);
+}
diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/9922/2/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/9922/2/output.js
new file mode 100644
index 000000000000..1844613a61c5
--- /dev/null
+++ b/crates/swc_ecma_minifier/tests/fixture/issues/9922/2/output.js
@@ -0,0 +1,1 @@
+g();