mirror of
https://github.com/aphrody-labs/oxc.git
synced 2026-10-14 22:29:17 +00:00
feat(minifier): enable termination statement optimization for do while (#24921)
- allow removing trailing unlabeled `continue;` in `do...while` block bodies (same as other loop block bodies). - allow removing trailing unlabeled `break;` in `do...while` block bodies **only** when the loop test is side-effect-free and statically `false`. - enable and update `do...while` exit-point tests. #### changes in stack 1. https://github.com/oxc-project/oxc/pull/24920 2. https://github.com/oxc-project/oxc/pull/24921 < This PR
This commit is contained in:
1 parent
e6e584b9be
commit
73fc747699
2 files changed
+38
-15
No files matched your search
@@ -5,7 +5,7 @@ use oxc_allocator::{ArenaBox, ArenaVec, TakeIn};
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_ast_visit::{VisitJs, walk_js};
|
||||
use oxc_ecmascript::{
|
||||
constant_evaluation::{DetermineValueType, IsLiteralValue, ValueType},
|
||||
constant_evaluation::{ConstantEvaluation, DetermineValueType, IsLiteralValue, ValueType},
|
||||
side_effects::MayHaveSideEffects,
|
||||
};
|
||||
use oxc_semantic::ScopeFlags;
|
||||
@@ -2066,7 +2066,7 @@ impl<'a> PeepholeOptimizations {
|
||||
/// - Bare `return` statements that terminate a function body
|
||||
fn can_remove_termination_statement(stmt: &Statement<'a>, ctx: &TraverseCtx<'a>) -> bool {
|
||||
match stmt {
|
||||
// unlabeled `continue;` that terminates a `for`, `for...in`, `for...of`, or `while` body.
|
||||
// unlabeled `continue;` that terminates a `for`, `for...in`, `for...of`, `while`, `do...while` body.
|
||||
Statement::ContinueStatement(stmt) if stmt.label.is_none() => {
|
||||
matches!(
|
||||
ctx.ancestors().nth(1),
|
||||
@@ -2075,9 +2075,19 @@ impl<'a> PeepholeOptimizations {
|
||||
| Ancestor::ForInStatementBody(_)
|
||||
| Ancestor::ForOfStatementBody(_)
|
||||
| Ancestor::WhileStatementBody(_)
|
||||
| Ancestor::DoWhileStatementBody(_)
|
||||
)
|
||||
)
|
||||
}
|
||||
// unlabeled `break;` that terminates a `do...while` body if test is false.
|
||||
Statement::BreakStatement(stmt) if stmt.label.is_none() => {
|
||||
match ctx.ancestors().nth(1) {
|
||||
Some(Ancestor::DoWhileStatementBody(do_while)) => {
|
||||
do_while.test().get_side_free_boolean_value(ctx) == Some(false)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
// bare `return;` in function-body scope.
|
||||
Statement::ReturnStatement(stmt) if stmt.argument.is_none() => {
|
||||
ctx.parent().is_function_body()
|
||||
|
||||
@@ -144,40 +144,53 @@ fn test_while_continue_optimization() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "TODO: Do-while continue optimization not yet implemented"]
|
||||
fn test_do_continue_optimization() {
|
||||
test("do{if(x)continue; x=3; continue; }while(true)", "do x||(x=3);while(!0)");
|
||||
test("do{if(x)continue; x=3; continue; }while(true)", "do x||=3;while(!0);");
|
||||
test("do{a();continue;b()}while(true)", "do a();while(!0)");
|
||||
test("do{if(true){a();continue;}else;b();}while(true)", "do a();while(!0)");
|
||||
test("do{if(false){a();continue;}else;b();continue;}while(true)", "do b();while(!0)");
|
||||
test("do{if(a()){b();continue;}else;c();}while(true)", "do a()?b():c();while(!0)");
|
||||
test("do{if(a()){b();}else{c();continue;}}while(true)", "do a()?b():c();while(!0)");
|
||||
test("do{if(a()){b();continue;}else;}while(true)", "do a()&&b();while(!0)");
|
||||
test(
|
||||
"do{if(a()){b();continue;}else;c();}while(true)",
|
||||
"do{if(a()){b();continue}c()}while(!0);",
|
||||
); // do a()?b():c();while(!0)
|
||||
test(
|
||||
"do{if(a()){b();}else{c();continue;}}while(true)",
|
||||
"do if(a())b();else{c();continue}while(!0);",
|
||||
); // do a()?b():c();while(!0)
|
||||
test("do{if(a()){b();continue;}else;}while(true)", "do if(a()){b();continue}while(!0);"); // do a()&&b();while(!0)
|
||||
test("do{if(a()){continue;}else{continue;} continue;}while(true)", "do a();while(!0)");
|
||||
test("do{if(a()){continue;}else{continue;} b();}while(true)", "do a();while(!0)");
|
||||
|
||||
test("do{while(a())continue;}while(true)", "do for(;a(););while(!0)");
|
||||
test("do{for(x in a())continue}while(true)", "do for(x in a());while(!0)");
|
||||
test("do{while(a())continue;}while(true)", "do for(;a();)continue;while(!0);"); // do for(;a(););while(!0)
|
||||
test("do{for(x in a())continue}while(true)", "do for(x in a())continue;while(!0);"); // do for(x in a());while(!0)
|
||||
|
||||
test("do{while(a())break;}while(true)", "do for(;a();)break;while(!0)");
|
||||
test("do for(x in a())break;while(true)", "do for(x in a())break;while(!0)");
|
||||
|
||||
test("do{try{continue;}catch(e){continue;}}while(true)", "do;while(!0)");
|
||||
test(
|
||||
"do{try{continue;}catch(e){continue;}}while(true)",
|
||||
"do try{continue}catch{continue}while(!0);",
|
||||
); // do;while(!0)
|
||||
test(
|
||||
"do{try{if(a()){continue;}else{continue;} continue;}catch(e){}}while(true)",
|
||||
"do try{a()}catch{}while(!0);",
|
||||
);
|
||||
"do try{if(a())continue;continue}catch{}while(!0);",
|
||||
); // do try{a()}catch{}while(!0);
|
||||
|
||||
test("do{g:continue}while(true)", "do;while(!0)");
|
||||
test("do{g:continue}while(true)", "do;while(!0);");
|
||||
// This case could be improved.
|
||||
test("do{g:if(a()){continue;}else{continue;} continue;}while(true)", "do g:a();while(!0)");
|
||||
test("do{g:if(a()){continue;}else{continue;} continue;}while(true)", "do g:a();while(!0);");
|
||||
|
||||
test("do { foo(); continue; } while(false)", "do foo();while(!1)");
|
||||
test("do { foo(); break; } while(false)", "do foo();while(!1)");
|
||||
|
||||
test("do{break}while(fn());", "do break; while(fn());");
|
||||
test("do{break}while(true);", "do break; while(!0);"); // do while(!1);
|
||||
test("do{break}while(!new Date());", "do;while(!1);");
|
||||
|
||||
test_same("do { foo(); switch (x) { case 1: break; default: f()}; } while(false)");
|
||||
test(
|
||||
"do { foo(); switch (x) { case 1: break; default: f()} } while(false)",
|
||||
"do switch (foo(),x) { case 1: break; default: f() } while(!1);",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user