Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(es/minifier): Preserve flags while dropping elements of SeqExpr #8907

Merged
merged 16 commits into from
Jul 31, 2024
5 changes: 5 additions & 0 deletions .changeset/gorgeous-ties-fail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
swc_ecma_minifier: patch
---

dead_branch_remover removes PURE annotations on sequence expressions
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ resolver = "2"
copyless = "0.1.5"
crc = "2.1.0"
criterion = "0.5.1"
crossbeam-queue = "0.3.11"
dashmap = "5.5.3"
dialoguer = "0.10.2"
difference = "2"
Expand Down
1 change: 1 addition & 0 deletions crates/swc_ecma_minifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
tracing = { workspace = true }


swc_allocator = { version = "0.1.7", path = "../swc_allocator", default-features = false }
swc_atoms = { version = "0.6.5", path = "../swc_atoms" }
swc_common = { version = "0.36.0", path = "../swc_common" }
Expand Down
1 change: 0 additions & 1 deletion crates/swc_ecma_minifier/src/compress/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,6 @@ impl Compressor<'_> {

let mut visitor = pure_optimizer(
self.options,
None,
self.marks,
PureOptimizerConfig {
enable_join_vars: self.pass > 1,
Expand Down
2 changes: 2 additions & 0 deletions crates/swc_ecma_minifier/src/compress/optimize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1817,7 +1817,9 @@ impl VisitMut for Optimizer<'_> {

match e {
Expr::Seq(seq) if seq.exprs.len() == 1 => {
let span = seq.span;
*e = *seq.exprs[0].take();
e.set_span(span);
}

Expr::Assign(AssignExpr {
Expand Down
72 changes: 49 additions & 23 deletions crates/swc_ecma_minifier/src/compress/pure/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,11 @@ impl Pure<'_> {
}
}

fn make_ignored_expr(&mut self, exprs: impl Iterator<Item = Box<Expr>>) -> Option<Expr> {
fn make_ignored_expr(
&mut self,
span: Span,
exprs: impl Iterator<Item = Box<Expr>>,
) -> Option<Expr> {
let mut exprs = exprs
.filter_map(|mut e| {
self.ignore_return_value(
Expand All @@ -894,7 +898,9 @@ impl Pure<'_> {
return None;
}
if exprs.len() == 1 {
return Some(*exprs.remove(0));
let mut new = *exprs.remove(0);
new.set_span(span);
return Some(new);
}

Some(
Expand Down Expand Up @@ -970,32 +976,41 @@ impl Pure<'_> {
}
}

Expr::Call(CallExpr { ctxt, args, .. }) if ctxt.has_mark(self.marks.pure) => {
Expr::Call(CallExpr {
span, ctxt, args, ..
}) if ctxt.has_mark(self.marks.pure) => {
report_change!("ignore_return_value: Dropping a pure call");
self.changed = true;

let new = self.make_ignored_expr(args.take().into_iter().map(|arg| arg.expr));
let new =
self.make_ignored_expr(*span, args.take().into_iter().map(|arg| arg.expr));

*e = new.unwrap_or(Invalid { span: DUMMY_SP }.into());
return;
}

Expr::TaggedTpl(TaggedTpl { ctxt, tpl, .. }) if ctxt.has_mark(self.marks.pure) => {
Expr::TaggedTpl(TaggedTpl {
span, ctxt, tpl, ..
}) if ctxt.has_mark(self.marks.pure) => {
report_change!("ignore_return_value: Dropping a pure call");
self.changed = true;

let new = self.make_ignored_expr(tpl.exprs.take().into_iter());
let new = self.make_ignored_expr(*span, tpl.exprs.take().into_iter());

*e = new.unwrap_or(Invalid { span: DUMMY_SP }.into());
return;
}

Expr::New(NewExpr { ctxt, args, .. }) if ctxt.has_mark(self.marks.pure) => {
Expr::New(NewExpr {
span, ctxt, args, ..
}) if ctxt.has_mark(self.marks.pure) => {
report_change!("ignore_return_value: Dropping a pure call");
self.changed = true;

let new =
self.make_ignored_expr(args.take().into_iter().flatten().map(|arg| arg.expr));
let new = self.make_ignored_expr(
*span,
args.take().into_iter().flatten().map(|arg| arg.expr),
);

*e = new.unwrap_or(Invalid { span: DUMMY_SP }.into());
return;
Expand All @@ -1006,6 +1021,7 @@ impl Pure<'_> {

match e {
Expr::Call(CallExpr {
span,
callee: Callee::Expr(callee),
args,
..
Expand All @@ -1014,20 +1030,23 @@ impl Pure<'_> {
self.changed = true;
report_change!("Dropping pure call as callee is pure");
*e = self
.make_ignored_expr(args.take().into_iter().map(|arg| arg.expr))
.make_ignored_expr(*span, args.take().into_iter().map(|arg| arg.expr))
.unwrap_or(Invalid { span: DUMMY_SP }.into());
return;
}
}

Expr::TaggedTpl(TaggedTpl {
tag: callee, tpl, ..
span,
tag: callee,
tpl,
..
}) => {
if callee.is_pure_callee(&self.expr_ctx) {
self.changed = true;
report_change!("Dropping pure tag tpl as callee is pure");
*e = self
.make_ignored_expr(tpl.exprs.take().into_iter())
.make_ignored_expr(*span, tpl.exprs.take().into_iter())
.unwrap_or(Invalid { span: DUMMY_SP }.into());
return;
}
Expand Down Expand Up @@ -1357,24 +1376,29 @@ impl Pure<'_> {

if self.options.side_effects && self.options.pristine_globals {
match e {
Expr::New(NewExpr { callee, args, .. })
if callee.is_one_of_global_ref_to(
&self.expr_ctx,
&[
"Map", "Set", "Array", "Object", "Boolean", "Number", "String",
],
) =>
Expr::New(NewExpr {
span, callee, args, ..
}) if callee.is_one_of_global_ref_to(
&self.expr_ctx,
&[
"Map", "Set", "Array", "Object", "Boolean", "Number", "String",
],
) =>
{
report_change!("Dropping a pure new expression");

self.changed = true;
*e = self
.make_ignored_expr(args.iter_mut().flatten().map(|arg| arg.expr.take()))
.make_ignored_expr(
*span,
args.iter_mut().flatten().map(|arg| arg.expr.take()),
)
.unwrap_or(Invalid { span: DUMMY_SP }.into());
return;
}

Expr::Call(CallExpr {
span,
callee: Callee::Expr(callee),
args,
..
Expand All @@ -1387,7 +1411,7 @@ impl Pure<'_> {

self.changed = true;
*e = self
.make_ignored_expr(args.iter_mut().map(|arg| arg.expr.take()))
.make_ignored_expr(*span, args.iter_mut().map(|arg| arg.expr.take()))
.unwrap_or(Invalid { span: DUMMY_SP }.into());
return;
}
Expand Down Expand Up @@ -1427,7 +1451,7 @@ impl Pure<'_> {
}

*e = self
.make_ignored_expr(exprs.into_iter())
.make_ignored_expr(obj.span, exprs.into_iter())
.unwrap_or(Invalid { span: DUMMY_SP }.into());
report_change!("Ignored an object literal");
self.changed = true;
Expand Down Expand Up @@ -1499,7 +1523,7 @@ impl Pure<'_> {
}

*e = self
.make_ignored_expr(exprs.into_iter())
.make_ignored_expr(arr.span, exprs.into_iter())
.unwrap_or(Invalid { span: DUMMY_SP }.into());
report_change!("Ignored an array literal");
self.changed = true;
Expand All @@ -1514,6 +1538,7 @@ impl Pure<'_> {
//
// foo(),basr(),foo;
Expr::Member(MemberExpr {
span,
obj,
prop: MemberProp::Computed(prop),
..
Expand All @@ -1526,6 +1551,7 @@ impl Pure<'_> {
_ => {
*e = self
.make_ignored_expr(
*span,
vec![obj.take(), prop.expr.take()].into_iter(),
)
.unwrap_or(Invalid { span: DUMMY_SP }.into());
Expand Down
9 changes: 1 addition & 8 deletions crates/swc_ecma_minifier/src/compress/pure/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@ use self::{ctx::Ctx, misc::DropOpts};
use super::util::is_pure_undefined_or_null;
#[cfg(feature = "debug")]
use crate::debug::dump;
use crate::{
debug::AssertValid, maybe_par, option::CompressOptions, program_data::ProgramData,
util::ModuleItemExt,
};
use crate::{debug::AssertValid, maybe_par, option::CompressOptions, util::ModuleItemExt};

mod arrows;
mod bools;
Expand Down Expand Up @@ -52,7 +49,6 @@ pub(crate) struct PureOptimizerConfig {
#[allow(clippy::needless_lifetimes)]
pub(crate) fn pure_optimizer<'a>(
options: &'a CompressOptions,
data: Option<&'a ProgramData>,
marks: Marks,
config: PureOptimizerConfig,
) -> impl 'a + VisitMut + Repeated {
Expand All @@ -64,7 +60,6 @@ pub(crate) fn pure_optimizer<'a>(
unresolved_ctxt: SyntaxContext::empty().apply_mark(marks.unresolved_mark),
is_unresolved_ref_safe: false,
},
data,
ctx: Default::default(),
changed: Default::default(),
}
Expand All @@ -76,8 +71,6 @@ struct Pure<'a> {
marks: Marks,
expr_ctx: ExprCtx,

#[allow(unused)]
data: Option<&'a ProgramData>,
ctx: Ctx,
changed: bool,
}
Expand Down
1 change: 0 additions & 1 deletion crates/swc_ecma_minifier/src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,6 @@ impl Evaluator {
{
e.visit_mut_with(&mut pure_optimizer(
&Default::default(),
None,
self.marks,
PureOptimizerConfig {
enable_join_vars: false,
Expand Down
1 change: 0 additions & 1 deletion crates/swc_ecma_minifier/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,6 @@ pub fn optimize(

let mut v = pure_optimizer(
c,
None,
marks,
PureOptimizerConfig {
force_str_for_tpl: Minification.force_str_for_tpl(),
Expand Down
3 changes: 1 addition & 2 deletions crates/swc_ecma_minifier/tests/benches-full/terser.js
Original file line number Diff line number Diff line change
Expand Up @@ -4437,8 +4437,7 @@
let printed_comments = new Set();
var to_utf8 = options.ascii_only ? function(str, identifier = !1, regexp = !1) {
return !(options.ecma >= 2015) || options.safari10 || regexp || (str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) {
return "\\u{" + // https://en.wikipedia.org/wiki/Universal_Character_Set_characters#Surrogates
(is_surrogate_pair_head(ch.charCodeAt(0)) ? 0x10000 + (ch.charCodeAt(0) - 0xd800 << 10) + ch.charCodeAt(1) - 0xdc00 : ch.charCodeAt(0)).toString(16) + "}";
return "\\u{" + (is_surrogate_pair_head(ch.charCodeAt(0)) ? 0x10000 + (ch.charCodeAt(0) - 0xd800 << 10) + ch.charCodeAt(1) - 0xdc00 : ch.charCodeAt(0)).toString(16) + "}";
})), str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
var code = ch.charCodeAt(0).toString(16);
if (code.length <= 2 && !identifier) {
Expand Down
3 changes: 1 addition & 2 deletions crates/swc_ecma_minifier/tests/benches-full/victory.js
Original file line number Diff line number Diff line change
Expand Up @@ -11730,8 +11730,7 @@ object-assign
// Equivalent of `typeof` but with special handling for array and regexp.
function getPropType(propValue) {
var propType = typeof propValue;
return Array.isArray(propValue) ? 'array' : propValue instanceof RegExp ? 'object' : // Native Symbol.
'symbol' === propType || propValue && ('Symbol' === propValue['@@toStringTag'] || 'function' == typeof Symbol && propValue instanceof Symbol) ? 'symbol' : propType;
return Array.isArray(propValue) ? 'array' : propValue instanceof RegExp ? 'object' : 'symbol' === propType || propValue && ('Symbol' === propValue['@@toStringTag'] || 'function' == typeof Symbol && propValue instanceof Symbol) ? 'symbol' : propType;
}
// This handles more types than `getPropType`. Only used for error messages.
// See `createPrimitiveTypeChecker`.
Expand Down
Loading
Loading