From b37dafbd2789ee8e5194ef2593c460f056c2b70f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Fri, 25 Mar 2022 21:08:14 +0900 Subject: [PATCH] feat(es/minifier): Implement rules for optimizing loops (#4157) --- crates/swc/Cargo.toml | 2 +- ...ileContinueStatements_es2015.2.minified.js | 8 +- ...oWhileContinueStatements_es5.2.minified.js | 8 +- ...forContinueStatements_es2015.2.minified.js | 8 +- .../forContinueStatements_es5.2.minified.js | 8 +- ...rInContinueStatements_es2015.2.minified.js | 8 +- .../forInContinueStatements_es5.2.minified.js | 8 +- .../parser_breakTarget1_es2015.2.minified.js | 1 - .../parser_breakTarget1_es5.2.minified.js | 1 - ...InIterationStatement1_es2015.2.minified.js | 2 +- ...nueInIterationStatement1_es5.2.minified.js | 2 +- ...InIterationStatement2_es2015.2.minified.js | 2 +- ...nueInIterationStatement2_es5.2.minified.js | 2 +- ...InIterationStatement3_es2015.2.minified.js | 2 +- ...nueInIterationStatement3_es5.2.minified.js | 2 +- ...InIterationStatement4_es2015.2.minified.js | 2 +- ...nueInIterationStatement4_es5.2.minified.js | 2 +- .../parser_continueLabel_es2015.2.minified.js | 2 +- .../parser_continueLabel_es5.2.minified.js | 2 +- ...arser_continueTarget2_es2015.2.minified.js | 2 +- .../parser_continueTarget2_es5.2.minified.js | 2 +- ...arser_continueTarget4_es2015.2.minified.js | 2 +- .../parser_continueTarget4_es5.2.minified.js | 2 +- ...ileContinueStatements_es2015.2.minified.js | 12 +- .../whileContinueStatements_es5.2.minified.js | 12 +- crates/swc/tests/tsc.rs | 34 ++- .../src/compress/pure/dead_code.rs | 221 +++++++++++++++++- .../src/compress/pure/mod.rs | 6 + crates/swc_ecma_minifier/tests/TODO.txt | 5 - crates/swc_ecma_minifier/tests/golden.txt | 5 + scripts/update-all.sh | 3 - 31 files changed, 307 insertions(+), 71 deletions(-) diff --git a/crates/swc/Cargo.toml b/crates/swc/Cargo.toml index 7291de2de49..8c97886133e 100644 --- a/crates/swc/Cargo.toml +++ b/crates/swc/Cargo.toml @@ -96,7 +96,7 @@ optional = true version = "2.0.0" [dev-dependencies] -rayon = "1" +rayon = "1.5.1" swc_ecma_lints = { version = "0.28.0", path = "../swc_ecma_lints", features = [ "non_critical_lints", ] } diff --git a/crates/swc/tests/tsc-references/doWhileContinueStatements_es2015.2.minified.js b/crates/swc/tests/tsc-references/doWhileContinueStatements_es2015.2.minified.js index 466e2334125..8b6e3979ab0 100644 --- a/crates/swc/tests/tsc-references/doWhileContinueStatements_es2015.2.minified.js +++ b/crates/swc/tests/tsc-references/doWhileContinueStatements_es2015.2.minified.js @@ -1,7 +1,7 @@ -for(;;)continue; -ONE: for(;;)continue ONE; -TWO: THREE: for(;;)continue THREE; +for(;;); +for(;;); +TWO: for(;;); FOUR: for(;;)FIVE: for(;;)continue FOUR; for(;;)SIX: for(;;)continue SIX; SEVEN: for(;;)for(;;)for(;;)continue SEVEN; -EIGHT: for(;;)continue EIGHT; +for(;;); diff --git a/crates/swc/tests/tsc-references/doWhileContinueStatements_es5.2.minified.js b/crates/swc/tests/tsc-references/doWhileContinueStatements_es5.2.minified.js index 466e2334125..8b6e3979ab0 100644 --- a/crates/swc/tests/tsc-references/doWhileContinueStatements_es5.2.minified.js +++ b/crates/swc/tests/tsc-references/doWhileContinueStatements_es5.2.minified.js @@ -1,7 +1,7 @@ -for(;;)continue; -ONE: for(;;)continue ONE; -TWO: THREE: for(;;)continue THREE; +for(;;); +for(;;); +TWO: for(;;); FOUR: for(;;)FIVE: for(;;)continue FOUR; for(;;)SIX: for(;;)continue SIX; SEVEN: for(;;)for(;;)for(;;)continue SEVEN; -EIGHT: for(;;)continue EIGHT; +for(;;); diff --git a/crates/swc/tests/tsc-references/forContinueStatements_es2015.2.minified.js b/crates/swc/tests/tsc-references/forContinueStatements_es2015.2.minified.js index 466e2334125..8b6e3979ab0 100644 --- a/crates/swc/tests/tsc-references/forContinueStatements_es2015.2.minified.js +++ b/crates/swc/tests/tsc-references/forContinueStatements_es2015.2.minified.js @@ -1,7 +1,7 @@ -for(;;)continue; -ONE: for(;;)continue ONE; -TWO: THREE: for(;;)continue THREE; +for(;;); +for(;;); +TWO: for(;;); FOUR: for(;;)FIVE: for(;;)continue FOUR; for(;;)SIX: for(;;)continue SIX; SEVEN: for(;;)for(;;)for(;;)continue SEVEN; -EIGHT: for(;;)continue EIGHT; +for(;;); diff --git a/crates/swc/tests/tsc-references/forContinueStatements_es5.2.minified.js b/crates/swc/tests/tsc-references/forContinueStatements_es5.2.minified.js index 466e2334125..8b6e3979ab0 100644 --- a/crates/swc/tests/tsc-references/forContinueStatements_es5.2.minified.js +++ b/crates/swc/tests/tsc-references/forContinueStatements_es5.2.minified.js @@ -1,7 +1,7 @@ -for(;;)continue; -ONE: for(;;)continue ONE; -TWO: THREE: for(;;)continue THREE; +for(;;); +for(;;); +TWO: for(;;); FOUR: for(;;)FIVE: for(;;)continue FOUR; for(;;)SIX: for(;;)continue SIX; SEVEN: for(;;)for(;;)for(;;)continue SEVEN; -EIGHT: for(;;)continue EIGHT; +for(;;); diff --git a/crates/swc/tests/tsc-references/forInContinueStatements_es2015.2.minified.js b/crates/swc/tests/tsc-references/forInContinueStatements_es2015.2.minified.js index ae0df3f32d1..d74d201cf04 100644 --- a/crates/swc/tests/tsc-references/forInContinueStatements_es2015.2.minified.js +++ b/crates/swc/tests/tsc-references/forInContinueStatements_es2015.2.minified.js @@ -1,7 +1,7 @@ -for(var x in {})continue; -ONE: for(var x in {})continue ONE; -TWO: THREE: for(var x in {})continue THREE; +for(var x in {}); +for(var x in {}); +TWO: for(var x in {}); FOUR: for(var x in {})FIVE: for(var x in {})continue FOUR; for(var x in {})SIX: for(var x in {})continue SIX; SEVEN: for(var x in {})for(var x in {})for(var x in {})continue SEVEN; -EIGHT: for(var x in {})continue EIGHT; +for(var x in {}); diff --git a/crates/swc/tests/tsc-references/forInContinueStatements_es5.2.minified.js b/crates/swc/tests/tsc-references/forInContinueStatements_es5.2.minified.js index ae0df3f32d1..d74d201cf04 100644 --- a/crates/swc/tests/tsc-references/forInContinueStatements_es5.2.minified.js +++ b/crates/swc/tests/tsc-references/forInContinueStatements_es5.2.minified.js @@ -1,7 +1,7 @@ -for(var x in {})continue; -ONE: for(var x in {})continue ONE; -TWO: THREE: for(var x in {})continue THREE; +for(var x in {}); +for(var x in {}); +TWO: for(var x in {}); FOUR: for(var x in {})FIVE: for(var x in {})continue FOUR; for(var x in {})SIX: for(var x in {})continue SIX; SEVEN: for(var x in {})for(var x in {})for(var x in {})continue SEVEN; -EIGHT: for(var x in {})continue EIGHT; +for(var x in {}); diff --git a/crates/swc/tests/tsc-references/parser_breakTarget1_es2015.2.minified.js b/crates/swc/tests/tsc-references/parser_breakTarget1_es2015.2.minified.js index 2ce5a040785..e69de29bb2d 100644 --- a/crates/swc/tests/tsc-references/parser_breakTarget1_es2015.2.minified.js +++ b/crates/swc/tests/tsc-references/parser_breakTarget1_es2015.2.minified.js @@ -1 +0,0 @@ -target: break target; diff --git a/crates/swc/tests/tsc-references/parser_breakTarget1_es5.2.minified.js b/crates/swc/tests/tsc-references/parser_breakTarget1_es5.2.minified.js index 2ce5a040785..e69de29bb2d 100644 --- a/crates/swc/tests/tsc-references/parser_breakTarget1_es5.2.minified.js +++ b/crates/swc/tests/tsc-references/parser_breakTarget1_es5.2.minified.js @@ -1 +0,0 @@ -target: break target; diff --git a/crates/swc/tests/tsc-references/parser_continueInIterationStatement1_es2015.2.minified.js b/crates/swc/tests/tsc-references/parser_continueInIterationStatement1_es2015.2.minified.js index 49bf1930798..4ab96f09617 100644 --- a/crates/swc/tests/tsc-references/parser_continueInIterationStatement1_es2015.2.minified.js +++ b/crates/swc/tests/tsc-references/parser_continueInIterationStatement1_es2015.2.minified.js @@ -1 +1 @@ -for(;;)continue; +for(;;); diff --git a/crates/swc/tests/tsc-references/parser_continueInIterationStatement1_es5.2.minified.js b/crates/swc/tests/tsc-references/parser_continueInIterationStatement1_es5.2.minified.js index 49bf1930798..4ab96f09617 100644 --- a/crates/swc/tests/tsc-references/parser_continueInIterationStatement1_es5.2.minified.js +++ b/crates/swc/tests/tsc-references/parser_continueInIterationStatement1_es5.2.minified.js @@ -1 +1 @@ -for(;;)continue; +for(;;); diff --git a/crates/swc/tests/tsc-references/parser_continueInIterationStatement2_es2015.2.minified.js b/crates/swc/tests/tsc-references/parser_continueInIterationStatement2_es2015.2.minified.js index 49bf1930798..4ab96f09617 100644 --- a/crates/swc/tests/tsc-references/parser_continueInIterationStatement2_es2015.2.minified.js +++ b/crates/swc/tests/tsc-references/parser_continueInIterationStatement2_es2015.2.minified.js @@ -1 +1 @@ -for(;;)continue; +for(;;); diff --git a/crates/swc/tests/tsc-references/parser_continueInIterationStatement2_es5.2.minified.js b/crates/swc/tests/tsc-references/parser_continueInIterationStatement2_es5.2.minified.js index 49bf1930798..4ab96f09617 100644 --- a/crates/swc/tests/tsc-references/parser_continueInIterationStatement2_es5.2.minified.js +++ b/crates/swc/tests/tsc-references/parser_continueInIterationStatement2_es5.2.minified.js @@ -1 +1 @@ -for(;;)continue; +for(;;); diff --git a/crates/swc/tests/tsc-references/parser_continueInIterationStatement3_es2015.2.minified.js b/crates/swc/tests/tsc-references/parser_continueInIterationStatement3_es2015.2.minified.js index 49bf1930798..4ab96f09617 100644 --- a/crates/swc/tests/tsc-references/parser_continueInIterationStatement3_es2015.2.minified.js +++ b/crates/swc/tests/tsc-references/parser_continueInIterationStatement3_es2015.2.minified.js @@ -1 +1 @@ -for(;;)continue; +for(;;); diff --git a/crates/swc/tests/tsc-references/parser_continueInIterationStatement3_es5.2.minified.js b/crates/swc/tests/tsc-references/parser_continueInIterationStatement3_es5.2.minified.js index 49bf1930798..4ab96f09617 100644 --- a/crates/swc/tests/tsc-references/parser_continueInIterationStatement3_es5.2.minified.js +++ b/crates/swc/tests/tsc-references/parser_continueInIterationStatement3_es5.2.minified.js @@ -1 +1 @@ -for(;;)continue; +for(;;); diff --git a/crates/swc/tests/tsc-references/parser_continueInIterationStatement4_es2015.2.minified.js b/crates/swc/tests/tsc-references/parser_continueInIterationStatement4_es2015.2.minified.js index b4e51dcdcf4..5500d6dbcff 100644 --- a/crates/swc/tests/tsc-references/parser_continueInIterationStatement4_es2015.2.minified.js +++ b/crates/swc/tests/tsc-references/parser_continueInIterationStatement4_es2015.2.minified.js @@ -1 +1 @@ -for(var i in something)continue; +for(var i in something); diff --git a/crates/swc/tests/tsc-references/parser_continueInIterationStatement4_es5.2.minified.js b/crates/swc/tests/tsc-references/parser_continueInIterationStatement4_es5.2.minified.js index b4e51dcdcf4..5500d6dbcff 100644 --- a/crates/swc/tests/tsc-references/parser_continueInIterationStatement4_es5.2.minified.js +++ b/crates/swc/tests/tsc-references/parser_continueInIterationStatement4_es5.2.minified.js @@ -1 +1 @@ -for(var i in something)continue; +for(var i in something); diff --git a/crates/swc/tests/tsc-references/parser_continueLabel_es2015.2.minified.js b/crates/swc/tests/tsc-references/parser_continueLabel_es2015.2.minified.js index d1ad522ed5d..22e40282b27 100644 --- a/crates/swc/tests/tsc-references/parser_continueLabel_es2015.2.minified.js +++ b/crates/swc/tests/tsc-references/parser_continueLabel_es2015.2.minified.js @@ -1 +1 @@ -label1: for(var i = 0; i < 1; i++)continue label1; +for(var i = 0; i < 1; i++); diff --git a/crates/swc/tests/tsc-references/parser_continueLabel_es5.2.minified.js b/crates/swc/tests/tsc-references/parser_continueLabel_es5.2.minified.js index d1ad522ed5d..22e40282b27 100644 --- a/crates/swc/tests/tsc-references/parser_continueLabel_es5.2.minified.js +++ b/crates/swc/tests/tsc-references/parser_continueLabel_es5.2.minified.js @@ -1 +1 @@ -label1: for(var i = 0; i < 1; i++)continue label1; +for(var i = 0; i < 1; i++); diff --git a/crates/swc/tests/tsc-references/parser_continueTarget2_es2015.2.minified.js b/crates/swc/tests/tsc-references/parser_continueTarget2_es2015.2.minified.js index ab003715209..4ab96f09617 100644 --- a/crates/swc/tests/tsc-references/parser_continueTarget2_es2015.2.minified.js +++ b/crates/swc/tests/tsc-references/parser_continueTarget2_es2015.2.minified.js @@ -1 +1 @@ -target: for(;;)continue target; +for(;;); diff --git a/crates/swc/tests/tsc-references/parser_continueTarget2_es5.2.minified.js b/crates/swc/tests/tsc-references/parser_continueTarget2_es5.2.minified.js index ab003715209..4ab96f09617 100644 --- a/crates/swc/tests/tsc-references/parser_continueTarget2_es5.2.minified.js +++ b/crates/swc/tests/tsc-references/parser_continueTarget2_es5.2.minified.js @@ -1 +1 @@ -target: for(;;)continue target; +for(;;); diff --git a/crates/swc/tests/tsc-references/parser_continueTarget4_es2015.2.minified.js b/crates/swc/tests/tsc-references/parser_continueTarget4_es2015.2.minified.js index f037671d992..ebf591d8a04 100644 --- a/crates/swc/tests/tsc-references/parser_continueTarget4_es2015.2.minified.js +++ b/crates/swc/tests/tsc-references/parser_continueTarget4_es2015.2.minified.js @@ -1 +1 @@ -target1: target2: for(;;)continue target2; +target1: for(;;); diff --git a/crates/swc/tests/tsc-references/parser_continueTarget4_es5.2.minified.js b/crates/swc/tests/tsc-references/parser_continueTarget4_es5.2.minified.js index f037671d992..ebf591d8a04 100644 --- a/crates/swc/tests/tsc-references/parser_continueTarget4_es5.2.minified.js +++ b/crates/swc/tests/tsc-references/parser_continueTarget4_es5.2.minified.js @@ -1 +1 @@ -target1: target2: for(;;)continue target2; +target1: for(;;); diff --git a/crates/swc/tests/tsc-references/whileContinueStatements_es2015.2.minified.js b/crates/swc/tests/tsc-references/whileContinueStatements_es2015.2.minified.js index e1dbc11b5dc..40143e3601c 100644 --- a/crates/swc/tests/tsc-references/whileContinueStatements_es2015.2.minified.js +++ b/crates/swc/tests/tsc-references/whileContinueStatements_es2015.2.minified.js @@ -1,9 +1,9 @@ -for(;;)continue; -for(;;)continue; -ONE: for(;;)continue ONE; -TWO: THREE: for(;;)continue THREE; +for(;;); +for(;;); +for(;;); +TWO: for(;;); FOUR: for(;;)FIVE: for(;;)continue FOUR; for(;;)SIX: for(;;)continue SIX; SEVEN: for(;;)for(;;)for(;;)continue SEVEN; -EIGHT: for(;;)continue EIGHT; -NINE: for(;;)continue NINE; +for(;;); +for(;;); diff --git a/crates/swc/tests/tsc-references/whileContinueStatements_es5.2.minified.js b/crates/swc/tests/tsc-references/whileContinueStatements_es5.2.minified.js index e1dbc11b5dc..40143e3601c 100644 --- a/crates/swc/tests/tsc-references/whileContinueStatements_es5.2.minified.js +++ b/crates/swc/tests/tsc-references/whileContinueStatements_es5.2.minified.js @@ -1,9 +1,9 @@ -for(;;)continue; -for(;;)continue; -ONE: for(;;)continue ONE; -TWO: THREE: for(;;)continue THREE; +for(;;); +for(;;); +for(;;); +TWO: for(;;); FOUR: for(;;)FIVE: for(;;)continue FOUR; for(;;)SIX: for(;;)continue SIX; SEVEN: for(;;)for(;;)for(;;)continue SEVEN; -EIGHT: for(;;)continue EIGHT; -NINE: for(;;)continue NINE; +for(;;); +for(;;); diff --git a/crates/swc/tests/tsc.rs b/crates/swc/tests/tsc.rs index 857a9994ccf..da9c73dbefb 100644 --- a/crates/swc/tests/tsc.rs +++ b/crates/swc/tests/tsc.rs @@ -1,8 +1,10 @@ use std::{ fs::create_dir_all, + panic::{catch_unwind, resume_unwind, AssertUnwindSafe}, path::{Path, PathBuf}, }; +use rayon::prelude::*; use serde::de::DeserializeOwned; use swc::{ config::{Config, IsModule, JscConfig, Options, SourceMapsConfig}, @@ -38,19 +40,33 @@ fn fixture(input: PathBuf) { return; } - for (name, opts) in matrix() { - let output_dir = Path::new("tests").join("tsc-references"); + let panics = matrix() + .into_par_iter() + .filter_map(|(name, opts)| { + // - let _ = create_dir_all(&output_dir); + catch_unwind(AssertUnwindSafe(|| { + let output_dir = Path::new("tests").join("tsc-references"); - let output_path = output_dir.join(format!( - "{}_{}.js", - input.file_stem().unwrap().to_str().unwrap(), - name - )); + let _ = create_dir_all(&output_dir); - compile(&input, &output_path, opts); + let output_path = output_dir.join(format!( + "{}_{}.js", + input.file_stem().unwrap().to_str().unwrap(), + name + )); + + compile(&input, &output_path, opts); + })) + .err() + }) + .collect::>(); + + if panics.is_empty() { + return; } + + resume_unwind(panics.into_iter().next().unwrap()); } fn from_json(s: &str) -> T diff --git a/crates/swc_ecma_minifier/src/compress/pure/dead_code.rs b/crates/swc_ecma_minifier/src/compress/pure/dead_code.rs index a64b9081142..be58563bf3b 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/dead_code.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/dead_code.rs @@ -1,6 +1,7 @@ -use swc_common::{util::take::Take, DUMMY_SP}; +use swc_common::{util::take::Take, EqIgnoreSpan, DUMMY_SP}; use swc_ecma_ast::*; use swc_ecma_utils::{ExprExt, StmtLike, Value}; +use swc_ecma_visit::{noop_visit_type, Visit, VisitWith}; use super::Pure; use crate::{ @@ -10,6 +11,182 @@ use crate::{ /// Methods related to option `dead_code`. impl Pure<'_> { + /// - Removes `L1: break L1` + pub(super) fn drop_instant_break(&mut self, s: &mut Stmt) { + if let Stmt::Labeled(ls) = s { + if let Stmt::Break(BreakStmt { + label: Some(label), .. + }) = &*ls.body + { + if label.sym == ls.label.sym { + self.changed = true; + tracing::debug!("Dropping instant break"); + s.take(); + } + } + } + } + + /// # Operations + /// + /// + /// - Convert if break to conditionals + /// + /// ```js + /// out: { + /// if (foo) break out; + /// console.log("bar"); + /// } + /// ``` + /// + /// => + /// + /// ```js + /// foo || console.log("bar"); + /// ``` + pub(super) fn optimize_labeled_stmt(&mut self, s: &mut Stmt) -> Option<()> { + if !self.options.dead_code { + return None; + } + + if let Stmt::Labeled(ls) = s { + if let Stmt::Block(bs) = &mut *ls.body { + let first = bs.stmts.first_mut()?; + + if let Stmt::If(IfStmt { + test, + cons, + alt: None, + .. + }) = first + { + if let Stmt::Break(BreakStmt { + label: Some(label), .. + }) = &**cons + { + if ls.label.sym == label.sym { + self.changed = true; + tracing::debug!("Optimizing labeled stmt with a break to if statement"); + + self.negate(test, true, false); + let test = test.take(); + + let mut cons = bs.take(); + cons.stmts.remove(0); + + *s = Stmt::If(IfStmt { + span: ls.span, + test, + cons: Box::new(Stmt::Block(cons)), + alt: None, + }); + return None; + } + } + } + + if let Stmt::If(IfStmt { + test, + cons, + alt: Some(alt), + .. + }) = first + { + if let Stmt::Break(BreakStmt { + label: Some(label), .. + }) = &**alt + { + if ls.label.sym == label.sym { + self.changed = true; + tracing::debug!( + "Optimizing labeled stmt with a break in alt to if statement" + ); + + let test = test.take(); + let cons = *cons.take(); + + let mut new_cons = bs.take(); + new_cons.stmts[0] = cons; + + *s = Stmt::If(IfStmt { + span: ls.span, + test, + cons: Box::new(Stmt::Block(new_cons)), + alt: None, + }); + return None; + } + } + } + } + } + + None + } + + /// Remove the last statement of a loop if it's continue + pub(super) fn drop_useless_continue(&mut self, s: &mut Stmt) { + match s { + Stmt::Labeled(ls) => { + let new = self.drop_useless_continue_inner(Some(ls.label.clone()), &mut ls.body); + if let Some(new) = new { + *s = new; + } + } + + _ => { + let new = self.drop_useless_continue_inner(None, s); + if let Some(new) = new { + *s = new; + } + } + } + } + + /// Returns [Some] if the whole statement sohuld be replaced + fn drop_useless_continue_inner( + &mut self, + label: Option, + loop_stmt: &mut Stmt, + ) -> Option { + let body = match loop_stmt { + Stmt::While(ws) => &mut *ws.body, + Stmt::For(fs) => &mut *fs.body, + Stmt::ForIn(fs) => &mut *fs.body, + Stmt::ForOf(fs) => &mut *fs.body, + _ => return None, + }; + + if let Stmt::Block(b) = body { + let last = b.stmts.last_mut()?; + + if let Stmt::Continue(last_cs) = last { + match last_cs.label { + Some(_) => { + if label.eq_ignore_span(&last_cs.label) { + } else { + return None; + } + } + None => {} + } + } else { + return None; + } + self.changed = true; + tracing::debug!("Remove useless continue (last stmt of a loop)"); + b.stmts.remove(b.stmts.len() - 1); + + if let Some(label) = &label { + if !contains_label(b, label) { + return Some(loop_stmt.take()); + } + } + } + + None + } + pub(super) fn drop_unreachable_stmts(&mut self, stmts: &mut Vec) where T: StmtLike + ModuleItemExt + Take, @@ -159,3 +336,45 @@ impl Pure<'_> { *stmts = new; } } + +fn contains_label(node: &N, label: &Ident) -> bool +where + for<'aa> N: VisitWith>, +{ + let mut v = LabelFinder { + label, + found: false, + }; + node.visit_with(&mut v); + v.found +} + +struct LabelFinder<'a> { + label: &'a Ident, + found: bool, +} +impl Visit for LabelFinder<'_> { + noop_visit_type!(); + + fn visit_break_stmt(&mut self, s: &BreakStmt) { + match &s.label { + Some(label) => { + if label.sym == self.label.sym { + self.found = true; + } + } + None => {} + } + } + + fn visit_continue_stmt(&mut self, s: &ContinueStmt) { + match &s.label { + Some(label) => { + if label.sym == self.label.sym { + self.found = true; + } + } + None => {} + } + } +} diff --git a/crates/swc_ecma_minifier/src/compress/pure/mod.rs b/crates/swc_ecma_minifier/src/compress/pure/mod.rs index 020a4658fe4..e05d62f924b 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/mod.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/mod.rs @@ -598,6 +598,12 @@ impl VisitMut for Pure<'_> { self.loop_to_for_stmt(s); + self.drop_instant_break(s); + + self.optimize_labeled_stmt(s); + + self.drop_useless_continue(s); + if let Stmt::Expr(es) = s { if es.expr.is_invalid() { *s = Stmt::Empty(EmptyStmt { span: DUMMY_SP }); diff --git a/crates/swc_ecma_minifier/tests/TODO.txt b/crates/swc_ecma_minifier/tests/TODO.txt index d352e6d6608..1f99c51f2b8 100644 --- a/crates/swc_ecma_minifier/tests/TODO.txt +++ b/crates/swc_ecma_minifier/tests/TODO.txt @@ -518,12 +518,7 @@ keep_names/keep_some_classnames/input.js keep_names/keep_some_fnames/input.js keep_names/keep_some_fnames_reduce/input.js keep_quoted_strict/keep_quoted_strict/input.js -labels/labels_1/input.js -labels/labels_2/input.js labels/labels_4/input.js -labels/labels_6/input.js -labels/labels_7/input.js -labels/labels_9/input.js logical_assignment/assign_in_conditional_part/input.js logical_assignment/assignment_in_left_part_2/input.js loops/drop_if_else_break_1/input.js diff --git a/crates/swc_ecma_minifier/tests/golden.txt b/crates/swc_ecma_minifier/tests/golden.txt index bf624ea7faf..074beb1e93c 100644 --- a/crates/swc_ecma_minifier/tests/golden.txt +++ b/crates/swc_ecma_minifier/tests/golden.txt @@ -813,10 +813,15 @@ keep_names/keep_classnames/input.js keep_names/keep_fnames/input.js keep_names/keep_fnames_and_avoid_collisions/input.js keep_names/keep_var_fnames/input.js +labels/labels_1/input.js labels/labels_10/input.js +labels/labels_2/input.js labels/labels_3/input.js labels/labels_5/input.js +labels/labels_6/input.js +labels/labels_7/input.js labels/labels_8/input.js +labels/labels_9/input.js logical_assignment/assign_in_conditional_part_reused/input.js logical_assignment/assignment_in_left_part/input.js logical_assignment/logical_assignment_not_always_happens/input.js diff --git a/scripts/update-all.sh b/scripts/update-all.sh index a9f17cac303..d27403a39ae 100755 --- a/scripts/update-all.sh +++ b/scripts/update-all.sh @@ -9,9 +9,6 @@ function up(){ } up -up -up -up git add -A