Skip to content

feat(minifier): minimize switch statements#17523

Open
armano2 wants to merge 40 commits intooxc-project:mainfrom
armano2:feat/minimize-switch
Open

feat(minifier): minimize switch statements#17523
armano2 wants to merge 40 commits intooxc-project:mainfrom
armano2:feat/minimize-switch

Conversation

@armano2
Copy link
Copy Markdown
Contributor

@armano2 armano2 commented Dec 31, 2025

Phase 3: Advanced Optimizations

  • Switch statement optimization

changes:

  • converts 1-case and 2-case switches into more compact if or if/else statements when safe.
  • removes redundant empty case suffixes at the end of a switch.
  • removes empty switches (preserving the discriminant if it has side effects) and redundant trailing break statements.

note:

  • i left couple of todo's for later additions, that could add additional optimizations, i can remove them if needed
  • all packages seem to be affected due to napi last break removal from switch cases

future improvements:

  • we could remove all empty cases if there is no default or when its empty as long as test has no side effects
  • in-lining of switches with constant discriminants
  • merge of identical consequent cases without side effects

fixes #17544

@github-actions github-actions bot added A-minifier Area - Minifier C-enhancement Category - New feature or request labels Dec 31, 2025
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Dec 31, 2025

Merging this PR will not alter performance

✅ 44 untouched benchmarks
⏩ 7 skipped benchmarks1


Comparing armano2:feat/minimize-switch (6f9d0d6) with main (8be4de7)2

Open in CodSpeed

Footnotes

  1. 7 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (538d703) during the generation of this report, so 8be4de7 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@github-actions github-actions bot added A-linter Area - Linter A-parser Area - Parser A-cli Area - CLI A-linter-plugins Area - Linter JS plugins labels Dec 31, 2025
@armano2 armano2 marked this pull request as ready for review December 31, 2025 19:32
@armano2
Copy link
Copy Markdown
Contributor Author

armano2 commented Dec 31, 2025

i'm pretty bad at naming stuff, suggestions are welcome 😄

Copy link
Copy Markdown
Contributor

@camc314 camc314 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me! Thank you!

I'll let the experts (sapphi-red and Boshen have a look as well)

}

// TODO: This is to aggressive, we should allow `break` for last elements in statements
impl<'a> Visit<'a> for FindNestedBreak {
Copy link
Copy Markdown
Contributor Author

@armano2 armano2 Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be made more generic, and used within eg, for (; x; ) break; to check if loop could be completely in-lined,

maybe we could add something like is_statement_terminated or is_terminated to statement nodes, instead of my is_terminated_switch_case and with addition of FindNestedBreak that could be really useful

test("while (x) { if (1) break; z(); }", "for (; x; ) break;");

should i implement it in more generic way?

@armano2
Copy link
Copy Markdown
Contributor Author

armano2 commented Jan 15, 2026

@Boshen i noticed that you started doing some changes in #17994 for switches, and looks like we worked on same thing

how i should proceed with this change?

/// non-empty case or case with side-effect-producing expressions backward to the last case.
/// - All cases in the identified removable suffix are eliminated, except for the last case,
/// which is preserved and its test is removed (if applicable).
fn collapse_empty_switch_cases(stmt: &mut Statement<'a>, ctx: &mut Ctx<'a, '_>) {
Copy link
Copy Markdown
Contributor Author

@armano2 armano2 Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new optimization has been added to main, and this code is partially redundant, tho my code supports more use cases

eg, trailing empty switch cases,

if let Some(last_case) = switch_stmt.cases.last()
&& last_case.test.is_none()
{
let default_idx = switch_stmt.cases.len() - 1;
let mut first_empty_idx = default_idx;
// Iterate backward through preceding cases
while first_empty_idx > 0 {
let case = &switch_stmt.cases[first_empty_idx - 1];
// Only remove empty cases with primitive literal tests
if case.consequent.is_empty()
&& case.test.as_ref().is_some_and(Expression::is_literal)
{
first_empty_idx -= 1;
} else {
break;
}
}
// If we found cases to remove, keep cases [0..first_empty_idx] + [default]
if first_empty_idx < default_idx {
let default_case = switch_stmt.cases.pop().unwrap();
switch_stmt.cases.truncate(first_empty_idx);
switch_stmt.cases.push(default_case);
ctx.state.changed = true;
}
}

@overlookmotel overlookmotel removed A-linter Area - Linter A-linter-plugins Area - Linter JS plugins A-parser Area - Parser labels Jan 20, 2026
@github-actions github-actions bot added A-linter Area - Linter A-parser Area - Parser A-linter-plugins Area - Linter JS plugins labels Mar 16, 2026
@Boshen Boshen self-assigned this Mar 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-cli Area - CLI A-linter Area - Linter A-linter-plugins Area - Linter JS plugins A-minifier Area - Minifier A-parser Area - Parser C-enhancement Category - New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

minifier: switch statement optimization

4 participants