mirror of
https://github.com/swc-project/swc.git
synced 2024-12-22 21:21:31 +03:00
refactor(es/minifier): Clean up logging (#4322)
This commit is contained in:
parent
279145022d
commit
2002554fa2
@ -577,7 +577,7 @@ where
|
|||||||
|
|
||||||
if let Expr::Ident(i) = e {
|
if let Expr::Ident(i) = e {
|
||||||
if cfg!(feature = "debug") {
|
if cfg!(feature = "debug") {
|
||||||
// tracing::debug!(
|
// debug!(
|
||||||
// "Usage: `{}``; update = {:?}, assign_lhs = {:?} ",
|
// "Usage: `{}``; update = {:?}, assign_lhs = {:?} ",
|
||||||
// i,
|
// i,
|
||||||
// self.ctx.in_update_arg,
|
// self.ctx.in_update_arg,
|
||||||
|
@ -32,7 +32,7 @@ impl Storage for ProgramData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (id, mut var_info) in child.vars {
|
for (id, mut var_info) in child.vars {
|
||||||
// tracing::trace!("merge({:?},{}{:?})", kind, id.0, id.1);
|
// trace!("merge({:?},{}{:?})", kind, id.0, id.1);
|
||||||
match self.vars.entry(id) {
|
match self.vars.entry(id) {
|
||||||
Entry::Occupied(mut e) => {
|
Entry::Occupied(mut e) => {
|
||||||
e.get_mut().inline_prevented |= var_info.inline_prevented;
|
e.get_mut().inline_prevented |= var_info.inline_prevented;
|
||||||
@ -118,7 +118,7 @@ impl Storage for ProgramData {
|
|||||||
kind: Option<VarDeclKind>,
|
kind: Option<VarDeclKind>,
|
||||||
) -> &mut VarUsageInfo {
|
) -> &mut VarUsageInfo {
|
||||||
// if cfg!(feature = "debug") {
|
// if cfg!(feature = "debug") {
|
||||||
// tracing::debug!(has_init = has_init, "declare_decl(`{}`)", i);
|
// debug!(has_init = has_init, "declare_decl(`{}`)", i);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let v = self
|
let v = self
|
||||||
@ -126,9 +126,7 @@ impl Storage for ProgramData {
|
|||||||
.entry(i.to_id())
|
.entry(i.to_id())
|
||||||
.and_modify(|v| {
|
.and_modify(|v| {
|
||||||
if has_init && v.declared {
|
if has_init && v.declared {
|
||||||
if cfg!(feature = "debug") {
|
trace_op!("declare_decl(`{}`): Already declared", i);
|
||||||
tracing::debug!("declare_decl(`{}`): Already declared", i);
|
|
||||||
}
|
|
||||||
|
|
||||||
v.mutated = true;
|
v.mutated = true;
|
||||||
v.reassigned_with_var_decl = true;
|
v.reassigned_with_var_decl = true;
|
||||||
@ -184,7 +182,7 @@ impl ScopeDataLike for ScopeData {
|
|||||||
|
|
||||||
impl ProgramData {
|
impl ProgramData {
|
||||||
fn report(&mut self, i: Id, ctx: Ctx, is_modify: bool, dejavu: &mut AHashSet<Id>) {
|
fn report(&mut self, i: Id, ctx: Ctx, is_modify: bool, dejavu: &mut AHashSet<Id>) {
|
||||||
// tracing::trace!("report({}{:?})", i.0, i.1);
|
// trace!("report({}{:?})", i.0, i.1);
|
||||||
|
|
||||||
let is_first = dejavu.is_empty();
|
let is_first = dejavu.is_empty();
|
||||||
|
|
||||||
@ -193,7 +191,7 @@ impl ProgramData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let e = self.vars.entry(i).or_insert_with(|| {
|
let e = self.vars.entry(i).or_insert_with(|| {
|
||||||
// tracing::trace!("insert({}{:?})", i.0, i.1);
|
// trace!("insert({}{:?})", i.0, i.1);
|
||||||
|
|
||||||
VarUsageInfo {
|
VarUsageInfo {
|
||||||
is_fn_local: true,
|
is_fn_local: true,
|
||||||
|
@ -22,7 +22,7 @@ use swc_ecma_transforms_optimization::simplify::{
|
|||||||
use swc_ecma_utils::StmtLike;
|
use swc_ecma_utils::StmtLike;
|
||||||
use swc_ecma_visit::{as_folder, noop_visit_mut_type, VisitMut, VisitMutWith, VisitWith};
|
use swc_ecma_visit::{as_folder, noop_visit_mut_type, VisitMut, VisitMutWith, VisitWith};
|
||||||
use swc_timer::timer;
|
use swc_timer::timer;
|
||||||
use tracing::error;
|
use tracing::{debug, error};
|
||||||
|
|
||||||
pub(crate) use self::pure::pure_optimizer;
|
pub(crate) use self::pure::pure_optimizer;
|
||||||
use self::{hoist_decls::DeclHoisterConfig, optimize::optimizer};
|
use self::{hoist_decls::DeclHoisterConfig, optimize::optimizer};
|
||||||
@ -128,7 +128,7 @@ where
|
|||||||
where
|
where
|
||||||
N: Send + Sync + for<'aa> VisitMutWith<Compressor<'aa, M>>,
|
N: Send + Sync + for<'aa> VisitMutWith<Compressor<'aa, M>>,
|
||||||
{
|
{
|
||||||
tracing::debug!("visit_par(left_depth = {})", self.left_parallel_depth);
|
trace_op!("visit_par(left_depth = {})", self.left_parallel_depth);
|
||||||
|
|
||||||
if self.left_parallel_depth == 0 || cfg!(target_arch = "wasm32") {
|
if self.left_parallel_depth == 0 || cfg!(target_arch = "wasm32") {
|
||||||
for node in nodes {
|
for node in nodes {
|
||||||
@ -181,12 +181,10 @@ where
|
|||||||
+ for<'aa> VisitMutWith<Compressor<'aa, M>>
|
+ for<'aa> VisitMutWith<Compressor<'aa, M>>
|
||||||
+ VisitWith<AssertValid>,
|
+ VisitWith<AssertValid>,
|
||||||
{
|
{
|
||||||
if cfg!(feature = "debug") {
|
trace_op!(
|
||||||
tracing::debug!(
|
"Optimizing a compile unit within `{:?}`",
|
||||||
"Optimizing a compile unit within `{:?}`",
|
thread::current().name()
|
||||||
thread::current().name()
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let data = analyze(&*n, Some(self.marks));
|
let data = analyze(&*n, Some(self.marks));
|
||||||
@ -236,7 +234,7 @@ where
|
|||||||
|
|
||||||
if self.options.passes != 0 && self.options.passes < self.pass {
|
if self.options.passes != 0 && self.options.passes < self.pass {
|
||||||
let done = dump(&*n, false);
|
let done = dump(&*n, false);
|
||||||
tracing::debug!("===== Done =====\n{}", done);
|
debug!("===== Done =====\n{}", done);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +266,7 @@ where
|
|||||||
|
|
||||||
let start = if cfg!(feature = "debug") {
|
let start = if cfg!(feature = "debug") {
|
||||||
let start = n.dump();
|
let start = n.dump();
|
||||||
tracing::debug!("===== Start =====\n{}", start);
|
debug!("===== Start =====\n{}", start);
|
||||||
start
|
start
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
@ -288,9 +286,9 @@ where
|
|||||||
if visitor.changed() {
|
if visitor.changed() {
|
||||||
n.invoke();
|
n.invoke();
|
||||||
|
|
||||||
tracing::debug!("compressor: Simplified expressions");
|
debug!("compressor: Simplified expressions");
|
||||||
if cfg!(feature = "debug") {
|
if cfg!(feature = "debug") {
|
||||||
tracing::debug!("===== Simplified =====\n{}", dump(&*n, false));
|
debug!("===== Simplified =====\n{}", dump(&*n, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,7 +333,7 @@ where
|
|||||||
n.invoke();
|
n.invoke();
|
||||||
|
|
||||||
let src = n.dump();
|
let src = n.dump();
|
||||||
tracing::debug!("===== After pure =====\n{}\n{}", start, src);
|
debug!("===== After pure =====\n{}\n{}", start, src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,7 +361,7 @@ where
|
|||||||
self.changed |= visitor.changed();
|
self.changed |= visitor.changed();
|
||||||
|
|
||||||
// let done = dump(&*n);
|
// let done = dump(&*n);
|
||||||
// tracing::debug!("===== Result =====\n{}", done);
|
// debug!("===== Result =====\n{}", done);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.options.conditionals || self.options.dead_code {
|
if self.options.conditionals || self.options.dead_code {
|
||||||
@ -392,10 +390,9 @@ where
|
|||||||
let simplified = dump(&*n, false);
|
let simplified = dump(&*n, false);
|
||||||
|
|
||||||
if start != simplified {
|
if start != simplified {
|
||||||
tracing::debug!(
|
debug!(
|
||||||
"===== Removed dead branches =====\n{}\n==== ===== ===== ===== ======\n{}",
|
"===== Removed dead branches =====\n{}\n==== ===== ===== ===== ======\n{}",
|
||||||
start,
|
start, simplified
|
||||||
simplified
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("arguments: Optimizing computed access to arguments");
|
report_change!("arguments: Optimizing computed access to arguments");
|
||||||
*prop = MemberProp::Ident(Ident {
|
*prop = MemberProp::Ident(Ident {
|
||||||
span: s.span,
|
span: s.span,
|
||||||
sym: s.take().value,
|
sym: s.take().value,
|
||||||
@ -48,7 +48,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("arguments: Optimizing computed access to arguments");
|
report_change!("arguments: Optimizing computed access to arguments");
|
||||||
*prop = SuperProp::Ident(Ident {
|
*prop = SuperProp::Ident(Ident {
|
||||||
span: s.span,
|
span: s.span,
|
||||||
sym: s.take().value,
|
sym: s.take().value,
|
||||||
@ -127,7 +127,7 @@ impl ArgReplacer<'_> {
|
|||||||
let new_args = idx + 1 - self.params.len();
|
let new_args = idx + 1 - self.params.len();
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("arguments: Injecting {} parameters", new_args);
|
report_change!("arguments: Injecting {} parameters", new_args);
|
||||||
let mut start = self.params.len();
|
let mut start = self.params.len();
|
||||||
self.params.extend(
|
self.params.extend(
|
||||||
repeat_with(|| {
|
repeat_with(|| {
|
||||||
@ -206,8 +206,8 @@ impl VisitMut for ArgReplacer<'_> {
|
|||||||
//
|
//
|
||||||
if let Some(param) = self.params.get(idx) {
|
if let Some(param) = self.params.get(idx) {
|
||||||
if let Pat::Ident(i) = ¶m.pat {
|
if let Pat::Ident(i) = ¶m.pat {
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"arguments: Replacing access to arguments to normal reference",
|
"arguments: Replacing access to arguments to normal reference"
|
||||||
);
|
);
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*n = Expr::Ident(i.id.clone());
|
*n = Expr::Ident(i.id.clone());
|
||||||
|
@ -62,7 +62,7 @@ where
|
|||||||
// =>
|
// =>
|
||||||
//
|
//
|
||||||
// `_ || 'undefined' == typeof require`
|
// `_ || 'undefined' == typeof require`
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
is_return_value_ignored = is_ret_val_ignored,
|
is_return_value_ignored = is_ret_val_ignored,
|
||||||
negate_cost = cost,
|
negate_cost = cost,
|
||||||
"bools: Negating: (!a && !b) => !(a || b) (because both expression are good for \
|
"bools: Negating: (!a && !b) => !(a || b) (because both expression are good for \
|
||||||
@ -84,9 +84,7 @@ where
|
|||||||
self.with_ctx(ctx).negate(&mut e.left, false);
|
self.with_ctx(ctx).negate(&mut e.left, false);
|
||||||
self.with_ctx(ctx).negate(&mut e.right, is_ret_val_ignored);
|
self.with_ctx(ctx).negate(&mut e.right, is_ret_val_ignored);
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
dump_change_detail!("{} => {}", start, dump(&*e, false));
|
||||||
tracing::debug!("[Change] {} => {}", start, dump(&*e, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -104,7 +102,7 @@ where
|
|||||||
if stmt.alt == None {
|
if stmt.alt == None {
|
||||||
if let Stmt::Expr(cons) = &mut *stmt.cons {
|
if let Stmt::Expr(cons) = &mut *stmt.cons {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("conditionals: `if (foo) bar;` => `foo && bar`");
|
report_change!("conditionals: `if (foo) bar;` => `foo && bar`");
|
||||||
*s = Stmt::Expr(ExprStmt {
|
*s = Stmt::Expr(ExprStmt {
|
||||||
span: stmt.span,
|
span: stmt.span,
|
||||||
expr: Box::new(Expr::Bin(BinExpr {
|
expr: Box::new(Expr::Bin(BinExpr {
|
||||||
@ -283,7 +281,7 @@ where
|
|||||||
match (lt, rt) {
|
match (lt, rt) {
|
||||||
(Type::Undefined, Type::Null) | (Type::Null, Type::Undefined) => {
|
(Type::Undefined, Type::Null) | (Type::Null, Type::Undefined) => {
|
||||||
if op == op!("===") {
|
if op == op!("===") {
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"Reducing `!== null || !== undefined` check to `!= null`"
|
"Reducing `!== null || !== undefined` check to `!= null`"
|
||||||
);
|
);
|
||||||
return Some(BinExpr {
|
return Some(BinExpr {
|
||||||
@ -293,7 +291,7 @@ where
|
|||||||
right: Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP }))),
|
right: Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP }))),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"Reducing `=== null || === undefined` check to `== null`"
|
"Reducing `=== null || === undefined` check to `== null`"
|
||||||
);
|
);
|
||||||
return Some(BinExpr {
|
return Some(BinExpr {
|
||||||
|
@ -62,7 +62,7 @@ where
|
|||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"collpase_vars: Decided to inline {}{:?}",
|
"collpase_vars: Decided to inline {}{:?}",
|
||||||
left.id.sym,
|
left.id.sym,
|
||||||
left.id.span.ctxt
|
left.id.span.ctxt
|
||||||
|
@ -34,7 +34,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
if negate_cost(&stmt.test, true, false) < 0 {
|
if negate_cost(&stmt.test, true, false) < 0 {
|
||||||
tracing::debug!("if_return: Negating `cond` of an if statement which has cons and alt");
|
report_change!("if_return: Negating `cond` of an if statement which has cons and alt");
|
||||||
let ctx = Ctx {
|
let ctx = Ctx {
|
||||||
in_bool_ctx: true,
|
in_bool_ctx: true,
|
||||||
..self.ctx
|
..self.ctx
|
||||||
@ -47,7 +47,7 @@ where
|
|||||||
match &*alt {
|
match &*alt {
|
||||||
Stmt::Return(..) | Stmt::Continue(ContinueStmt { label: None, .. }) => {
|
Stmt::Return(..) | Stmt::Continue(ContinueStmt { label: None, .. }) => {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"if_return: Negating an if statement because the alt is return / continue"
|
"if_return: Negating an if statement because the alt is return / continue"
|
||||||
);
|
);
|
||||||
self.negate(&mut stmt.test, false);
|
self.negate(&mut stmt.test, false);
|
||||||
@ -68,7 +68,7 @@ where
|
|||||||
|
|
||||||
if !cond.cons.may_have_side_effects() {
|
if !cond.cons.may_have_side_effects() {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("conditionals: `cond ? useless : alt` => `cond || alt`");
|
report_change!("conditionals: `cond ? useless : alt` => `cond || alt`");
|
||||||
*e = Expr::Bin(BinExpr {
|
*e = Expr::Bin(BinExpr {
|
||||||
span: cond.span,
|
span: cond.span,
|
||||||
op: op!("||"),
|
op: op!("||"),
|
||||||
@ -80,7 +80,7 @@ where
|
|||||||
|
|
||||||
if !cond.alt.may_have_side_effects() {
|
if !cond.alt.may_have_side_effects() {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("conditionals: `cond ? cons : useless` => `cond && cons`");
|
report_change!("conditionals: `cond ? cons : useless` => `cond && cons`");
|
||||||
*e = Expr::Bin(BinExpr {
|
*e = Expr::Bin(BinExpr {
|
||||||
span: cond.span,
|
span: cond.span,
|
||||||
op: op!("&&"),
|
op: op!("&&"),
|
||||||
@ -127,7 +127,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("conditionals: Merging if statements with same `cons`");
|
report_change!("conditionals: Merging if statements with same `cons`");
|
||||||
|
|
||||||
let mut cur: Option<IfStmt> = None;
|
let mut cur: Option<IfStmt> = None;
|
||||||
let mut new = Vec::with_capacity(stmts.len());
|
let mut new = Vec::with_capacity(stmts.len());
|
||||||
@ -214,7 +214,7 @@ where
|
|||||||
expr: stmt.test.take(),
|
expr: stmt.test.take(),
|
||||||
});
|
});
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("conditionals: `if (foo);` => `foo` ");
|
report_change!("conditionals: `if (foo);` => `foo` ");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,7 +240,7 @@ where
|
|||||||
Expr::Unary(UnaryExpr {
|
Expr::Unary(UnaryExpr {
|
||||||
op: op!("!"), arg, ..
|
op: op!("!"), arg, ..
|
||||||
}) => {
|
}) => {
|
||||||
tracing::debug!("Optimizing `if (!foo); else bar();` as `foo && bar();`");
|
report_change!("Optimizing `if (!foo); else bar();` as `foo && bar();`");
|
||||||
|
|
||||||
let mut expr = Box::new(Expr::Bin(BinExpr {
|
let mut expr = Box::new(Expr::Bin(BinExpr {
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
@ -255,7 +255,7 @@ where
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
tracing::debug!("Optimizing `if (foo); else bar();` as `foo || bar();`");
|
report_change!("Optimizing `if (foo); else bar();` as `foo || bar();`");
|
||||||
|
|
||||||
let mut expr = Box::new(Expr::Bin(BinExpr {
|
let mut expr = Box::new(Expr::Bin(BinExpr {
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
@ -290,7 +290,7 @@ where
|
|||||||
|
|
||||||
if self.options.conditionals || self.options.bools {
|
if self.options.conditionals || self.options.bools {
|
||||||
// if (a) b(); else c(); => a ? b() : c()
|
// if (a) b(); else c(); => a ? b() : c()
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"Compressing if statement as conditional expression (even though cons and alt is \
|
"Compressing if statement as conditional expression (even though cons and alt is \
|
||||||
not compressable)"
|
not compressable)"
|
||||||
);
|
);
|
||||||
@ -325,7 +325,7 @@ where
|
|||||||
|
|
||||||
// x ? x : y => x || y
|
// x ? x : y => x || y
|
||||||
if cond.test.is_ident() && cond.test.eq_ignore_span(&cond.cons) {
|
if cond.test.is_ident() && cond.test.eq_ignore_span(&cond.cons) {
|
||||||
tracing::debug!("Compressing `x ? x : y` as `x || y`");
|
report_change!("Compressing `x ? x : y` as `x || y`");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*e = Expr::Bin(BinExpr {
|
*e = Expr::Bin(BinExpr {
|
||||||
span: cond.span,
|
span: cond.span,
|
||||||
@ -344,7 +344,7 @@ where
|
|||||||
is_for_if_stmt: bool,
|
is_for_if_stmt: bool,
|
||||||
) -> Option<Expr> {
|
) -> Option<Expr> {
|
||||||
if cons.eq_ignore_span(alt) && !matches!(&*cons, Expr::Yield(..) | Expr::Fn(..)) {
|
if cons.eq_ignore_span(alt) && !matches!(&*cons, Expr::Yield(..) | Expr::Fn(..)) {
|
||||||
tracing::debug!("conditionals: cons is same as alt");
|
report_change!("conditionals: cons is same as alt");
|
||||||
return Some(Expr::Seq(SeqExpr {
|
return Some(Expr::Seq(SeqExpr {
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
exprs: vec![test.take(), Box::new(cons.take())],
|
exprs: vec![test.take(), Box::new(cons.take())],
|
||||||
@ -384,7 +384,7 @@ where
|
|||||||
.count();
|
.count();
|
||||||
|
|
||||||
if diff_count == 1 {
|
if diff_count == 1 {
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"conditionals: Merging cons and alt as only one argument differs"
|
"conditionals: Merging cons and alt as only one argument differs"
|
||||||
);
|
);
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
@ -446,7 +446,7 @@ where
|
|||||||
}
|
}
|
||||||
.as_arg()];
|
.as_arg()];
|
||||||
|
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"Compressing if into cond as there's no side effect and the number of \
|
"Compressing if into cond as there's no side effect and the number of \
|
||||||
arguments is 1"
|
arguments is 1"
|
||||||
);
|
);
|
||||||
@ -459,7 +459,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !side_effect_free && is_for_if_stmt {
|
if !side_effect_free && is_for_if_stmt {
|
||||||
tracing::debug!("Compressing if into cond while preserving side effects");
|
report_change!("Compressing if into cond while preserving side effects");
|
||||||
return Some(Expr::Cond(CondExpr {
|
return Some(Expr::Cond(CondExpr {
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
test: test.take(),
|
test: test.take(),
|
||||||
@ -512,7 +512,7 @@ where
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"Compressing if statement into a conditional expression of `new` as \
|
"Compressing if statement into a conditional expression of `new` as \
|
||||||
there's no side effect and the number of arguments is 1"
|
there's no side effect and the number of arguments is 1"
|
||||||
);
|
);
|
||||||
@ -533,7 +533,7 @@ where
|
|||||||
&& cons.left.eq_ignore_span(&alt.left)
|
&& cons.left.eq_ignore_span(&alt.left)
|
||||||
&& is_simple_lhs(&cons.left) =>
|
&& is_simple_lhs(&cons.left) =>
|
||||||
{
|
{
|
||||||
tracing::debug!("Merging assignments in cons and alt of if statement");
|
report_change!("Merging assignments in cons and alt of if statement");
|
||||||
Some(Expr::Assign(AssignExpr {
|
Some(Expr::Assign(AssignExpr {
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
op: cons.op,
|
op: cons.op,
|
||||||
@ -549,7 +549,7 @@ where
|
|||||||
|
|
||||||
// a ? b ? c() : d() : d() => a && b ? c() : d()
|
// a ? b ? c() : d() : d() => a && b ? c() : d()
|
||||||
(Expr::Cond(cons), alt) if (*cons.alt).eq_ignore_span(&*alt) => {
|
(Expr::Cond(cons), alt) if (*cons.alt).eq_ignore_span(&*alt) => {
|
||||||
tracing::debug!("conditionals: a ? b ? c() : d() : d() => a && b ? c() : d()");
|
report_change!("conditionals: a ? b ? c() : d() : d() => a && b ? c() : d()");
|
||||||
Some(Expr::Cond(CondExpr {
|
Some(Expr::Cond(CondExpr {
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
test: Box::new(Expr::Bin(BinExpr {
|
test: Box::new(Expr::Bin(BinExpr {
|
||||||
@ -568,7 +568,7 @@ where
|
|||||||
// (z || condition(), "fuji");
|
// (z || condition(), "fuji");
|
||||||
(cons, Expr::Seq(alt)) if (**alt.exprs.last().unwrap()).eq_ignore_span(&*cons) => {
|
(cons, Expr::Seq(alt)) if (**alt.exprs.last().unwrap()).eq_ignore_span(&*cons) => {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("conditionals: Reducing seq expr in alt");
|
report_change!("conditionals: Reducing seq expr in alt");
|
||||||
//
|
//
|
||||||
alt.exprs.pop();
|
alt.exprs.pop();
|
||||||
let first = Box::new(Expr::Bin(BinExpr {
|
let first = Box::new(Expr::Bin(BinExpr {
|
||||||
@ -591,7 +591,7 @@ where
|
|||||||
// (z && condition(), "fuji");
|
// (z && condition(), "fuji");
|
||||||
(Expr::Seq(cons), alt) if (**cons.exprs.last().unwrap()).eq_ignore_span(&*alt) => {
|
(Expr::Seq(cons), alt) if (**cons.exprs.last().unwrap()).eq_ignore_span(&*alt) => {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("conditionals: Reducing seq expr in cons");
|
report_change!("conditionals: Reducing seq expr in cons");
|
||||||
//
|
//
|
||||||
cons.exprs.pop();
|
cons.exprs.pop();
|
||||||
let first = Box::new(Expr::Bin(BinExpr {
|
let first = Box::new(Expr::Bin(BinExpr {
|
||||||
@ -647,7 +647,7 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("if_return: Injecting else because it's shorter");
|
report_change!("if_return: Injecting else because it's shorter");
|
||||||
|
|
||||||
let mut new = vec![];
|
let mut new = vec![];
|
||||||
new.reserve(pos_of_if + 1);
|
new.reserve(pos_of_if + 1);
|
||||||
@ -738,7 +738,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("conditionals: Dropped useless `else` token");
|
report_change!("conditionals: Dropped useless `else` token");
|
||||||
*stmts = new_stmts;
|
*stmts = new_stmts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ where
|
|||||||
.map(|var| var.is_fn_local && !var.declared_as_fn_param)
|
.map(|var| var.is_fn_local && !var.declared_as_fn_param)
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"dead_code: Dropping an assignment to a variable declared in function \
|
"dead_code: Dropping an assignment to a variable declared in function \
|
||||||
because function is being terminated"
|
because function is being terminated"
|
||||||
);
|
);
|
||||||
@ -80,7 +80,7 @@ where
|
|||||||
.map(|var| var.is_fn_local)
|
.map(|var| var.is_fn_local)
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"dead_code: Converting an assignment into a binary expression in \
|
"dead_code: Converting an assignment into a binary expression in \
|
||||||
function termination"
|
function termination"
|
||||||
);
|
);
|
||||||
|
@ -50,7 +50,7 @@ where
|
|||||||
if self.options.unsafe_passes {
|
if self.options.unsafe_passes {
|
||||||
match &*prop.sym {
|
match &*prop.sym {
|
||||||
"length" => {
|
"length" => {
|
||||||
tracing::debug!("evaluate: function.length");
|
report_change!("evaluate: function.length");
|
||||||
|
|
||||||
*e = Expr::Lit(Lit::Num(Number {
|
*e = Expr::Lit(Lit::Num(Number {
|
||||||
span: *span,
|
span: *span,
|
||||||
@ -61,7 +61,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
"name" => {
|
"name" => {
|
||||||
tracing::debug!("evaluate: function.name");
|
report_change!("evaluate: function.name");
|
||||||
|
|
||||||
*e = Expr::Lit(Lit::Str(Str {
|
*e = Expr::Lit(Lit::Str(Str {
|
||||||
span: *span,
|
span: *span,
|
||||||
@ -108,7 +108,7 @@ where
|
|||||||
sym: js_word!("undefined"),
|
sym: js_word!("undefined"),
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
tracing::debug!("evaluate: `undefined` -> `void 0`");
|
report_change!("evaluate: `undefined` -> `void 0`");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*e = *undefined(*span);
|
*e = *undefined(*span);
|
||||||
}
|
}
|
||||||
@ -118,7 +118,7 @@ where
|
|||||||
sym: js_word!("Infinity"),
|
sym: js_word!("Infinity"),
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
tracing::debug!("evaluate: `Infinity` -> `1 / 0`");
|
report_change!("evaluate: `Infinity` -> `1 / 0`");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*e = Expr::Bin(BinExpr {
|
*e = Expr::Bin(BinExpr {
|
||||||
span: *span,
|
span: *span,
|
||||||
@ -192,7 +192,7 @@ where
|
|||||||
1 => {
|
1 => {
|
||||||
if let Expr::Lit(Lit::Str(exp)) = &*args[0].expr {
|
if let Expr::Lit(Lit::Str(exp)) = &*args[0].expr {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"evaluate: Converting RegExpr call into a regexp literal `/{}/`",
|
"evaluate: Converting RegExpr call into a regexp literal `/{}/`",
|
||||||
exp.value
|
exp.value
|
||||||
);
|
);
|
||||||
@ -209,7 +209,7 @@ where
|
|||||||
(&*args[0].expr, &*args[1].expr)
|
(&*args[0].expr, &*args[1].expr)
|
||||||
{
|
{
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"evaluate: Converting RegExpr call into a regexp literal `/{}/{}`",
|
"evaluate: Converting RegExpr call into a regexp literal `/{}/{}`",
|
||||||
exp.value,
|
exp.value,
|
||||||
flags.value
|
flags.value
|
||||||
@ -244,7 +244,7 @@ where
|
|||||||
|
|
||||||
if let Some(v) = char::from_u32(v) {
|
if let Some(v) = char::from_u32(v) {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"evaluate: Evaluated `String.charCodeAt({})` as `{}`",
|
"evaluate: Evaluated `String.charCodeAt({})` as `{}`",
|
||||||
char_code,
|
char_code,
|
||||||
v
|
v
|
||||||
@ -346,7 +346,7 @@ where
|
|||||||
if let Expr::Call(..) = e {
|
if let Expr::Call(..) = e {
|
||||||
if let Some(value) = eval_as_number(e) {
|
if let Some(value) = eval_as_number(e) {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("evaluate: Evaluated an expression as `{}`", value);
|
report_change!("evaluate: Evaluated an expression as `{}`", value);
|
||||||
|
|
||||||
*e = Expr::Lit(Lit::Num(Number {
|
*e = Expr::Lit(Lit::Num(Number {
|
||||||
span: e.span(),
|
span: e.span(),
|
||||||
@ -365,7 +365,7 @@ where
|
|||||||
if let Known(l) = l {
|
if let Known(l) = l {
|
||||||
if let Known(r) = r {
|
if let Known(r) = r {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("evaluate: Evaluated `{:?} ** {:?}`", l, r);
|
report_change!("evaluate: Evaluated `{:?} ** {:?}`", l, r);
|
||||||
|
|
||||||
let value = l.powf(r);
|
let value = l.powf(r);
|
||||||
*e = Expr::Lit(Lit::Num(Number {
|
*e = Expr::Lit(Lit::Num(Number {
|
||||||
@ -405,7 +405,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("evaluate: `0 / 0` => `NaN`");
|
report_change!("evaluate: `0 / 0` => `NaN`");
|
||||||
|
|
||||||
// Sign does not matter for NaN
|
// Sign does not matter for NaN
|
||||||
*e = Expr::Ident(Ident::new(
|
*e = Expr::Ident(Ident::new(
|
||||||
@ -415,7 +415,7 @@ where
|
|||||||
}
|
}
|
||||||
(FpCategory::Normal, FpCategory::Zero) => {
|
(FpCategory::Normal, FpCategory::Zero) => {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("evaluate: `{} / 0` => `Infinity`", ln);
|
report_change!("evaluate: `{} / 0` => `Infinity`", ln);
|
||||||
|
|
||||||
// Sign does not matter for NaN
|
// Sign does not matter for NaN
|
||||||
*e = if ln.is_sign_positive() == rn.is_sign_positive() {
|
*e = if ln.is_sign_positive() == rn.is_sign_positive() {
|
||||||
@ -469,7 +469,7 @@ where
|
|||||||
// As we used as_pure_bool, we can drop it.
|
// As we used as_pure_bool, we can drop it.
|
||||||
if v && e.op == op!("&&") {
|
if v && e.op == op!("&&") {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Removing `b` from `a && b && c` because b is always truthy");
|
report_change!("Removing `b` from `a && b && c` because b is always truthy");
|
||||||
|
|
||||||
left.right.take();
|
left.right.take();
|
||||||
return;
|
return;
|
||||||
@ -477,7 +477,7 @@ where
|
|||||||
|
|
||||||
if !v && e.op == op!("||") {
|
if !v && e.op == op!("||") {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Removing `b` from `a || b || c` because b is always falsy");
|
report_change!("Removing `b` from `a || b || c` because b is always falsy");
|
||||||
|
|
||||||
left.right.take();
|
left.right.take();
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("fns: Reordering statements");
|
report_change!("fns: Reordering statements");
|
||||||
let mut fns = vec![];
|
let mut fns = vec![];
|
||||||
let mut other = vec![];
|
let mut other = vec![];
|
||||||
|
|
||||||
|
@ -41,9 +41,7 @@ where
|
|||||||
})
|
})
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("[x] bad usage");
|
||||||
tracing::trace!("[x] bad usage");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,9 +85,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !unknown_used_props.is_empty() {
|
if !unknown_used_props.is_empty() {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("[x] unknown used props: {:?}", unknown_used_props);
|
||||||
tracing::trace!("[x] unknown used props: {:?}", unknown_used_props);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +111,7 @@ where
|
|||||||
|
|
||||||
match &p.key {
|
match &p.key {
|
||||||
PropName::Str(s) => {
|
PropName::Str(s) => {
|
||||||
tracing::debug!(
|
trace_op!(
|
||||||
"hoist_props: Storing a variable (`{}`) to inline properties",
|
"hoist_props: Storing a variable (`{}`) to inline properties",
|
||||||
name.id
|
name.id
|
||||||
);
|
);
|
||||||
@ -124,7 +120,7 @@ where
|
|||||||
self.mode.store(name.to_id(), n.init.as_deref().unwrap());
|
self.mode.store(name.to_id(), n.init.as_deref().unwrap());
|
||||||
}
|
}
|
||||||
PropName::Ident(i) => {
|
PropName::Ident(i) => {
|
||||||
tracing::debug!(
|
trace_op!(
|
||||||
"hoist_props: Storing a variable(`{}`) to inline properties",
|
"hoist_props: Storing a variable(`{}`) to inline properties",
|
||||||
name.id
|
name.id
|
||||||
);
|
);
|
||||||
@ -177,7 +173,7 @@ where
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
tracing::debug!(
|
trace_op!(
|
||||||
"hoist_props: Stored {}{:?} to inline property access",
|
"hoist_props: Stored {}{:?} to inline property access",
|
||||||
name.id.sym,
|
name.id.sym,
|
||||||
name.id.span.ctxt
|
name.id.span.ctxt
|
||||||
@ -204,7 +200,7 @@ where
|
|||||||
f.function.span = DUMMY_SP;
|
f.function.span = DUMMY_SP;
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::debug!("hoist_props: Inlining `{}.{}`", obj.sym, prop.sym);
|
report_change!("hoist_props: Inlining `{}.{}`", obj.sym, prop.sym);
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*e = *value;
|
*e = *value;
|
||||||
return;
|
return;
|
||||||
@ -214,7 +210,7 @@ where
|
|||||||
if let Some(value) = self.vars_for_prop_hoisting.remove(&obj.to_id()) {
|
if let Some(value) = self.vars_for_prop_hoisting.remove(&obj.to_id()) {
|
||||||
member.obj = value;
|
member.obj = value;
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("hoist_props: Inlined a property");
|
report_change!("hoist_props: Inlined a property");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ where
|
|||||||
}) = &mut *s.cons
|
}) = &mut *s.cons
|
||||||
{
|
{
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("if_return: Merging nested if statements");
|
report_change!("if_return: Merging nested if statements");
|
||||||
|
|
||||||
s.test = Box::new(Expr::Bin(BinExpr {
|
s.test = Box::new(Expr::Bin(BinExpr {
|
||||||
span: s.test.span(),
|
span: s.test.span(),
|
||||||
@ -74,7 +74,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("if_return: Merging `else if` into `else`");
|
report_change!("if_return: Merging `else if` into `else`");
|
||||||
|
|
||||||
match &mut **alt_of_alt {
|
match &mut **alt_of_alt {
|
||||||
Stmt::Block(alt_of_alt) => {
|
Stmt::Block(alt_of_alt) => {
|
||||||
@ -181,7 +181,7 @@ where
|
|||||||
None => true,
|
None => true,
|
||||||
});
|
});
|
||||||
let skip = idx_of_not_mergable.map(|v| v + 1).unwrap_or(0);
|
let skip = idx_of_not_mergable.map(|v| v + 1).unwrap_or(0);
|
||||||
tracing::trace!("if_return: Skip = {}", skip);
|
trace_op!("if_return: Skip = {}", skip);
|
||||||
let mut last_idx = stmts.len() - 1;
|
let mut last_idx = stmts.len() - 1;
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -207,7 +207,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
if last_idx <= skip {
|
if last_idx <= skip {
|
||||||
tracing::trace!("if_return: [x] Aborting because of skip");
|
log_abort!("if_return: [x] Aborting because of skip");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,7 +218,7 @@ where
|
|||||||
// There's no return statement so merging requires injecting unnecessary `void
|
// There's no return statement so merging requires injecting unnecessary `void
|
||||||
// 0`
|
// 0`
|
||||||
if return_count == 0 {
|
if return_count == 0 {
|
||||||
tracing::trace!("if_return: [x] Aborting because we failed to find return");
|
log_abort!("if_return: [x] Aborting because we failed to find return");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ where
|
|||||||
(_, Some(Stmt::If(IfStmt { alt: None, .. }) | Stmt::Expr(..)))
|
(_, Some(Stmt::If(IfStmt { alt: None, .. }) | Stmt::Expr(..)))
|
||||||
if if_return_count <= 1 =>
|
if if_return_count <= 1 =>
|
||||||
{
|
{
|
||||||
tracing::trace!(
|
log_abort!(
|
||||||
"if_return: [x] Aborting because last stmt is a not return stmt"
|
"if_return: [x] Aborting because last stmt is a not return stmt"
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@ -258,7 +258,7 @@ where
|
|||||||
) => match &**cons {
|
) => match &**cons {
|
||||||
Stmt::Return(ReturnStmt { arg: Some(..), .. }) => {}
|
Stmt::Return(ReturnStmt { arg: Some(..), .. }) => {}
|
||||||
_ => {
|
_ => {
|
||||||
tracing::trace!(
|
log_abort!(
|
||||||
"if_return: [x] Aborting because stmt before last is an if stmt \
|
"if_return: [x] Aborting because stmt before last is an if stmt \
|
||||||
and cons of it is not a return stmt"
|
and cons of it is not a return stmt"
|
||||||
);
|
);
|
||||||
@ -314,14 +314,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::debug!("if_return: Merging returns");
|
report_change!("if_return: Merging returns");
|
||||||
if cfg!(feature = "debug") {
|
|
||||||
let block = BlockStmt {
|
|
||||||
span: DUMMY_SP,
|
|
||||||
stmts: stmts.clone(),
|
|
||||||
};
|
|
||||||
tracing::trace!("if_return: {}", dump(&block, false))
|
|
||||||
}
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
|
|
||||||
let mut cur: Option<Box<Expr>> = None;
|
let mut cur: Option<Box<Expr>> = None;
|
||||||
@ -442,9 +436,7 @@ where
|
|||||||
expr: Box::new(cur),
|
expr: Box::new(cur),
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
if cfg!(feature = "debug") {
|
trace_op!("if_return: Ignoring return value");
|
||||||
tracing::debug!("if_return: Ignoring return value");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -535,7 +527,7 @@ where
|
|||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
// if !res {
|
// if !res {
|
||||||
// tracing::trace!("Cannot merge: {}", dump(s));
|
// trace!("Cannot merge: {}", dump(s));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
res
|
res
|
||||||
@ -633,9 +625,7 @@ fn can_merge_as_if_return(s: &Stmt) -> bool {
|
|||||||
|
|
||||||
let c = cost(s);
|
let c = cost(s);
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
trace_op!("merging cost of `{}` = {:?}", dump(s, false), c);
|
||||||
tracing::trace!("merging cost of `{}` = {:?}", dump(s, false), c);
|
|
||||||
}
|
|
||||||
|
|
||||||
c.unwrap_or(0) < 0
|
c.unwrap_or(0) < 0
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Expr::Fn(..) = callee {
|
if let Expr::Fn(..) = callee {
|
||||||
tracing::debug!("negate_iife: Negating iife");
|
report_change!("negate_iife: Negating iife");
|
||||||
*e = Expr::Unary(UnaryExpr {
|
*e = Expr::Unary(UnaryExpr {
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
op: op!("!"),
|
op: op!("!"),
|
||||||
@ -73,7 +73,7 @@ where
|
|||||||
|
|
||||||
match callee {
|
match callee {
|
||||||
Expr::Fn(..) => {
|
Expr::Fn(..) => {
|
||||||
tracing::debug!("negate_iife: Swapping cons and alt");
|
report_change!("negate_iife: Swapping cons and alt");
|
||||||
cond.test = Box::new(Expr::Unary(UnaryExpr {
|
cond.test = Box::new(Expr::Unary(UnaryExpr {
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
op: op!("!"),
|
op: op!("!"),
|
||||||
@ -214,7 +214,7 @@ where
|
|||||||
|
|
||||||
let should_be_inlined = self.can_be_inlined_for_iife(arg);
|
let should_be_inlined = self.can_be_inlined_for_iife(arg);
|
||||||
if should_be_inlined {
|
if should_be_inlined {
|
||||||
tracing::trace!(
|
trace_op!(
|
||||||
"iife: Trying to inline argument ({}{:?})",
|
"iife: Trying to inline argument ({}{:?})",
|
||||||
param.id.sym,
|
param.id.sym,
|
||||||
param.id.span.ctxt
|
param.id.span.ctxt
|
||||||
@ -222,7 +222,7 @@ where
|
|||||||
vars.insert(param.to_id(), arg.clone());
|
vars.insert(param.to_id(), arg.clone());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tracing::trace!(
|
trace_op!(
|
||||||
"iife: Trying to inline argument ({}{:?}) (undefined)",
|
"iife: Trying to inline argument ({}{:?}) (undefined)",
|
||||||
param.id.sym,
|
param.id.sym,
|
||||||
param.id.span.ctxt
|
param.id.span.ctxt
|
||||||
@ -241,11 +241,11 @@ where
|
|||||||
let mut optimizer = self.with_ctx(ctx);
|
let mut optimizer = self.with_ctx(ctx);
|
||||||
match find_body(callee) {
|
match find_body(callee) {
|
||||||
Some(Either::Left(body)) => {
|
Some(Either::Left(body)) => {
|
||||||
tracing::trace!("inline: Inlining arguments");
|
trace_op!("inline: Inlining arguments");
|
||||||
optimizer.inline_vars_in_node(body, vars);
|
optimizer.inline_vars_in_node(body, vars);
|
||||||
}
|
}
|
||||||
Some(Either::Right(body)) => {
|
Some(Either::Right(body)) => {
|
||||||
tracing::trace!("inline: Inlining arguments");
|
trace_op!("inline: Inlining arguments");
|
||||||
optimizer.inline_vars_in_node(body, vars);
|
optimizer.inline_vars_in_node(body, vars);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -258,9 +258,7 @@ where
|
|||||||
where
|
where
|
||||||
N: for<'aa> VisitMutWith<MultiReplacer<'aa>>,
|
N: for<'aa> VisitMutWith<MultiReplacer<'aa>>,
|
||||||
{
|
{
|
||||||
if cfg!(feature = "debug") {
|
trace_op!("inline: inline_vars_in_node");
|
||||||
tracing::trace!("inline: inline_vars_in_node");
|
|
||||||
}
|
|
||||||
|
|
||||||
n.visit_mut_with(&mut MultiReplacer::new(
|
n.visit_mut_with(&mut MultiReplacer::new(
|
||||||
&mut vars,
|
&mut vars,
|
||||||
@ -315,19 +313,19 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
if self.ctx.dont_invoke_iife {
|
if self.ctx.dont_invoke_iife {
|
||||||
tracing::trace!("iife: [x] Inline is prevented");
|
log_abort!("iife: [x] Inline is prevented");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match callee {
|
match callee {
|
||||||
Expr::Arrow(f) => {
|
Expr::Arrow(f) => {
|
||||||
if f.is_async {
|
if f.is_async {
|
||||||
tracing::trace!("iife: [x] Cannot inline async fn");
|
log_abort!("iife: [x] Cannot inline async fn");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.is_generator {
|
if f.is_generator {
|
||||||
tracing::trace!("iife: [x] Cannot inline generator");
|
log_abort!("iife: [x] Cannot inline generator");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,7 +357,7 @@ where
|
|||||||
let new = self.inline_fn_like(¶m_ids, body, &mut call.args);
|
let new = self.inline_fn_like(¶m_ids, body, &mut call.args);
|
||||||
if let Some(new) = new {
|
if let Some(new) = new {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("inline: Inlining a function call (arrow)");
|
report_change!("inline: Inlining a function call (arrow)");
|
||||||
|
|
||||||
*e = new;
|
*e = new;
|
||||||
}
|
}
|
||||||
@ -446,7 +444,7 @@ where
|
|||||||
body.visit_mut_with(&mut Remapper { vars: remap });
|
body.visit_mut_with(&mut Remapper { vars: remap });
|
||||||
exprs.push(body.take());
|
exprs.push(body.take());
|
||||||
|
|
||||||
tracing::debug!("inline: Inlining a call to an arrow function");
|
report_change!("inline: Inlining a call to an arrow function");
|
||||||
*e = Expr::Seq(SeqExpr {
|
*e = Expr::Seq(SeqExpr {
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
exprs,
|
exprs,
|
||||||
@ -460,18 +458,18 @@ where
|
|||||||
let body = f.function.body.as_ref().unwrap();
|
let body = f.function.body.as_ref().unwrap();
|
||||||
let has_decl = body.stmts.iter().any(|stmt| matches!(stmt, Stmt::Decl(..)));
|
let has_decl = body.stmts.iter().any(|stmt| matches!(stmt, Stmt::Decl(..)));
|
||||||
if has_decl {
|
if has_decl {
|
||||||
tracing::trace!("iife: [x] Found decl");
|
log_abort!("iife: [x] Found decl");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.function.is_async {
|
if f.function.is_async {
|
||||||
tracing::trace!("iife: [x] Cannot inline async fn");
|
log_abort!("iife: [x] Cannot inline async fn");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.function.is_generator {
|
if f.function.is_generator {
|
||||||
tracing::trace!("iife: [x] Cannot inline generator");
|
log_abort!("iife: [x] Cannot inline generator");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,25 +480,25 @@ where
|
|||||||
Pat::Object(..) | Pat::Array(..) | Pat::Assign(..) | Pat::Rest(..)
|
Pat::Object(..) | Pat::Array(..) | Pat::Assign(..) | Pat::Rest(..)
|
||||||
)
|
)
|
||||||
}) {
|
}) {
|
||||||
tracing::trace!("iife: [x] Found complex pattern");
|
log_abort!("iife: [x] Found complex pattern");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(i) = &f.ident {
|
if let Some(i) = &f.ident {
|
||||||
if idents_used_by(&f.function.body).contains(&i.to_id()) {
|
if idents_used_by(&f.function.body).contains(&i.to_id()) {
|
||||||
tracing::trace!("iife: [x] Recursive?");
|
log_abort!("iife: [x] Recursive?");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for arg in &call.args {
|
for arg in &call.args {
|
||||||
if arg.spread.is_some() {
|
if arg.spread.is_some() {
|
||||||
tracing::trace!("iife: [x] Found spread argument");
|
log_abort!("iife: [x] Found spread argument");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
match &*arg.expr {
|
match &*arg.expr {
|
||||||
Expr::Fn(..) | Expr::Arrow(..) => {
|
Expr::Fn(..) | Expr::Arrow(..) => {
|
||||||
tracing::trace!("iife: [x] Found callable argument");
|
log_abort!("iife: [x] Found callable argument");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -521,18 +519,16 @@ where
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if !self.can_inline_fn_like(¶m_ids, body) {
|
if !self.can_inline_fn_like(¶m_ids, body) {
|
||||||
tracing::trace!("iife: [x] Body is not inlinable");
|
log_abort!("iife: [x] Body is not inlinable");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let new = self.inline_fn_like(¶m_ids, body, &mut call.args);
|
let new = self.inline_fn_like(¶m_ids, body, &mut call.args);
|
||||||
if let Some(new) = new {
|
if let Some(new) = new {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("inline: Inlining a function call");
|
report_change!("inline: Inlining a function call");
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
dump_change_detail!("{}", dump(&new, false));
|
||||||
tracing::debug!("[Change]: {}", dump(&new, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
*e = new;
|
*e = new;
|
||||||
}
|
}
|
||||||
@ -579,9 +575,7 @@ where
|
|||||||
for pid in param_ids {
|
for pid in param_ids {
|
||||||
if let Some(usage) = self.data.vars.get(&pid.to_id()) {
|
if let Some(usage) = self.data.vars.get(&pid.to_id()) {
|
||||||
if usage.ref_count > 1 || usage.assign_count > 0 || usage.inline_prevented {
|
if usage.ref_count > 1 || usage.assign_count > 0 || usage.inline_prevented {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("iife: [x] Cannot inline because of usage of `{}`", pid);
|
||||||
tracing::trace!("iife: [x] Cannot inline because of usage of {}", pid);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -594,12 +588,10 @@ where
|
|||||||
|
|
||||||
for param in param_ids {
|
for param in param_ids {
|
||||||
if captured.contains(¶m.to_id()) {
|
if captured.contains(¶m.to_id()) {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!(
|
||||||
tracing::trace!(
|
"iife: [x] Cannot inline because of the capture of `{}`",
|
||||||
"iife: [x] Cannot inline because of the capture of {}",
|
param
|
||||||
param
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -682,7 +674,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("inline: Inlining an iife");
|
report_change!("inline: Inlining an iife");
|
||||||
|
|
||||||
let mut exprs = vec![];
|
let mut exprs = vec![];
|
||||||
|
|
||||||
@ -739,9 +731,8 @@ where
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if !vars.is_empty() {
|
if !vars.is_empty() {
|
||||||
if cfg!(feature = "debug") {
|
trace_op!("iife: Creating variables: {:?}", vars);
|
||||||
tracing::debug!("iife: Creating variables: {:?}", vars);
|
|
||||||
}
|
|
||||||
self.prepend_stmts.push(Stmt::Decl(Decl::Var(VarDecl {
|
self.prepend_stmts.push(Stmt::Decl(Decl::Var(VarDecl {
|
||||||
span: DUMMY_SP.apply_mark(self.marks.non_top_level),
|
span: DUMMY_SP.apply_mark(self.marks.non_top_level),
|
||||||
kind: VarDeclKind::Var,
|
kind: VarDeclKind::Var,
|
||||||
|
@ -30,13 +30,11 @@ where
|
|||||||
&& (!self.options.top_level() && self.options.top_retain.is_empty())
|
&& (!self.options.top_level() && self.options.top_retain.is_empty())
|
||||||
&& self.ctx.in_top_level();
|
&& self.ctx.in_top_level();
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
trace_op!(
|
||||||
tracing::trace!(
|
"inline: store_var_for_inlining({}, should_preserve = {:?})",
|
||||||
"inline: store_var_for_inlining({}, should_preserve = {:?})",
|
dump(&var.name, false),
|
||||||
dump(&var.name, false),
|
should_preserve
|
||||||
should_preserve
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.data.top.has_eval_call {
|
if self.data.top.has_eval_call {
|
||||||
return;
|
return;
|
||||||
@ -64,19 +62,15 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
if should_preserve && usage.var_kind != Some(VarDeclKind::Const) {
|
if should_preserve && usage.var_kind != Some(VarDeclKind::Const) {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!(
|
||||||
tracing::trace!(
|
"inline: [x] Preserving non-const variable `{}` because it's top-level",
|
||||||
"inline: [x] Preserving non-const variable `{}` because it's top-level",
|
dump(&var.name, false)
|
||||||
dump(&var.name, false)
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if usage.cond_init || usage.used_above_decl {
|
if usage.cond_init || usage.used_above_decl {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("inline: [x] It's cond init or used before decl",);
|
||||||
tracing::trace!("inline: [x] It's cond init or used before decl",);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,16 +91,12 @@ where
|
|||||||
}) => {
|
}) => {
|
||||||
if body.stmts.len() == 1 && matches!(&body.stmts[0], Stmt::Return(..)) {
|
if body.stmts.len() == 1 && matches!(&body.stmts[0], Stmt::Return(..)) {
|
||||||
} else {
|
} else {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("inline: [x] It's not fn-local");
|
||||||
tracing::trace!("inline: [x] It's not fn-local");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("inline: [x] It's not fn-local");
|
||||||
tracing::trace!("inline: [x] It's not fn-local");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,7 +165,7 @@ where
|
|||||||
{
|
{
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
|
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"inline: Decided to inline '{}{:?}' because it's simple",
|
"inline: Decided to inline '{}{:?}' because it's simple",
|
||||||
i.id.sym,
|
i.id.sym,
|
||||||
i.id.span.ctxt
|
i.id.span.ctxt
|
||||||
@ -189,7 +179,7 @@ where
|
|||||||
|
|
||||||
var.name.take();
|
var.name.take();
|
||||||
} else if self.options.inline != 0 || self.options.reduce_vars {
|
} else if self.options.inline != 0 || self.options.reduce_vars {
|
||||||
tracing::debug!(
|
trace_op!(
|
||||||
"inline: Decided to copy '{}{:?}' because it's simple",
|
"inline: Decided to copy '{}{:?}' because it's simple",
|
||||||
i.id.sym,
|
i.id.sym,
|
||||||
i.id.span.ctxt
|
i.id.span.ctxt
|
||||||
@ -289,7 +279,7 @@ where
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"inline: Decided to inline var '{}' because it's used only once",
|
"inline: Decided to inline var '{}' because it's used only once",
|
||||||
i.id
|
i.id
|
||||||
);
|
);
|
||||||
@ -364,7 +354,7 @@ where
|
|||||||
|
|
||||||
if let Some(usage) = self.data.vars.get(&i.to_id()) {
|
if let Some(usage) = self.data.vars.get(&i.to_id()) {
|
||||||
if !usage.reassigned() {
|
if !usage.reassigned() {
|
||||||
tracing::trace!("typeofs: Storing typeof `{}{:?}`", i.sym, i.span.ctxt);
|
trace_op!("typeofs: Storing typeof `{}{:?}`", i.sym, i.span.ctxt);
|
||||||
match &*decl {
|
match &*decl {
|
||||||
Decl::Fn(..) => {
|
Decl::Fn(..) => {
|
||||||
self.typeofs.insert(i.to_id(), js_word!("function"));
|
self.typeofs.insert(i.to_id(), js_word!("function"));
|
||||||
@ -393,45 +383,33 @@ where
|
|||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
trace_op!("inline: Trying to inline decl ({}{:?})", i.sym, i.span.ctxt);
|
||||||
tracing::trace!("inline: Trying to inline decl ({}{:?})", i.sym, i.span.ctxt);
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.options.inline == 0 && !self.options.reduce_vars {
|
if self.options.inline == 0 && !self.options.reduce_vars {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("inline: [x] Inline disabled");
|
||||||
tracing::trace!("inline: [x] Inline disabled");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self.options.top_level() && self.options.top_retain.is_empty())
|
if (!self.options.top_level() && self.options.top_retain.is_empty())
|
||||||
&& self.ctx.in_top_level()
|
&& self.ctx.in_top_level()
|
||||||
{
|
{
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("inline: [x] Top level");
|
||||||
tracing::trace!("inline: [x] Top level");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.has_noinline(decl.span()) {
|
if self.has_noinline(decl.span()) {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("inline: [x] Has noinline");
|
||||||
tracing::trace!("inline: [x] Has noinline");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respect `top_retain`
|
// Respect `top_retain`
|
||||||
if self.ctx.in_top_level() && self.options.top_retain.contains(&i.sym) {
|
if self.ctx.in_top_level() && self.options.top_retain.contains(&i.sym) {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("inline: [x] top_retain");
|
||||||
tracing::trace!("inline: [x] top_retain");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.ctx.is_exported {
|
if self.ctx.is_exported {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("inline: [x] exported");
|
||||||
tracing::trace!("inline: [x] exported");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,20 +419,16 @@ where
|
|||||||
|
|
||||||
if let Some(usage) = self.data.vars.get(&i.to_id()) {
|
if let Some(usage) = self.data.vars.get(&i.to_id()) {
|
||||||
if usage.declared_as_catch_param {
|
if usage.declared_as_catch_param {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("inline: [x] Declared as a catch parameter");
|
||||||
tracing::trace!("inline: [x] Declared as a catch parameter");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if usage.reassigned() || usage.inline_prevented {
|
if usage.reassigned() || usage.inline_prevented {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!(
|
||||||
tracing::trace!(
|
"inline: [x] reassigned = {}, inline_prevented = {}",
|
||||||
"inline: [x] reassigned = {}, inline_prevented = {}",
|
usage.reassigned(),
|
||||||
usage.reassigned(),
|
usage.inline_prevented
|
||||||
usage.inline_prevented
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -466,7 +440,7 @@ where
|
|||||||
if !UsageFinder::find(&i, body)
|
if !UsageFinder::find(&i, body)
|
||||||
&& self.is_fn_body_simple_enough_to_inline(body)
|
&& self.is_fn_body_simple_enough_to_inline(body)
|
||||||
{
|
{
|
||||||
tracing::debug!(
|
trace_op!(
|
||||||
"inline: Decided to inline function '{}{:?}' as it's very \
|
"inline: Decided to inline function '{}{:?}' as it's very \
|
||||||
simple",
|
simple",
|
||||||
f.ident.sym,
|
f.ident.sym,
|
||||||
@ -529,14 +503,14 @@ where
|
|||||||
self.changed = true;
|
self.changed = true;
|
||||||
match &decl {
|
match &decl {
|
||||||
Decl::Class(c) => {
|
Decl::Class(c) => {
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"inline: Decided to inline class `{}{:?}` as it's used only once",
|
"inline: Decided to inline class `{}{:?}` as it's used only once",
|
||||||
c.ident.sym,
|
c.ident.sym,
|
||||||
c.ident.span.ctxt
|
c.ident.span.ctxt
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Decl::Fn(f) => {
|
Decl::Fn(f) => {
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"inline: Decided to inline function `{}{:?}` as it's used only once",
|
"inline: Decided to inline function `{}{:?}` as it's used only once",
|
||||||
f.ident.sym,
|
f.ident.sym,
|
||||||
f.ident.span.ctxt
|
f.ident.span.ctxt
|
||||||
@ -561,9 +535,7 @@ where
|
|||||||
|
|
||||||
self.vars.vars_for_inlining.insert(i.to_id(), e);
|
self.vars.vars_for_inlining.insert(i.to_id(), e);
|
||||||
} else {
|
} else {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("inline: [x] Usage: {:?}", usage);
|
||||||
tracing::trace!("inline: [x] Usage: {:?}", usage);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -609,7 +581,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("inline: Replacing a variable with cheap expression");
|
report_change!("inline: Replacing a variable with cheap expression");
|
||||||
|
|
||||||
*e = *value;
|
*e = *value;
|
||||||
return;
|
return;
|
||||||
@ -630,17 +602,11 @@ where
|
|||||||
|
|
||||||
if let Some(value) = self.vars.vars_for_inlining.remove(&i.to_id()) {
|
if let Some(value) = self.vars.vars_for_inlining.remove(&i.to_id()) {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!("inline: Replacing '{}' with an expression", i);
|
||||||
"inline: Replacing '{}{:?}' with an expression",
|
|
||||||
i.sym,
|
|
||||||
i.span.ctxt
|
|
||||||
);
|
|
||||||
|
|
||||||
*e = *value;
|
*e = *value;
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("inline: [Change] {}", dump(&*e, false))
|
||||||
tracing::trace!("inline: [Change] {}", dump(&*e, false))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ where
|
|||||||
self.changed = true;
|
self.changed = true;
|
||||||
// Remove the labeled statement.
|
// Remove the labeled statement.
|
||||||
self.label = None;
|
self.label = None;
|
||||||
tracing::debug!("loops: Removing a for loop with instant break");
|
report_change!("loops: Removing a for loop with instant break");
|
||||||
self.prepend_stmts
|
self.prepend_stmts
|
||||||
.extend(f.init.take().map(|init| match init {
|
.extend(f.init.take().map(|init| match init {
|
||||||
VarDeclOrExpr::VarDecl(var) => Stmt::Decl(Decl::Var(var)),
|
VarDeclOrExpr::VarDecl(var) => Stmt::Decl(Decl::Var(var)),
|
||||||
@ -79,7 +79,7 @@ where
|
|||||||
let changed = UnreachableHandler::preserve_vars(stmt);
|
let changed = UnreachableHandler::preserve_vars(stmt);
|
||||||
self.changed |= changed;
|
self.changed |= changed;
|
||||||
if changed {
|
if changed {
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"loops: Removing unreachable while statement without side effects"
|
"loops: Removing unreachable while statement without side effects"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -87,9 +87,7 @@ where
|
|||||||
let changed = UnreachableHandler::preserve_vars(&mut w.body);
|
let changed = UnreachableHandler::preserve_vars(&mut w.body);
|
||||||
self.changed |= changed;
|
self.changed |= changed;
|
||||||
if changed {
|
if changed {
|
||||||
tracing::debug!(
|
report_change!("loops: Removing unreachable body of a while statement");
|
||||||
"loops: Removing unreachable body of a while statement"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,7 +99,7 @@ where
|
|||||||
let changed = UnreachableHandler::preserve_vars(&mut f.body);
|
let changed = UnreachableHandler::preserve_vars(&mut f.body);
|
||||||
self.changed |= changed;
|
self.changed |= changed;
|
||||||
if changed {
|
if changed {
|
||||||
tracing::debug!("loops: Removing unreachable body of a for statement");
|
report_change!("loops: Removing unreachable body of a for statement");
|
||||||
}
|
}
|
||||||
self.changed |= f.init.is_some() | f.update.is_some();
|
self.changed |= f.init.is_some() | f.update.is_some();
|
||||||
|
|
||||||
@ -122,7 +120,7 @@ where
|
|||||||
} else if let Known(true) = val {
|
} else if let Known(true) = val {
|
||||||
if purity.is_pure() {
|
if purity.is_pure() {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"loops: Removing `test` part of a for stmt as it's always true"
|
"loops: Removing `test` part of a for stmt as it's always true"
|
||||||
);
|
);
|
||||||
f.test = None;
|
f.test = None;
|
||||||
@ -151,7 +149,7 @@ where
|
|||||||
} else {
|
} else {
|
||||||
s.init = None;
|
s.init = None;
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"loops: Removed side-effect-free expressions in `init` of a for stmt"
|
"loops: Removed side-effect-free expressions in `init` of a for stmt"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ use swc_ecma_utils::{
|
|||||||
StmtLike, Type, Value,
|
StmtLike, Type, Value,
|
||||||
};
|
};
|
||||||
use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith, VisitWith};
|
use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith, VisitWith};
|
||||||
use tracing::{span, Level};
|
use tracing::{debug, span, Level};
|
||||||
use Value::Known;
|
use Value::Known;
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
@ -673,7 +673,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::debug!("Compressing array.join()");
|
report_change!("Compressing array.join()");
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*e = Expr::Lit(Lit::Str(Str {
|
*e = Expr::Lit(Lit::Str(Str {
|
||||||
@ -708,7 +708,7 @@ where
|
|||||||
if self.options.bools_as_ints || self.options.bools {
|
if self.options.bools_as_ints || self.options.bools {
|
||||||
if let Lit::Bool(v) = lit {
|
if let Lit::Bool(v) = lit {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Compressing boolean literal");
|
report_change!("Compressing boolean literal");
|
||||||
*e = Expr::Unary(UnaryExpr {
|
*e = Expr::Unary(UnaryExpr {
|
||||||
span: v.span,
|
span: v.span,
|
||||||
op: op!("!"),
|
op: op!("!"),
|
||||||
@ -751,27 +751,23 @@ where
|
|||||||
|
|
||||||
match e {
|
match e {
|
||||||
Expr::This(_) | Expr::Invalid(_) | Expr::Lit(..) => {
|
Expr::This(_) | Expr::Invalid(_) | Expr::Lit(..) => {
|
||||||
if cfg!(feature = "debug") {
|
report_change!(
|
||||||
tracing::debug!(
|
"ignore_return_value: Dropping unused expr: {}",
|
||||||
"ignore_return_value: Dropping unused expr: {}",
|
dump(&*e, false)
|
||||||
dump(&*e, false)
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Tpl(t) if t.exprs.is_empty() => {
|
Expr::Tpl(t) if t.exprs.is_empty() => {
|
||||||
if cfg!(feature = "debug") {
|
report_change!("ignore_return_value: Dropping tpl expr without expr");
|
||||||
tracing::debug!("ignore_return_value: Dropping tpl expr without expr");
|
|
||||||
}
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function expression cannot have a side effect.
|
// Function expression cannot have a side effect.
|
||||||
Expr::Fn(_) => {
|
Expr::Fn(_) => {
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"ignore_return_value: Dropping unused fn expr as it does not have any side \
|
"ignore_return_value: Dropping unused fn expr as it does not have any side \
|
||||||
effect"
|
effect"
|
||||||
);
|
);
|
||||||
@ -913,7 +909,7 @@ where
|
|||||||
_ => false,
|
_ => false,
|
||||||
} && args.is_empty() =>
|
} && args.is_empty() =>
|
||||||
{
|
{
|
||||||
tracing::debug!("ignore_return_value: Dropping a pure call");
|
report_change!("ignore_return_value: Dropping a pure call");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -1020,7 +1016,7 @@ where
|
|||||||
Expr::Array(arr) => {
|
Expr::Array(arr) => {
|
||||||
let mut exprs = vec![];
|
let mut exprs = vec![];
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("ignore_return_value: Inverting an array literal");
|
report_change!("ignore_return_value: Inverting an array literal");
|
||||||
exprs.extend(
|
exprs.extend(
|
||||||
arr.elems
|
arr.elems
|
||||||
.take()
|
.take()
|
||||||
@ -1044,7 +1040,7 @@ where
|
|||||||
Expr::Object(obj) => {
|
Expr::Object(obj) => {
|
||||||
let mut exprs = vec![];
|
let mut exprs = vec![];
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("ignore_return_value: Inverting an object literal");
|
report_change!("ignore_return_value: Inverting an object literal");
|
||||||
for prop in obj.props.take() {
|
for prop in obj.props.take() {
|
||||||
match prop {
|
match prop {
|
||||||
PropOrSpread::Spread(mut e) => {
|
PropOrSpread::Spread(mut e) => {
|
||||||
@ -1114,14 +1110,14 @@ where
|
|||||||
|
|
||||||
*arg = Box::new(processed_arg);
|
*arg = Box::new(processed_arg);
|
||||||
|
|
||||||
tracing::trace!("ignore_return_value: Preserving negated iife");
|
log_abort!("ignore_return_value: Preserving negated iife");
|
||||||
return Some(e.take());
|
return Some(e.take());
|
||||||
}
|
}
|
||||||
|
|
||||||
// `delete` is handled above
|
// `delete` is handled above
|
||||||
Expr::Unary(expr) => {
|
Expr::Unary(expr) => {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("ignore_return_value: Reducing unary ({})", expr.op);
|
report_change!("ignore_return_value: Reducing unary ({})", expr.op);
|
||||||
return self.ignore_return_value(&mut expr.arg);
|
return self.ignore_return_value(&mut expr.arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1132,7 +1128,7 @@ where
|
|||||||
op,
|
op,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
tracing::debug!("ignore_return_value: Reducing binary ({})", *op);
|
report_change!("ignore_return_value: Reducing binary ({})", *op);
|
||||||
|
|
||||||
let left = self.ignore_return_value(&mut **left).map(Box::new);
|
let left = self.ignore_return_value(&mut **left).map(Box::new);
|
||||||
let right = self.ignore_return_value(&mut **right).map(Box::new);
|
let right = self.ignore_return_value(&mut **right).map(Box::new);
|
||||||
@ -1145,7 +1141,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
Expr::Cond(cond) => {
|
Expr::Cond(cond) => {
|
||||||
tracing::trace!("ignore_return_value: Cond expr");
|
trace_op!("ignore_return_value: Cond expr");
|
||||||
|
|
||||||
self.restore_negated_iife(cond);
|
self.restore_negated_iife(cond);
|
||||||
|
|
||||||
@ -1172,12 +1168,12 @@ where
|
|||||||
span: cond.span,
|
span: cond.span,
|
||||||
test: cond.test.take(),
|
test: cond.test.take(),
|
||||||
cons: cons.unwrap_or_else(|| {
|
cons: cons.unwrap_or_else(|| {
|
||||||
tracing::debug!("ignore_return_value: Dropped `cons`");
|
report_change!("ignore_return_value: Dropped `cons`");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
undefined(cons_span)
|
undefined(cons_span)
|
||||||
}),
|
}),
|
||||||
alt: alt.unwrap_or_else(|| {
|
alt: alt.unwrap_or_else(|| {
|
||||||
tracing::debug!("ignore_return_value: Dropped `alt`");
|
report_change!("ignore_return_value: Dropped `alt`");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
undefined(alt_span)
|
undefined(alt_span)
|
||||||
}),
|
}),
|
||||||
@ -1223,7 +1219,7 @@ where
|
|||||||
|
|
||||||
// Make return type undefined.
|
// Make return type undefined.
|
||||||
if let Some(last) = exprs.last_mut() {
|
if let Some(last) = exprs.last_mut() {
|
||||||
tracing::debug!("ignore_return_value: Shifting void");
|
report_change!("ignore_return_value: Shifting void");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*last = Box::new(Expr::Unary(UnaryExpr {
|
*last = Box::new(Expr::Unary(UnaryExpr {
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
@ -1234,7 +1230,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
if exprs.is_empty() {
|
if exprs.is_empty() {
|
||||||
tracing::debug!("ignore_return_value: Dropping empty seq");
|
report_change!("ignore_return_value: Dropping empty seq");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1335,7 +1331,7 @@ where
|
|||||||
})
|
})
|
||||||
.unwrap_or(js_word!(""));
|
.unwrap_or(js_word!(""));
|
||||||
|
|
||||||
tracing::debug!("Converting call to RegExp into a regexp literal");
|
report_change!("Converting call to RegExp into a regexp literal");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*e = Expr::Lit(Lit::Regex(Regex {
|
*e = Expr::Lit(Lit::Regex(Regex {
|
||||||
span,
|
span,
|
||||||
@ -1403,19 +1399,17 @@ where
|
|||||||
}) {
|
}) {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
report_change!("Merging variable declarations");
|
||||||
tracing::debug!("Merging variable declarations");
|
dump_change_detail!(
|
||||||
tracing::trace!(
|
"[Before]: {}",
|
||||||
"[Before]: {}",
|
dump(
|
||||||
dump(
|
&BlockStmt {
|
||||||
&BlockStmt {
|
span: DUMMY_SP,
|
||||||
span: DUMMY_SP,
|
stmts: stmts.clone()
|
||||||
stmts: stmts.clone()
|
},
|
||||||
},
|
false
|
||||||
false
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
);
|
||||||
|
|
||||||
let orig = take(stmts);
|
let orig = take(stmts);
|
||||||
let mut new = Vec::with_capacity(orig.len());
|
let mut new = Vec::with_capacity(orig.len());
|
||||||
@ -1448,18 +1442,17 @@ where
|
|||||||
|
|
||||||
new.extend(var_decl.take().map(Decl::Var).map(Stmt::Decl));
|
new.extend(var_decl.take().map(Decl::Var).map(Stmt::Decl));
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
dump_change_detail!(
|
||||||
tracing::trace!(
|
"[Change] merged: {}",
|
||||||
"[Change] merged: {}",
|
dump(
|
||||||
dump(
|
&BlockStmt {
|
||||||
&BlockStmt {
|
span: DUMMY_SP,
|
||||||
span: DUMMY_SP,
|
stmts: new.clone()
|
||||||
stmts: new.clone()
|
},
|
||||||
},
|
false
|
||||||
false
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
);
|
||||||
|
|
||||||
*stmts = new
|
*stmts = new
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1485,7 +1478,7 @@ where
|
|||||||
.iter()
|
.iter()
|
||||||
.all(|stmt| !matches!(stmt, Stmt::Decl(..)))
|
.all(|stmt| !matches!(stmt, Stmt::Decl(..)))
|
||||||
{
|
{
|
||||||
tracing::debug!("optimizer: Removing nested block");
|
report_change!("optimizer: Removing nested block");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
bs.stmts = block.stmts.take();
|
bs.stmts = block.stmts.take();
|
||||||
}
|
}
|
||||||
@ -1506,7 +1499,7 @@ where
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
tracing::debug!("optimizer: Unwrapping a block with variable statements");
|
report_change!("optimizer: Unwrapping a block with variable statements");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*s = bs.stmts[0].take();
|
*s = bs.stmts[0].take();
|
||||||
return;
|
return;
|
||||||
@ -1516,7 +1509,7 @@ where
|
|||||||
if let Stmt::Block(block) = &stmt {
|
if let Stmt::Block(block) = &stmt {
|
||||||
if block.stmts.is_empty() {
|
if block.stmts.is_empty() {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("optimizer: Removing empty block");
|
report_change!("optimizer: Removing empty block");
|
||||||
*stmt = Stmt::Empty(EmptyStmt { span: DUMMY_SP });
|
*stmt = Stmt::Empty(EmptyStmt { span: DUMMY_SP });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1526,12 +1519,12 @@ where
|
|||||||
match &bs.stmts[0] {
|
match &bs.stmts[0] {
|
||||||
Stmt::Expr(..) | Stmt::If(..) => {
|
Stmt::Expr(..) | Stmt::If(..) => {
|
||||||
*s = bs.stmts[0].take();
|
*s = bs.stmts[0].take();
|
||||||
tracing::debug!("optimizer: Unwrapping block stmt");
|
report_change!("optimizer: Unwrapping block stmt");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
}
|
}
|
||||||
Stmt::Decl(Decl::Fn(..)) if !self.ctx.in_strict => {
|
Stmt::Decl(Decl::Fn(..)) if !self.ctx.in_strict => {
|
||||||
*s = bs.stmts[0].take();
|
*s = bs.stmts[0].take();
|
||||||
tracing::debug!("optimizer: Unwrapping block stmt in non strcit mode");
|
report_change!("optimizer: Unwrapping block stmt in non strcit mode");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -1602,7 +1595,7 @@ where
|
|||||||
if stmt.alt.is_none() {
|
if stmt.alt.is_none() {
|
||||||
if let Stmt::Expr(cons) = &mut *stmt.cons {
|
if let Stmt::Expr(cons) = &mut *stmt.cons {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Converting if statement to a form `test && cons`");
|
report_change!("Converting if statement to a form `test && cons`");
|
||||||
*s = Stmt::Expr(ExprStmt {
|
*s = Stmt::Expr(ExprStmt {
|
||||||
span: stmt.span,
|
span: stmt.span,
|
||||||
expr: Box::new(stmt.test.take().make_bin(op!("&&"), *cons.expr.take())),
|
expr: Box::new(stmt.test.take().make_bin(op!("&&"), *cons.expr.take())),
|
||||||
@ -1637,9 +1630,8 @@ where
|
|||||||
}
|
}
|
||||||
BlockStmtOrExpr::Expr(v) => {
|
BlockStmtOrExpr::Expr(v) => {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
if cfg!(feature = "debug") {
|
report_change!("Converting a body of an arrow expression to BlockStmt");
|
||||||
tracing::debug!("Converting a body of an arrow expression to BlockStmt");
|
|
||||||
}
|
|
||||||
stmts.push(Stmt::Return(ReturnStmt {
|
stmts.push(Stmt::Return(ReturnStmt {
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
arg: Some(v.take()),
|
arg: Some(v.take()),
|
||||||
@ -1772,7 +1764,7 @@ where
|
|||||||
raw: None,
|
raw: None,
|
||||||
})));
|
})));
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("injecting zero to preserve `this` in call");
|
report_change!("injecting zero to preserve `this` in call");
|
||||||
|
|
||||||
*callee = Box::new(Expr::Seq(SeqExpr {
|
*callee = Box::new(Expr::Seq(SeqExpr {
|
||||||
span: callee.span(),
|
span: callee.span(),
|
||||||
@ -1925,7 +1917,7 @@ where
|
|||||||
if let Expr::Bin(bin) = e {
|
if let Expr::Bin(bin) = e {
|
||||||
let expr = self.optimize_lit_cmp(bin);
|
let expr = self.optimize_lit_cmp(bin);
|
||||||
if let Some(expr) = expr {
|
if let Some(expr) = expr {
|
||||||
tracing::debug!("Optimizing: Literal comparison");
|
report_change!("Optimizing: Literal comparison");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*e = expr;
|
*e = expr;
|
||||||
}
|
}
|
||||||
@ -2016,9 +2008,7 @@ where
|
|||||||
}
|
}
|
||||||
let expr = self.ignore_return_value(&mut n.expr);
|
let expr = self.ignore_return_value(&mut n.expr);
|
||||||
n.expr = expr.map(Box::new).unwrap_or_else(|| {
|
n.expr = expr.map(Box::new).unwrap_or_else(|| {
|
||||||
if cfg!(feature = "debug") {
|
report_change!("visit_mut_expr_stmt: Dropped an expression statement");
|
||||||
tracing::debug!("visit_mut_expr_stmt: Dropped an expression statement");
|
|
||||||
}
|
|
||||||
undefined(DUMMY_SP)
|
undefined(DUMMY_SP)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -2040,6 +2030,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_fn_decl(&mut self, f: &mut FnDecl) {
|
fn visit_mut_fn_decl(&mut self, f: &mut FnDecl) {
|
||||||
self.functions
|
self.functions
|
||||||
.entry(f.ident.to_id())
|
.entry(f.ident.to_id())
|
||||||
@ -2049,10 +2040,14 @@ where
|
|||||||
self.drop_unused_params(&mut f.function.params);
|
self.drop_unused_params(&mut f.function.params);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ctx = Ctx { ..self.ctx };
|
let ctx = Ctx {
|
||||||
|
top_level: false,
|
||||||
|
..self.ctx
|
||||||
|
};
|
||||||
f.visit_mut_children_with(&mut *self.with_ctx(ctx));
|
f.visit_mut_children_with(&mut *self.with_ctx(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_fn_expr(&mut self, e: &mut FnExpr) {
|
fn visit_mut_fn_expr(&mut self, e: &mut FnExpr) {
|
||||||
if let Some(ident) = &e.ident {
|
if let Some(ident) = &e.ident {
|
||||||
self.functions
|
self.functions
|
||||||
@ -2067,6 +2062,7 @@ where
|
|||||||
e.visit_mut_children_with(self);
|
e.visit_mut_children_with(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_for_in_stmt(&mut self, n: &mut ForInStmt) {
|
fn visit_mut_for_in_stmt(&mut self, n: &mut ForInStmt) {
|
||||||
n.right.visit_mut_with(self);
|
n.right.visit_mut_with(self);
|
||||||
|
|
||||||
@ -2087,6 +2083,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_for_of_stmt(&mut self, n: &mut ForOfStmt) {
|
fn visit_mut_for_of_stmt(&mut self, n: &mut ForOfStmt) {
|
||||||
n.right.visit_mut_with(self);
|
n.right.visit_mut_with(self);
|
||||||
|
|
||||||
@ -2107,6 +2104,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_for_stmt(&mut self, s: &mut ForStmt) {
|
fn visit_mut_for_stmt(&mut self, s: &mut ForStmt) {
|
||||||
let ctx = Ctx {
|
let ctx = Ctx {
|
||||||
executed_multiple_time: true,
|
executed_multiple_time: true,
|
||||||
@ -2149,6 +2147,7 @@ where
|
|||||||
in_fn_like: true,
|
in_fn_like: true,
|
||||||
scope: n.span.ctxt,
|
scope: n.span.ctxt,
|
||||||
can_inline_arguments: true,
|
can_inline_arguments: true,
|
||||||
|
top_level: false,
|
||||||
|
|
||||||
..self.ctx
|
..self.ctx
|
||||||
};
|
};
|
||||||
@ -2188,6 +2187,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_if_stmt(&mut self, n: &mut IfStmt) {
|
fn visit_mut_if_stmt(&mut self, n: &mut IfStmt) {
|
||||||
n.test.visit_mut_with(self);
|
n.test.visit_mut_with(self);
|
||||||
|
|
||||||
@ -2207,6 +2207,7 @@ where
|
|||||||
self.merge_else_if(n);
|
self.merge_else_if(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_labeled_stmt(&mut self, n: &mut LabeledStmt) {
|
fn visit_mut_labeled_stmt(&mut self, n: &mut LabeledStmt) {
|
||||||
let ctx = Ctx {
|
let ctx = Ctx {
|
||||||
stmt_labelled: true,
|
stmt_labelled: true,
|
||||||
@ -2223,6 +2224,7 @@ where
|
|||||||
self.label = old_label;
|
self.label = old_label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_member_expr(&mut self, n: &mut MemberExpr) {
|
fn visit_mut_member_expr(&mut self, n: &mut MemberExpr) {
|
||||||
{
|
{
|
||||||
let ctx = Ctx {
|
let ctx = Ctx {
|
||||||
@ -2271,6 +2273,7 @@ where
|
|||||||
drop_invalid_stmts(stmts);
|
drop_invalid_stmts(stmts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_new_expr(&mut self, n: &mut NewExpr) {
|
fn visit_mut_new_expr(&mut self, n: &mut NewExpr) {
|
||||||
{
|
{
|
||||||
let ctx = Ctx {
|
let ctx = Ctx {
|
||||||
@ -2289,16 +2292,18 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_opt_stmt(&mut self, s: &mut Option<Box<Stmt>>) {
|
fn visit_mut_opt_stmt(&mut self, s: &mut Option<Box<Stmt>>) {
|
||||||
s.visit_mut_children_with(self);
|
s.visit_mut_children_with(self);
|
||||||
|
|
||||||
if let Some(Stmt::Empty(..)) = s.as_deref() {
|
if let Some(Stmt::Empty(..)) = s.as_deref() {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("misc: Removing empty statement");
|
report_change!("misc: Removing empty statement");
|
||||||
*s = None;
|
*s = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_opt_var_decl_or_expr(&mut self, n: &mut Option<VarDeclOrExpr>) {
|
fn visit_mut_opt_var_decl_or_expr(&mut self, n: &mut Option<VarDeclOrExpr>) {
|
||||||
n.visit_mut_children_with(self);
|
n.visit_mut_children_with(self);
|
||||||
|
|
||||||
@ -2321,6 +2326,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_param(&mut self, n: &mut Param) {
|
fn visit_mut_param(&mut self, n: &mut Param) {
|
||||||
let ctx = Ctx {
|
let ctx = Ctx {
|
||||||
var_kind: None,
|
var_kind: None,
|
||||||
@ -2338,6 +2344,7 @@ where
|
|||||||
n.retain(|p| !p.pat.is_invalid());
|
n.retain(|p| !p.pat.is_invalid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_prop(&mut self, n: &mut Prop) {
|
fn visit_mut_prop(&mut self, n: &mut Prop) {
|
||||||
n.visit_mut_children_with(self);
|
n.visit_mut_children_with(self);
|
||||||
|
|
||||||
@ -2358,6 +2365,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_return_stmt(&mut self, n: &mut ReturnStmt) {
|
fn visit_mut_return_stmt(&mut self, n: &mut ReturnStmt) {
|
||||||
n.visit_mut_children_with(self);
|
n.visit_mut_children_with(self);
|
||||||
|
|
||||||
@ -2533,7 +2541,7 @@ where
|
|||||||
let text = dump(&*s, false);
|
let text = dump(&*s, false);
|
||||||
|
|
||||||
if text.lines().count() < 10 {
|
if text.lines().count() < 10 {
|
||||||
tracing::debug!("after: visit_mut_children_with: {}", text);
|
debug!("after: visit_mut_children_with: {}", text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2555,7 +2563,7 @@ where
|
|||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
tracing::debug!("Removing 'use strict'");
|
report_change!("Removing 'use strict'");
|
||||||
*s = Stmt::Empty(EmptyStmt { span: DUMMY_SP });
|
*s = Stmt::Empty(EmptyStmt { span: DUMMY_SP });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2566,10 +2574,8 @@ where
|
|||||||
|
|
||||||
if can_be_removed {
|
if can_be_removed {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("unused: Dropping an expression without side effect");
|
report_change!("unused: Dropping an expression without side effect");
|
||||||
if cfg!(feature = "debug") {
|
dump_change_detail!("unused: Dropping \n{}\n", dump(&*expr, false));
|
||||||
tracing::trace!("unused: [Change] Dropping \n{}\n", dump(&*expr, false));
|
|
||||||
}
|
|
||||||
*s = Stmt::Empty(EmptyStmt { span: DUMMY_SP });
|
*s = Stmt::Empty(EmptyStmt { span: DUMMY_SP });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2619,7 +2625,7 @@ where
|
|||||||
let text = dump(&*s, false);
|
let text = dump(&*s, false);
|
||||||
|
|
||||||
if text.lines().count() < 10 {
|
if text.lines().count() < 10 {
|
||||||
tracing::debug!("after: visit_mut_stmt: {}", text);
|
debug!("after: visit_mut_stmt: {}", text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2678,6 +2684,7 @@ where
|
|||||||
s.visit_mut_children_with(self);
|
s.visit_mut_children_with(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_super_prop_expr(&mut self, n: &mut SuperPropExpr) {
|
fn visit_mut_super_prop_expr(&mut self, n: &mut SuperPropExpr) {
|
||||||
if let SuperProp::Computed(c) = &mut n.prop {
|
if let SuperProp::Computed(c) = &mut n.prop {
|
||||||
let ctx = Ctx {
|
let ctx = Ctx {
|
||||||
@ -2689,12 +2696,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_switch_cases(&mut self, n: &mut Vec<SwitchCase>) {
|
fn visit_mut_switch_cases(&mut self, n: &mut Vec<SwitchCase>) {
|
||||||
n.visit_mut_children_with(self);
|
n.visit_mut_children_with(self);
|
||||||
|
|
||||||
self.optimize_switch_cases(n);
|
self.optimize_switch_cases(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_switch_stmt(&mut self, n: &mut SwitchStmt) {
|
fn visit_mut_switch_stmt(&mut self, n: &mut SwitchStmt) {
|
||||||
n.discriminant.visit_mut_with(self);
|
n.discriminant.visit_mut_with(self);
|
||||||
|
|
||||||
@ -2704,18 +2713,21 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// We don't optimize [Tpl] contained in [TaggedTpl].
|
/// We don't optimize [Tpl] contained in [TaggedTpl].
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_tagged_tpl(&mut self, n: &mut TaggedTpl) {
|
fn visit_mut_tagged_tpl(&mut self, n: &mut TaggedTpl) {
|
||||||
n.tag.visit_mut_with(self);
|
n.tag.visit_mut_with(self);
|
||||||
|
|
||||||
n.tpl.exprs.visit_mut_with(self);
|
n.tpl.exprs.visit_mut_with(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_throw_stmt(&mut self, n: &mut ThrowStmt) {
|
fn visit_mut_throw_stmt(&mut self, n: &mut ThrowStmt) {
|
||||||
n.visit_mut_children_with(self);
|
n.visit_mut_children_with(self);
|
||||||
|
|
||||||
self.optimize_in_fn_termination(&mut n.arg);
|
self.optimize_in_fn_termination(&mut n.arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_tpl(&mut self, n: &mut Tpl) {
|
fn visit_mut_tpl(&mut self, n: &mut Tpl) {
|
||||||
debug_assert_eq!(n.exprs.len() + 1, n.quasis.len());
|
debug_assert_eq!(n.exprs.len() + 1, n.quasis.len());
|
||||||
|
|
||||||
@ -2733,6 +2745,7 @@ where
|
|||||||
.for_each(|expr| self.optimize_expr_in_str_ctx(&mut **expr));
|
.for_each(|expr| self.optimize_expr_in_str_ctx(&mut **expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_try_stmt(&mut self, n: &mut TryStmt) {
|
fn visit_mut_try_stmt(&mut self, n: &mut TryStmt) {
|
||||||
let ctx = Ctx {
|
let ctx = Ctx {
|
||||||
in_try_block: true,
|
in_try_block: true,
|
||||||
@ -2745,6 +2758,7 @@ where
|
|||||||
n.finalizer.visit_mut_with(self);
|
n.finalizer.visit_mut_with(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_unary_expr(&mut self, n: &mut UnaryExpr) {
|
fn visit_mut_unary_expr(&mut self, n: &mut UnaryExpr) {
|
||||||
let ctx = Ctx {
|
let ctx = Ctx {
|
||||||
in_bang_arg: n.op == op!("!"),
|
in_bang_arg: n.op == op!("!"),
|
||||||
@ -2760,7 +2774,7 @@ where
|
|||||||
Expr::Lit(Lit::Num(..)) => {}
|
Expr::Lit(Lit::Num(..)) => {}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
tracing::debug!("Ignoring arg of `void`");
|
report_change!("Ignoring arg of `void`");
|
||||||
let arg = self.ignore_return_value(&mut n.arg);
|
let arg = self.ignore_return_value(&mut n.arg);
|
||||||
|
|
||||||
n.arg = Box::new(arg.unwrap_or_else(|| make_number(DUMMY_SP, 0.0)));
|
n.arg = Box::new(arg.unwrap_or_else(|| make_number(DUMMY_SP, 0.0)));
|
||||||
@ -2769,6 +2783,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_update_expr(&mut self, n: &mut UpdateExpr) {
|
fn visit_mut_update_expr(&mut self, n: &mut UpdateExpr) {
|
||||||
let ctx = Ctx {
|
let ctx = Ctx {
|
||||||
is_update_arg: true,
|
is_update_arg: true,
|
||||||
@ -2778,6 +2793,7 @@ where
|
|||||||
n.visit_mut_children_with(&mut *self.with_ctx(ctx));
|
n.visit_mut_children_with(&mut *self.with_ctx(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_var_decl(&mut self, n: &mut VarDecl) {
|
fn visit_mut_var_decl(&mut self, n: &mut VarDecl) {
|
||||||
{
|
{
|
||||||
let ctx = Ctx {
|
let ctx = Ctx {
|
||||||
@ -2795,7 +2811,7 @@ where
|
|||||||
if let Some(e) = &var.init {
|
if let Some(e) = &var.init {
|
||||||
if is_pure_undefined(e) {
|
if is_pure_undefined(e) {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"Dropping explicit initializer which evaluates to `undefined`"
|
"Dropping explicit initializer which evaluates to `undefined`"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2806,6 +2822,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_var_declarator(&mut self, var: &mut VarDeclarator) {
|
fn visit_mut_var_declarator(&mut self, var: &mut VarDeclarator) {
|
||||||
var.name.visit_mut_with(self);
|
var.name.visit_mut_with(self);
|
||||||
|
|
||||||
@ -2817,6 +2834,7 @@ where
|
|||||||
self.store_var_for_prop_hoisting(var);
|
self.store_var_for_prop_hoisting(var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_var_declarators(&mut self, vars: &mut Vec<VarDeclarator>) {
|
fn visit_mut_var_declarators(&mut self, vars: &mut Vec<VarDeclarator>) {
|
||||||
vars.retain_mut(|var| {
|
vars.retain_mut(|var| {
|
||||||
let had_init = var.init.is_some();
|
let had_init = var.init.is_some();
|
||||||
@ -2950,6 +2968,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_while_stmt(&mut self, n: &mut WhileStmt) {
|
fn visit_mut_while_stmt(&mut self, n: &mut WhileStmt) {
|
||||||
{
|
{
|
||||||
let ctx = Ctx {
|
let ctx = Ctx {
|
||||||
@ -2960,6 +2979,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
|
||||||
fn visit_mut_yield_expr(&mut self, n: &mut YieldExpr) {
|
fn visit_mut_yield_expr(&mut self, n: &mut YieldExpr) {
|
||||||
n.visit_mut_children_with(self);
|
n.visit_mut_children_with(self);
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ where
|
|||||||
if e.op == op!("===") || e.op == op!("!==") {
|
if e.op == op!("===") || e.op == op!("!==") {
|
||||||
if (e.left.is_ident() || e.left.is_member()) && e.left.eq_ignore_span(&e.right) {
|
if (e.left.is_ident() || e.left.is_member()) && e.left.eq_ignore_span(&e.right) {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Reducing comparison of same variable ({})", e.op);
|
report_change!("Reducing comparison of same variable ({})", e.op);
|
||||||
|
|
||||||
e.op = if e.op == op!("===") {
|
e.op = if e.op == op!("===") {
|
||||||
op!("==")
|
op!("==")
|
||||||
@ -68,7 +68,7 @@ where
|
|||||||
if lt == rt {
|
if lt == rt {
|
||||||
e.op = op!("==");
|
e.op = op!("==");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"Reduced `===` to `==` because types of operands are identical"
|
"Reduced `===` to `==` because types of operands are identical"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -99,19 +99,19 @@ where
|
|||||||
(Type::Num, Type::Num) => {
|
(Type::Num, Type::Num) => {
|
||||||
let l = n.left.as_number().opt()?;
|
let l = n.left.as_number().opt()?;
|
||||||
let r = n.right.as_number().opt()?;
|
let r = n.right.as_number().opt()?;
|
||||||
tracing::debug!("Optimizing: literal comparison => num");
|
report_change!("Optimizing: literal comparison => num");
|
||||||
return make_lit_bool(l == r);
|
return make_lit_bool(l == r);
|
||||||
}
|
}
|
||||||
(Type::Str, Type::Str) => {
|
(Type::Str, Type::Str) => {
|
||||||
let l = &n.left.as_string().opt()?;
|
let l = &n.left.as_string().opt()?;
|
||||||
let r = &n.right.as_string().opt()?;
|
let r = &n.right.as_string().opt()?;
|
||||||
tracing::debug!("Optimizing: literal comparison => str");
|
report_change!("Optimizing: literal comparison => str");
|
||||||
return make_lit_bool(l == r);
|
return make_lit_bool(l == r);
|
||||||
}
|
}
|
||||||
(_, _) => {
|
(_, _) => {
|
||||||
let l = n.left.as_pure_bool().opt()?;
|
let l = n.left.as_pure_bool().opt()?;
|
||||||
let r = n.right.as_pure_bool().opt()?;
|
let r = n.right.as_pure_bool().opt()?;
|
||||||
tracing::debug!("Optimizing: literal comparison => bool");
|
report_change!("Optimizing: literal comparison => bool");
|
||||||
return make_lit_bool(l == r);
|
return make_lit_bool(l == r);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -148,7 +148,7 @@ where
|
|||||||
| Expr::Bin(BinExpr { op: op!(">"), .. }) => {
|
| Expr::Bin(BinExpr { op: op!(">"), .. }) => {
|
||||||
if let Known(Type::Bool) = arg.get_type() {
|
if let Known(Type::Bool) = arg.get_type() {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Optimizing: `!!expr` => `expr`");
|
report_change!("Optimizing: `!!expr` => `expr`");
|
||||||
*e = *arg.take();
|
*e = *arg.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,7 +230,7 @@ where
|
|||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
tracing::debug!("Compressing: `e = 3 & e` => `e &= 3`");
|
report_change!("Compressing: `e = 3 & e` => `e &= 3`");
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
e.op = op;
|
e.op = op;
|
||||||
@ -290,13 +290,13 @@ where
|
|||||||
|
|
||||||
if rb {
|
if rb {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Optimizing: e && true => !!e");
|
report_change!("Optimizing: e && true => !!e");
|
||||||
|
|
||||||
self.negate_twice(&mut bin.left, false);
|
self.negate_twice(&mut bin.left, false);
|
||||||
*e = *bin.left.take();
|
*e = *bin.left.take();
|
||||||
} else {
|
} else {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Optimizing: e && false => e");
|
report_change!("Optimizing: e && false => e");
|
||||||
|
|
||||||
*e = *bin.left.take();
|
*e = *bin.left.take();
|
||||||
}
|
}
|
||||||
@ -310,7 +310,7 @@ where
|
|||||||
|
|
||||||
if !rb {
|
if !rb {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Optimizing: e || false => !!e");
|
report_change!("Optimizing: e || false => !!e");
|
||||||
|
|
||||||
self.negate_twice(&mut bin.left, false);
|
self.negate_twice(&mut bin.left, false);
|
||||||
*e = *bin.left.take();
|
*e = *bin.left.take();
|
||||||
@ -370,7 +370,7 @@ where
|
|||||||
|
|
||||||
match l {
|
match l {
|
||||||
Expr::Lit(Lit::Null(..)) => {
|
Expr::Lit(Lit::Null(..)) => {
|
||||||
tracing::debug!("Removing null from lhs of ??");
|
report_change!("Removing null from lhs of ??");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*e = r.take();
|
*e = r.take();
|
||||||
}
|
}
|
||||||
@ -379,7 +379,7 @@ where
|
|||||||
| Expr::Lit(Lit::BigInt(..))
|
| Expr::Lit(Lit::BigInt(..))
|
||||||
| Expr::Lit(Lit::Bool(..))
|
| Expr::Lit(Lit::Bool(..))
|
||||||
| Expr::Lit(Lit::Regex(..)) => {
|
| Expr::Lit(Lit::Regex(..)) => {
|
||||||
tracing::debug!("Removing rhs of ?? as lhs cannot be null nor undefined");
|
report_change!("Removing rhs of ?? as lhs cannot be null nor undefined");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*e = l.take();
|
*e = l.take();
|
||||||
}
|
}
|
||||||
@ -403,7 +403,7 @@ where
|
|||||||
match &**arg {
|
match &**arg {
|
||||||
Expr::Ident(arg) => {
|
Expr::Ident(arg) => {
|
||||||
if let Some(value) = self.typeofs.get(&arg.to_id()).cloned() {
|
if let Some(value) = self.typeofs.get(&arg.to_id()).cloned() {
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"Converting typeof of variable to literal as we know the value"
|
"Converting typeof of variable to literal as we know the value"
|
||||||
);
|
);
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
@ -416,7 +416,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
Expr::Arrow(..) | Expr::Fn(..) => {
|
Expr::Arrow(..) | Expr::Fn(..) => {
|
||||||
tracing::debug!("Converting typeof to 'function' as we know the value");
|
report_change!("Converting typeof to 'function' as we know the value");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*e = Expr::Lit(Lit::Str(Str {
|
*e = Expr::Lit(Lit::Str(Str {
|
||||||
span: *span,
|
span: *span,
|
||||||
@ -426,7 +426,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
Expr::Array(..) | Expr::Object(..) => {
|
Expr::Array(..) | Expr::Object(..) => {
|
||||||
tracing::debug!("Converting typeof to 'object' as we know the value");
|
report_change!("Converting typeof to 'object' as we know the value");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*e = Expr::Lit(Lit::Str(Str {
|
*e = Expr::Lit(Lit::Str(Str {
|
||||||
span: *span,
|
span: *span,
|
||||||
|
@ -139,7 +139,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::debug!("sequences: Compressing statements as a sequences");
|
report_change!("sequences: Compressing statements as a sequences");
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
let mut exprs = vec![];
|
let mut exprs = vec![];
|
||||||
@ -415,7 +415,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"sequences: Splitted a sequence expression to multiple expression statements"
|
"sequences: Splitted a sequence expression to multiple expression statements"
|
||||||
);
|
);
|
||||||
*stmts = new_stmts;
|
*stmts = new_stmts;
|
||||||
@ -449,7 +449,7 @@ where
|
|||||||
if !can_work {
|
if !can_work {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tracing::debug!("sequences: Lifting");
|
report_change!("sequences: Lifting");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,7 +526,7 @@ where
|
|||||||
if lhs.sym == last_id.sym && lhs.span.ctxt == last_id.span.ctxt {
|
if lhs.sym == last_id.sym && lhs.span.ctxt == last_id.span.ctxt {
|
||||||
e.exprs.pop();
|
e.exprs.pop();
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("sequences: Shifting assignment");
|
report_change!("sequences: Shifting assignment");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -548,7 +548,7 @@ where
|
|||||||
if let Some(last) = e.exprs.last() {
|
if let Some(last) = e.exprs.last() {
|
||||||
if is_pure_undefined(last) {
|
if is_pure_undefined(last) {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("sequences: Shifting void");
|
report_change!("sequences: Shifting void");
|
||||||
|
|
||||||
e.exprs.pop();
|
e.exprs.pop();
|
||||||
let last = e.exprs.last_mut().unwrap();
|
let last = e.exprs.last_mut().unwrap();
|
||||||
@ -601,16 +601,12 @@ where
|
|||||||
T: ModuleItemExt,
|
T: ModuleItemExt,
|
||||||
{
|
{
|
||||||
if !self.options.sequences() && !self.options.collapse_vars {
|
if !self.options.sequences() && !self.options.collapse_vars {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("sequences: [x] Disabled");
|
||||||
tracing::trace!("sequences: [x] Disabled");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.ctx.in_top_level() && !self.options.top_level() {
|
if self.ctx.in_top_level() && !self.options.top_level() {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("sequences: [x] Top level");
|
||||||
tracing::trace!("sequences: [x] Top level");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1033,19 +1029,19 @@ where
|
|||||||
Expr::Update(..) | Expr::Arrow(..) | Expr::Fn(..) => return Ok(false),
|
Expr::Update(..) | Expr::Arrow(..) | Expr::Fn(..) => return Ok(false),
|
||||||
|
|
||||||
Expr::Cond(b) => {
|
Expr::Cond(b) => {
|
||||||
tracing::trace!("seq: Try test of cond");
|
trace_op!("seq: Try test of cond");
|
||||||
return self.merge_sequential_expr(a, &mut *b.test);
|
return self.merge_sequential_expr(a, &mut *b.test);
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Unary(b) => {
|
Expr::Unary(b) => {
|
||||||
tracing::trace!("seq: Try arg of unary");
|
trace_op!("seq: Try arg of unary");
|
||||||
return self.merge_sequential_expr(a, &mut b.arg);
|
return self.merge_sequential_expr(a, &mut b.arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Bin(BinExpr {
|
Expr::Bin(BinExpr {
|
||||||
op, left, right, ..
|
op, left, right, ..
|
||||||
}) => {
|
}) => {
|
||||||
tracing::trace!("seq: Try left of bin");
|
trace_op!("seq: Try left of bin");
|
||||||
if self.merge_sequential_expr(a, &mut **left)? {
|
if self.merge_sequential_expr(a, &mut **left)? {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
@ -1059,12 +1055,12 @@ where
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::trace!("seq: Try right of bin");
|
trace_op!("seq: Try right of bin");
|
||||||
return self.merge_sequential_expr(a, &mut **right);
|
return self.merge_sequential_expr(a, &mut **right);
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Member(MemberExpr { obj, prop, .. }) if !prop.is_computed() => {
|
Expr::Member(MemberExpr { obj, prop, .. }) if !prop.is_computed() => {
|
||||||
tracing::trace!("seq: Try object of member");
|
trace_op!("seq: Try object of member");
|
||||||
return self.merge_sequential_expr(a, &mut **obj);
|
return self.merge_sequential_expr(a, &mut **obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1073,7 +1069,7 @@ where
|
|||||||
prop: MemberProp::Computed(c),
|
prop: MemberProp::Computed(c),
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
tracing::trace!("seq: Try object of member (computed)");
|
trace_op!("seq: Try object of member (computed)");
|
||||||
if self.merge_sequential_expr(a, &mut **obj)? {
|
if self.merge_sequential_expr(a, &mut **obj)? {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
@ -1082,7 +1078,7 @@ where
|
|||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::trace!("seq: Try prop of member (computed)");
|
trace_op!("seq: Try prop of member (computed)");
|
||||||
return self.merge_sequential_expr(a, &mut c.expr);
|
return self.merge_sequential_expr(a, &mut c.expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1090,14 +1086,14 @@ where
|
|||||||
prop: SuperProp::Computed(c),
|
prop: SuperProp::Computed(c),
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
tracing::trace!("seq: Try prop of member (computed)");
|
trace_op!("seq: Try prop of member (computed)");
|
||||||
return self.merge_sequential_expr(a, &mut c.expr);
|
return self.merge_sequential_expr(a, &mut c.expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Assign(b @ AssignExpr { op: op!("="), .. }) => {
|
Expr::Assign(b @ AssignExpr { op: op!("="), .. }) => {
|
||||||
match &mut b.left {
|
match &mut b.left {
|
||||||
PatOrExpr::Expr(b_left) => {
|
PatOrExpr::Expr(b_left) => {
|
||||||
tracing::trace!("seq: Try lhs of assign");
|
trace_op!("seq: Try lhs of assign");
|
||||||
if self.merge_sequential_expr(a, &mut **b_left)? {
|
if self.merge_sequential_expr(a, &mut **b_left)? {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
@ -1112,7 +1108,7 @@ where
|
|||||||
}
|
}
|
||||||
PatOrExpr::Pat(b_left) => match &mut **b_left {
|
PatOrExpr::Pat(b_left) => match &mut **b_left {
|
||||||
Pat::Expr(b_left) => {
|
Pat::Expr(b_left) => {
|
||||||
tracing::trace!("seq: Try lhs of assign");
|
trace_op!("seq: Try lhs of assign");
|
||||||
if self.merge_sequential_expr(a, &mut **b_left)? {
|
if self.merge_sequential_expr(a, &mut **b_left)? {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
@ -1133,7 +1129,7 @@ where
|
|||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::trace!("seq: Try rhs of assign");
|
trace_op!("seq: Try rhs of assign");
|
||||||
return self.merge_sequential_expr(a, &mut b.right);
|
return self.merge_sequential_expr(a, &mut b.right);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1152,7 +1148,7 @@ where
|
|||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::trace!("seq: Try rhs of assign with op");
|
trace_op!("seq: Try rhs of assign with op");
|
||||||
return self.merge_sequential_expr(a, &mut b.right);
|
return self.merge_sequential_expr(a, &mut b.right);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1160,7 +1156,7 @@ where
|
|||||||
for elem in &mut b.elems {
|
for elem in &mut b.elems {
|
||||||
match elem {
|
match elem {
|
||||||
Some(elem) => {
|
Some(elem) => {
|
||||||
tracing::trace!("seq: Try element of array");
|
trace_op!("seq: Try element of array");
|
||||||
if self.merge_sequential_expr(a, &mut elem.expr)? {
|
if self.merge_sequential_expr(a, &mut elem.expr)? {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
@ -1183,7 +1179,7 @@ where
|
|||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
let is_this_undefined = b_callee.is_ident();
|
let is_this_undefined = b_callee.is_ident();
|
||||||
tracing::trace!("seq: Try callee of call");
|
trace_op!("seq: Try callee of call");
|
||||||
if self.merge_sequential_expr(a, &mut **b_callee)? {
|
if self.merge_sequential_expr(a, &mut **b_callee)? {
|
||||||
if is_this_undefined {
|
if is_this_undefined {
|
||||||
if let Expr::Member(..) = &**b_callee {
|
if let Expr::Member(..) = &**b_callee {
|
||||||
@ -1192,7 +1188,7 @@ where
|
|||||||
value: 0.0,
|
value: 0.0,
|
||||||
raw: None,
|
raw: None,
|
||||||
})));
|
})));
|
||||||
tracing::debug!("injecting zero to preserve `this` in call");
|
report_change!("injecting zero to preserve `this` in call");
|
||||||
|
|
||||||
*b_callee = Box::new(Expr::Seq(SeqExpr {
|
*b_callee = Box::new(Expr::Seq(SeqExpr {
|
||||||
span: b_callee.span(),
|
span: b_callee.span(),
|
||||||
@ -1209,7 +1205,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
for arg in b_args {
|
for arg in b_args {
|
||||||
tracing::trace!("seq: Try arg of call");
|
trace_op!("seq: Try arg of call");
|
||||||
if self.merge_sequential_expr(a, &mut arg.expr)? {
|
if self.merge_sequential_expr(a, &mut arg.expr)? {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
@ -1225,7 +1221,7 @@ where
|
|||||||
Expr::New(NewExpr {
|
Expr::New(NewExpr {
|
||||||
callee: b_callee, ..
|
callee: b_callee, ..
|
||||||
}) => {
|
}) => {
|
||||||
tracing::trace!("seq: Try callee of new");
|
trace_op!("seq: Try callee of new");
|
||||||
if self.merge_sequential_expr(a, &mut **b_callee)? {
|
if self.merge_sequential_expr(a, &mut **b_callee)? {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
@ -1235,7 +1231,7 @@ where
|
|||||||
|
|
||||||
Expr::Seq(SeqExpr { exprs: b_exprs, .. }) => {
|
Expr::Seq(SeqExpr { exprs: b_exprs, .. }) => {
|
||||||
for b_expr in b_exprs {
|
for b_expr in b_exprs {
|
||||||
tracing::trace!("seq: Try elem of seq");
|
trace_op!("seq: Try elem of seq");
|
||||||
|
|
||||||
if self.merge_sequential_expr(a, &mut **b_expr)? {
|
if self.merge_sequential_expr(a, &mut **b_expr)? {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
@ -1311,22 +1307,20 @@ where
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
match a {
|
||||||
match a {
|
Mergable::Var(a) => {
|
||||||
Mergable::Var(a) => {
|
trace_op!(
|
||||||
tracing::trace!(
|
"sequences: Trying to merge `{}` => `{}`",
|
||||||
"sequences: Trying to merge `{}` => `{}`",
|
crate::debug::dump(&**a, false),
|
||||||
crate::debug::dump(&**a, false),
|
crate::debug::dump(&*b, false)
|
||||||
crate::debug::dump(&*b, false)
|
);
|
||||||
);
|
}
|
||||||
}
|
Mergable::Expr(a) => {
|
||||||
Mergable::Expr(a) => {
|
trace_op!(
|
||||||
tracing::trace!(
|
"sequences: Trying to merge `{}` => `{}`",
|
||||||
"sequences: Trying to merge `{}` => `{}`",
|
crate::debug::dump(&**a, false),
|
||||||
crate::debug::dump(&**a, false),
|
crate::debug::dump(&*b, false)
|
||||||
crate::debug::dump(&*b, false)
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1375,15 +1369,13 @@ where
|
|||||||
};
|
};
|
||||||
b.visit_with(&mut v);
|
b.visit_with(&mut v);
|
||||||
if v.expr_usage != 1 || v.pat_usage != 0 {
|
if v.expr_usage != 1 || v.pat_usage != 0 {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!(
|
||||||
tracing::trace!(
|
"sequences: Aborting merging of an update expression because of usage \
|
||||||
"[X] sequences: Aborting merging of an update expression because \
|
counts ({}, ref = {}, pat = {})",
|
||||||
of usage counts ({}, ref = {}, pat = {})",
|
a_id,
|
||||||
a_id,
|
v.expr_usage,
|
||||||
v.expr_usage,
|
v.pat_usage
|
||||||
v.pat_usage
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
@ -1418,7 +1410,7 @@ where
|
|||||||
});
|
});
|
||||||
if replaced {
|
if replaced {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"sequences: Merged update expression into another expression",
|
"sequences: Merged update expression into another expression",
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1450,7 +1442,7 @@ where
|
|||||||
let left_id = match left.as_ident() {
|
let left_id = match left.as_ident() {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => {
|
None => {
|
||||||
tracing::trace!("[X] sequences: Aborting because lhs is not an id");
|
log_abort!("sequences: Aborting because lhs is not an id");
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1466,8 +1458,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
if usage.declared_as_fn_expr {
|
if usage.declared_as_fn_expr {
|
||||||
tracing::trace!(
|
log_abort!(
|
||||||
"sequences: [X] Declared as fn expr ({}, {:?})",
|
"sequences: Declared as fn expr ({}, {:?})",
|
||||||
left_id.sym,
|
left_id.sym,
|
||||||
left_id.span.ctxt
|
left_id.span.ctxt
|
||||||
);
|
);
|
||||||
@ -1545,7 +1537,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
if used_by_b.contains(id) {
|
if used_by_b.contains(id) {
|
||||||
tracing::trace!("[X] sequences: Aborting because of deps");
|
log_abort!("[X] sequences: Aborting because of deps");
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1560,22 +1552,20 @@ where
|
|||||||
};
|
};
|
||||||
b.visit_with(&mut v);
|
b.visit_with(&mut v);
|
||||||
if v.expr_usage != 1 || v.pat_usage != 0 {
|
if v.expr_usage != 1 || v.pat_usage != 0 {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!(
|
||||||
tracing::trace!(
|
"sequences: Aborting because of usage counts ({}{:?}, ref = {}, pat = {})",
|
||||||
"[X] sequences: Aborting because of usage counts ({}{:?}, ref = {}, pat = \
|
left_id.sym,
|
||||||
{})",
|
left_id.span.ctxt,
|
||||||
left_id.sym,
|
v.expr_usage,
|
||||||
left_id.span.ctxt,
|
v.pat_usage
|
||||||
v.expr_usage,
|
);
|
||||||
v.pat_usage
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"sequences: Inlining sequential expressions (`{}{:?}`)",
|
"sequences: Inlining sequential expressions (`{}{:?}`)",
|
||||||
left_id.sym,
|
left_id.sym,
|
||||||
left_id.span.ctxt
|
left_id.span.ctxt
|
||||||
@ -1588,9 +1578,7 @@ where
|
|||||||
|
|
||||||
replace_id_with_expr(b, left_id.to_id(), to);
|
replace_id_with_expr(b, left_id.to_id(), to);
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
dump_change_detail!("sequences: {}", dump(&*b, false));
|
||||||
tracing::debug!("sequences: [Changed] {}", dump(&*b, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ where
|
|||||||
|
|
||||||
if let Expr::Lit(Lit::Str(..)) = &*args[0].expr {
|
if let Expr::Lit(Lit::Str(..)) = &*args[0].expr {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"strings: Unsafely reduced `RegExp` call in a string context"
|
"strings: Unsafely reduced `RegExp` call in a string context"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ where
|
|||||||
if let Expr::Lit(Lit::Str(..)) = &*e.expr {
|
if let Expr::Lit(Lit::Str(..)) = &*e.expr {
|
||||||
*n = *e.expr.take();
|
*n = *e.expr.take();
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("string: Removed a paren in a string context");
|
report_change!("string: Removed a paren in a string context");
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -72,7 +72,7 @@ where
|
|||||||
let span = n.span();
|
let span = n.span();
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"strings: Converted an expression into a string literal (in string context)"
|
"strings: Converted an expression into a string literal (in string context)"
|
||||||
);
|
);
|
||||||
*n = Expr::Lit(Lit::Str(Str {
|
*n = Expr::Lit(Lit::Str(Str {
|
||||||
@ -86,7 +86,7 @@ where
|
|||||||
match n {
|
match n {
|
||||||
Expr::Lit(Lit::Num(v)) => {
|
Expr::Lit(Lit::Num(v)) => {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"strings: Converted a numeric literal ({}) into a string literal (in string \
|
"strings: Converted a numeric literal ({}) into a string literal (in string \
|
||||||
context)",
|
context)",
|
||||||
v.value
|
v.value
|
||||||
@ -106,7 +106,7 @@ where
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"strings: Converted a regex (/{}/{}) into a string literal (in string context)",
|
"strings: Converted a regex (/{}/{}) into a string literal (in string context)",
|
||||||
v.exp,
|
v.exp,
|
||||||
v.flags
|
v.flags
|
||||||
@ -139,7 +139,7 @@ where
|
|||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"strings: Converting an unresolved reference ({}{:?}) into `undefined` \
|
"strings: Converting an unresolved reference ({}{:?}) into `undefined` \
|
||||||
(in string context)",
|
(in string context)",
|
||||||
i.sym,
|
i.sym,
|
||||||
|
@ -66,9 +66,9 @@ where
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::debug!("switches: Removing unreachable cases from a constant switch");
|
report_change!("switches: Removing unreachable cases from a constant switch");
|
||||||
} else {
|
} else {
|
||||||
tracing::debug!("switches: Removing a constant switch");
|
report_change!("switches: Removing a constant switch");
|
||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
@ -233,7 +233,7 @@ where
|
|||||||
if !preserve_cases {
|
if !preserve_cases {
|
||||||
if let Some(last_non_empty) = last_non_empty {
|
if let Some(last_non_empty) = last_non_empty {
|
||||||
if last_non_empty + 1 != cases.len() {
|
if last_non_empty + 1 != cases.len() {
|
||||||
tracing::debug!("switches: Removing empty cases at the end");
|
report_change!("switches: Removing empty cases at the end");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
cases.drain(last_non_empty + 1..);
|
cases.drain(last_non_empty + 1..);
|
||||||
}
|
}
|
||||||
@ -242,14 +242,14 @@ where
|
|||||||
|
|
||||||
if let Some(last) = cases.last_mut() {
|
if let Some(last) = cases.last_mut() {
|
||||||
if let Some(Stmt::Break(BreakStmt { label: None, .. })) = last.cons.last() {
|
if let Some(Stmt::Break(BreakStmt { label: None, .. })) = last.cons.last() {
|
||||||
tracing::debug!("switches: Removing `break` at the end");
|
report_change!("switches: Removing `break` at the end");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
last.cons.pop();
|
last.cons.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If a case ends with break but content is same with the consequtive case
|
/// If a case ends with break but content is same with the consecutive case
|
||||||
/// except the break statement, we merge them.
|
/// except the break statement, we merge them.
|
||||||
fn merge_cases_with_same_cons(&mut self, cases: &mut Vec<SwitchCase>) {
|
fn merge_cases_with_same_cons(&mut self, cases: &mut Vec<SwitchCase>) {
|
||||||
let mut stop_pos_opt = cases
|
let mut stop_pos_opt = cases
|
||||||
@ -301,7 +301,7 @@ where
|
|||||||
|
|
||||||
if let Some(idx) = found {
|
if let Some(idx) = found {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("switches: Merging cases with same cons");
|
report_change!("switches: Merging cases with same cons");
|
||||||
cases[idx].cons.clear();
|
cases[idx].cons.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ where
|
|||||||
self.drop_unused_vars(var.span, &mut var.name, Some(init));
|
self.drop_unused_vars(var.span, &mut var.name, Some(init));
|
||||||
|
|
||||||
if var.name.is_invalid() {
|
if var.name.is_invalid() {
|
||||||
tracing::debug!("unused: Removing an unused variable declarator");
|
report_change!("unused: Removing an unused variable declarator");
|
||||||
let side_effects = self.ignore_return_value(init).map(Box::new);
|
let side_effects = self.ignore_return_value(init).map(Box::new);
|
||||||
if let Some(e) = side_effects {
|
if let Some(e) = side_effects {
|
||||||
*storage_for_side_effects = Some(e);
|
*storage_for_side_effects = Some(e);
|
||||||
@ -118,9 +118,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
trace_op!("unused: drop_unused_vars({})", dump(&*name, false));
|
||||||
tracing::trace!("unused: drop_unused_vars({})", dump(&*name, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Top-level
|
// Top-level
|
||||||
if !has_mark {
|
if !has_mark {
|
||||||
@ -128,12 +126,10 @@ where
|
|||||||
Some(VarDeclKind::Var) => {
|
Some(VarDeclKind::Var) => {
|
||||||
if !self.options.top_level() && self.options.top_retain.is_empty() {
|
if !self.options.top_level() && self.options.top_retain.is_empty() {
|
||||||
if self.ctx.in_top_level() {
|
if self.ctx.in_top_level() {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!(
|
||||||
tracing::trace!(
|
"unused: [X] Preserving `var` `{}` because it's top-level",
|
||||||
"unused: [X] Preserving `var` `{}` because it's top-level",
|
dump(&*name, false)
|
||||||
dump(&*name, false)
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -141,13 +137,11 @@ where
|
|||||||
}
|
}
|
||||||
Some(VarDeclKind::Let) | Some(VarDeclKind::Const) => {
|
Some(VarDeclKind::Let) | Some(VarDeclKind::Const) => {
|
||||||
if !self.options.top_level() && self.ctx.is_top_level_for_block_level_vars() {
|
if !self.options.top_level() && self.ctx.is_top_level_for_block_level_vars() {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!(
|
||||||
tracing::trace!(
|
"unused: Preserving block scoped var `{}` because it's top-level",
|
||||||
"unused: [X] Preserving block scoped var `{}` because it's \
|
dump(&*name, false)
|
||||||
top-level",
|
);
|
||||||
dump(&*name, false)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,12 +151,10 @@ where
|
|||||||
|
|
||||||
if let Some(scope) = self.data.scopes.get(&self.ctx.scope) {
|
if let Some(scope) = self.data.scopes.get(&self.ctx.scope) {
|
||||||
if scope.has_eval_call || scope.has_with_stmt {
|
if scope.has_eval_call || scope.has_with_stmt {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!(
|
||||||
tracing::trace!(
|
"unused: Preserving `{}` because of usages",
|
||||||
"unused: [X] Preserving `{}` because of usages",
|
dump(&*name, false)
|
||||||
dump(&*name, false)
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,16 +184,12 @@ where
|
|||||||
i: &mut Ident,
|
i: &mut Ident,
|
||||||
init: Option<&mut Expr>,
|
init: Option<&mut Expr>,
|
||||||
) {
|
) {
|
||||||
if cfg!(debug_assertions) {
|
trace_op!("unused: Checking identifier `{}`", i);
|
||||||
tracing::trace!("unused: Checking identifier `{}`", i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !parent_span.has_mark(self.marks.non_top_level)
|
if !parent_span.has_mark(self.marks.non_top_level)
|
||||||
&& self.options.top_retain.contains(&i.sym)
|
&& self.options.top_retain.contains(&i.sym)
|
||||||
{
|
{
|
||||||
if cfg!(feature = "debug") {
|
log_abort!("unused: [X] Top-retain");
|
||||||
tracing::trace!("unused: [X] Top-retain")
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,7 +201,7 @@ where
|
|||||||
&& !v.declared_as_catch_param
|
&& !v.declared_as_catch_param
|
||||||
{
|
{
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"unused: Dropping a variable '{}{:?}' because it is not used",
|
"unused: Dropping a variable '{}{:?}' because it is not used",
|
||||||
i.sym,
|
i.sym,
|
||||||
i.span.ctxt
|
i.span.ctxt
|
||||||
@ -244,12 +232,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
log_abort!(
|
||||||
tracing::trace!(
|
"unused: Cannot drop ({}) because it's used",
|
||||||
"unused: Cannot drop ({}) because it's used",
|
dump(&*i, false)
|
||||||
dump(&*i, false)
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,9 +317,7 @@ where
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
trace_op!("unused: take_pat_if_unused({})", dump(&*name, false));
|
||||||
tracing::trace!("unused: take_pat_if_unused({})", dump(&*name, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
if !name.is_ident() {
|
if !name.is_ident() {
|
||||||
// TODO: Use smart logic
|
// TODO: Use smart logic
|
||||||
@ -488,7 +472,7 @@ where
|
|||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"unused: Dropping a decl '{}{:?}' because it is not used",
|
"unused: Dropping a decl '{}{:?}' because it is not used",
|
||||||
ident.sym,
|
ident.sym,
|
||||||
ident.span.ctxt
|
ident.span.ctxt
|
||||||
@ -525,7 +509,7 @@ where
|
|||||||
// Update is counted as usage
|
// Update is counted as usage
|
||||||
if var.declared && var.is_fn_local && var.usage_count == 1 {
|
if var.declared && var.is_fn_local && var.usage_count == 1 {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"unused: Dropping an update '{}{:?}' because it is not used",
|
"unused: Dropping an update '{}{:?}' because it is not used",
|
||||||
arg.sym,
|
arg.sym,
|
||||||
arg.span.ctxt
|
arg.span.ctxt
|
||||||
@ -570,7 +554,7 @@ where
|
|||||||
// TODO: We don't need fn_local check
|
// TODO: We don't need fn_local check
|
||||||
if var.declared && var.is_fn_local && var.usage_count == 1 {
|
if var.declared && var.is_fn_local && var.usage_count == 1 {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"unused: Dropping an op-assign '{}{:?}' because it is not used",
|
"unused: Dropping an op-assign '{}{:?}' because it is not used",
|
||||||
left.id.sym,
|
left.id.sym,
|
||||||
left.id.span.ctxt
|
left.id.span.ctxt
|
||||||
@ -616,23 +600,19 @@ where
|
|||||||
})
|
})
|
||||||
.used_arguments;
|
.used_arguments;
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
trace_op!(
|
||||||
tracing::trace!(
|
"unused: drop_unused_assignments: Target: `{}`",
|
||||||
"unused: drop_unused_assignments: Target: `{}`",
|
dump(&assign.left, false)
|
||||||
dump(&assign.left, false)
|
);
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !has_mark
|
if !has_mark
|
||||||
&& (!self.options.top_level() && self.options.top_retain.is_empty())
|
&& (!self.options.top_level() && self.options.top_retain.is_empty())
|
||||||
&& self.ctx.in_top_level()
|
&& self.ctx.in_top_level()
|
||||||
{
|
{
|
||||||
if cfg!(feature = "debug") {
|
log_abort!(
|
||||||
tracing::trace!(
|
"unused: Preserving assignment to `{}` because it's top-level",
|
||||||
"unused: Preserving assignment to `{}` because it's top-level",
|
dump(&assign.left, false)
|
||||||
dump(&assign.left, false)
|
);
|
||||||
)
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,12 +620,10 @@ where
|
|||||||
|
|
||||||
match &mut assign.left {
|
match &mut assign.left {
|
||||||
PatOrExpr::Expr(_) => {
|
PatOrExpr::Expr(_) => {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!(
|
||||||
tracing::trace!(
|
"unused: Preserving assignment to `{}` because it's an expression",
|
||||||
"unused: Preserving assignment to `{}` because it's an expression",
|
dump(&assign.left, false)
|
||||||
dump(&assign.left, false)
|
);
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
PatOrExpr::Pat(left) => {
|
PatOrExpr::Pat(left) => {
|
||||||
if let Pat::Ident(i) = &**left {
|
if let Pat::Ident(i) = &**left {
|
||||||
@ -659,7 +637,7 @@ where
|
|||||||
&& var.declared
|
&& var.declared
|
||||||
&& (!var.declared_as_fn_param || !used_arguments || self.ctx.in_strict)
|
&& (!var.declared_as_fn_param || !used_arguments || self.ctx.in_strict)
|
||||||
{
|
{
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"unused: Dropping assignment to var '{}{:?}', which is never used",
|
"unused: Dropping assignment to var '{}{:?}', which is never used",
|
||||||
i.id.sym,
|
i.id.sym,
|
||||||
i.id.span.ctxt
|
i.id.span.ctxt
|
||||||
@ -674,13 +652,11 @@ where
|
|||||||
*e = *assign.right.take();
|
*e = *assign.right.take();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if cfg!(feature = "debug") {
|
log_abort!(
|
||||||
tracing::trace!(
|
"unused: Preserving assignment to `{}` because of usage: {:?}",
|
||||||
"unused: Preserving assignment to `{}` because of usage: {:?}",
|
dump(&assign.left, false),
|
||||||
dump(&assign.left, false),
|
var
|
||||||
var
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -709,7 +685,7 @@ where
|
|||||||
|
|
||||||
if can_remove_ident {
|
if can_remove_ident {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Removing ident of an class / function expression");
|
report_change!("Removing ident of an class / function expression");
|
||||||
*name = None;
|
*name = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -731,7 +707,7 @@ where
|
|||||||
if let Some(usage) = self.data.vars.get(&name.to_id()) {
|
if let Some(usage) = self.data.vars.get(&name.to_id()) {
|
||||||
if usage.is_fn_local && usage.declared_as_fn_param {
|
if usage.is_fn_local && usage.declared_as_fn_param {
|
||||||
d.name.take();
|
d.name.take();
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"Removing a variable statement because it's a function parameter"
|
"Removing a variable statement because it's a function parameter"
|
||||||
);
|
);
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
@ -762,7 +738,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"unused: Removing the name of a function expression because it's not used by it'"
|
"unused: Removing the name of a function expression because it's not used by it'"
|
||||||
);
|
);
|
||||||
f.ident = None;
|
f.ident = None;
|
||||||
|
@ -26,7 +26,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("unsafe_arrows: Fn expr => arrow");
|
report_change!("unsafe_arrows: Fn expr => arrow");
|
||||||
|
|
||||||
*e = Expr::Arrow(ArrowExpr {
|
*e = Expr::Arrow(ArrowExpr {
|
||||||
span: function.span,
|
span: function.span,
|
||||||
@ -50,7 +50,7 @@ impl Pure<'_> {
|
|||||||
if s.stmts.len() == 1 {
|
if s.stmts.len() == 1 {
|
||||||
if let Stmt::Return(s) = &mut s.stmts[0] {
|
if let Stmt::Return(s) = &mut s.stmts[0] {
|
||||||
if let Some(arg) = &mut s.arg {
|
if let Some(arg) = &mut s.arg {
|
||||||
tracing::debug!("arrows: Optimizing the body of an arrow");
|
report_change!("arrows: Optimizing the body of an arrow");
|
||||||
*b = BlockStmtOrExpr::Expr(arg.take());
|
*b = BlockStmtOrExpr::Expr(arg.take());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,7 +90,7 @@ impl Pure<'_> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Method property => arrow");
|
report_change!("Method property => arrow");
|
||||||
|
|
||||||
let arg = body
|
let arg = body
|
||||||
.take()
|
.take()
|
||||||
|
@ -47,7 +47,7 @@ impl Pure<'_> {
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tracing::debug!("bools: Optimizing `!(a && b)` as `!a || !b`");
|
report_change!("bools: Optimizing `!(a && b)` as `!a || !b`");
|
||||||
self.negate(arg, false, false);
|
self.negate(arg, false, false);
|
||||||
*e = *arg.take();
|
*e = *arg.take();
|
||||||
}
|
}
|
||||||
@ -69,7 +69,7 @@ impl Pure<'_> {
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tracing::debug!("bools: Optimizing `!!(a || b)` as `!a && !b`");
|
report_change!("bools: Optimizing `!!(a || b)` as `!a && !b`");
|
||||||
self.negate(arg_of_arg, false, false);
|
self.negate(arg_of_arg, false, false);
|
||||||
*e = *arg.take();
|
*e = *arg.take();
|
||||||
}
|
}
|
||||||
@ -111,7 +111,7 @@ impl Pure<'_> {
|
|||||||
if should_optimize(&e.left, &e.right, self.options)
|
if should_optimize(&e.left, &e.right, self.options)
|
||||||
|| should_optimize(&e.right, &e.left, self.options)
|
|| should_optimize(&e.right, &e.left, self.options)
|
||||||
{
|
{
|
||||||
tracing::debug!("bools: Compressing comparison of `typeof` with literal");
|
report_change!("bools: Compressing comparison of `typeof` with literal");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
e.op = match e.op {
|
e.op = match e.op {
|
||||||
op!("===") => {
|
op!("===") => {
|
||||||
@ -164,9 +164,9 @@ impl Pure<'_> {
|
|||||||
|
|
||||||
if can_remove {
|
if can_remove {
|
||||||
if *op == op!("&&") {
|
if *op == op!("&&") {
|
||||||
tracing::debug!("booleans: Compressing `!foo && true` as `!foo`");
|
report_change!("booleans: Compressing `!foo && true` as `!foo`");
|
||||||
} else {
|
} else {
|
||||||
tracing::debug!("booleans: Compressing `!foo || false` as `!foo`");
|
report_change!("booleans: Compressing `!foo || false` as `!foo`");
|
||||||
}
|
}
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*e = *left.take();
|
*e = *left.take();
|
||||||
@ -237,7 +237,7 @@ impl Pure<'_> {
|
|||||||
} else {
|
} else {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
let span = delete.arg.span();
|
let span = delete.arg.span();
|
||||||
tracing::debug!("booleans: Compressing `delete` as sequence expression");
|
report_change!("booleans: Compressing `delete` as sequence expression");
|
||||||
*e = Expr::Seq(SeqExpr {
|
*e = Expr::Seq(SeqExpr {
|
||||||
span,
|
span,
|
||||||
exprs: vec![delete.arg.take(), Box::new(make_bool(span, true))],
|
exprs: vec![delete.arg.take(), Box::new(make_bool(span, true))],
|
||||||
@ -252,7 +252,7 @@ impl Pure<'_> {
|
|||||||
if convert_to_true {
|
if convert_to_true {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
let span = delete.arg.span();
|
let span = delete.arg.span();
|
||||||
tracing::debug!("booleans: Compressing `delete` => true");
|
report_change!("booleans: Compressing `delete` => true");
|
||||||
*e = make_bool(span, true);
|
*e = make_bool(span, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,7 +269,7 @@ impl Pure<'_> {
|
|||||||
if exprs.is_empty() {
|
if exprs.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tracing::debug!("bools: Optimizing negated sequences");
|
report_change!("bools: Optimizing negated sequences");
|
||||||
|
|
||||||
{
|
{
|
||||||
let last = exprs.last_mut().unwrap();
|
let last = exprs.last_mut().unwrap();
|
||||||
@ -323,7 +323,7 @@ impl Pure<'_> {
|
|||||||
arg,
|
arg,
|
||||||
}) => match &mut **arg {
|
}) => match &mut **arg {
|
||||||
Expr::Lit(Lit::Num(Number { value, .. })) => {
|
Expr::Lit(Lit::Num(Number { value, .. })) => {
|
||||||
tracing::debug!("Optimizing: number => number (in bool context)");
|
report_change!("Optimizing: number => number (in bool context)");
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*n = Expr::Lit(Lit::Num(Number {
|
*n = Expr::Lit(Lit::Num(Number {
|
||||||
@ -336,7 +336,7 @@ impl Pure<'_> {
|
|||||||
Expr::Unary(UnaryExpr {
|
Expr::Unary(UnaryExpr {
|
||||||
op: op!("!"), arg, ..
|
op: op!("!"), arg, ..
|
||||||
}) => {
|
}) => {
|
||||||
tracing::debug!("bools: !!expr => expr (in bool ctx)");
|
report_change!("bools: !!expr => expr (in bool ctx)");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*n = *arg.take();
|
*n = *arg.take();
|
||||||
}
|
}
|
||||||
@ -348,7 +348,7 @@ impl Pure<'_> {
|
|||||||
op: op!("typeof"),
|
op: op!("typeof"),
|
||||||
arg,
|
arg,
|
||||||
}) => {
|
}) => {
|
||||||
tracing::debug!("Optimizing: typeof => true (in bool context)");
|
report_change!("Optimizing: typeof => true (in bool context)");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
|
|
||||||
match &**arg {
|
match &**arg {
|
||||||
@ -376,7 +376,7 @@ impl Pure<'_> {
|
|||||||
|
|
||||||
Expr::Lit(Lit::Str(s)) => {
|
Expr::Lit(Lit::Str(s)) => {
|
||||||
if !is_ignore {
|
if !is_ignore {
|
||||||
tracing::debug!("Converting string as boolean expressions");
|
report_change!("Converting string as boolean expressions");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*n = Expr::Lit(Lit::Num(Number {
|
*n = Expr::Lit(Lit::Num(Number {
|
||||||
span: s.span,
|
span: s.span,
|
||||||
@ -391,7 +391,7 @@ impl Pure<'_> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if self.options.bools {
|
if self.options.bools {
|
||||||
tracing::debug!("booleans: Converting number as boolean expressions");
|
report_change!("booleans: Converting number as boolean expressions");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*n = Expr::Lit(Lit::Num(Number {
|
*n = Expr::Lit(Lit::Num(Number {
|
||||||
span: num.span,
|
span: num.span,
|
||||||
@ -409,7 +409,7 @@ impl Pure<'_> {
|
|||||||
}) => {
|
}) => {
|
||||||
// Optimize if (a ?? false); as if (a);
|
// Optimize if (a ?? false); as if (a);
|
||||||
if let Value::Known(false) = right.as_pure_bool() {
|
if let Value::Known(false) = right.as_pure_bool() {
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"Dropping right operand of `??` as it's always false (in bool context)"
|
"Dropping right operand of `??` as it's always false (in bool context)"
|
||||||
);
|
);
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
@ -426,7 +426,7 @@ impl Pure<'_> {
|
|||||||
// `a || false` => `a` (as it will be casted to boolean anyway)
|
// `a || false` => `a` (as it will be casted to boolean anyway)
|
||||||
|
|
||||||
if let Value::Known(false) = right.as_pure_bool() {
|
if let Value::Known(false) = right.as_pure_bool() {
|
||||||
tracing::debug!("bools: `expr || false` => `expr` (in bool context)");
|
report_change!("bools: `expr || false` => `expr` (in bool context)");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*n = *left.take();
|
*n = *left.take();
|
||||||
}
|
}
|
||||||
@ -436,7 +436,7 @@ impl Pure<'_> {
|
|||||||
let v = n.as_pure_bool();
|
let v = n.as_pure_bool();
|
||||||
if let Value::Known(v) = v {
|
if let Value::Known(v) = v {
|
||||||
let span = n.span();
|
let span = n.span();
|
||||||
tracing::debug!("Optimizing expr as {} (in bool context)", v);
|
report_change!("Optimizing expr as {} (in bool context)", v);
|
||||||
*n = make_bool(span, v);
|
*n = make_bool(span, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -520,7 +520,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.can_swap_bin_operands(left, right, false) {
|
if self.can_swap_bin_operands(left, right, false) {
|
||||||
tracing::debug!("Swapping operands of binary expession");
|
report_change!("Swapping operands of binary expession");
|
||||||
swap(left, right);
|
swap(left, right);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -535,7 +535,7 @@ impl Pure<'_> {
|
|||||||
| Expr::Bin(e @ BinExpr { op: op!("<"), .. }) => {
|
| Expr::Bin(e @ BinExpr { op: op!("<"), .. }) => {
|
||||||
if self.options.comparisons && self.can_swap_bin_operands(&e.left, &e.right, true) {
|
if self.options.comparisons && self.can_swap_bin_operands(&e.left, &e.right, true) {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("comparisons: Swapping operands of {}", e.op);
|
report_change!("comparisons: Swapping operands of {}", e.op);
|
||||||
|
|
||||||
e.op = if e.op == op!("<=") {
|
e.op = if e.op == op!("<=") {
|
||||||
op!(">=")
|
op!(">=")
|
||||||
|
@ -22,7 +22,7 @@ impl Pure<'_> {
|
|||||||
if let Value::Known(Type::Bool) = lt {
|
if let Value::Known(Type::Bool) = lt {
|
||||||
let lb = cond.cons.as_pure_bool();
|
let lb = cond.cons.as_pure_bool();
|
||||||
if let Value::Known(true) = lb {
|
if let Value::Known(true) = lb {
|
||||||
tracing::debug!("conditionals: `foo ? true : bar` => `!!foo || bar`");
|
report_change!("conditionals: `foo ? true : bar` => `!!foo || bar`");
|
||||||
|
|
||||||
// Negate twice to convert `test` to boolean.
|
// Negate twice to convert `test` to boolean.
|
||||||
self.negate_twice(&mut cond.test, false);
|
self.negate_twice(&mut cond.test, false);
|
||||||
@ -39,7 +39,7 @@ impl Pure<'_> {
|
|||||||
|
|
||||||
// TODO: Verify this rule.
|
// TODO: Verify this rule.
|
||||||
if let Value::Known(false) = lb {
|
if let Value::Known(false) = lb {
|
||||||
tracing::debug!("conditionals: `foo ? false : bar` => `!foo && bar`");
|
report_change!("conditionals: `foo ? false : bar` => `!foo && bar`");
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
self.negate(&mut cond.test, false, false);
|
self.negate(&mut cond.test, false, false);
|
||||||
@ -58,7 +58,7 @@ impl Pure<'_> {
|
|||||||
if let Value::Known(Type::Bool) = rt {
|
if let Value::Known(Type::Bool) = rt {
|
||||||
let rb = cond.alt.as_pure_bool();
|
let rb = cond.alt.as_pure_bool();
|
||||||
if let Value::Known(false) = rb {
|
if let Value::Known(false) = rb {
|
||||||
tracing::debug!("conditionals: `foo ? bar : false` => `!!foo && bar`");
|
report_change!("conditionals: `foo ? bar : false` => `!!foo && bar`");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
|
|
||||||
// Negate twice to convert `test` to boolean.
|
// Negate twice to convert `test` to boolean.
|
||||||
@ -74,7 +74,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Value::Known(true) = rb {
|
if let Value::Known(true) = rb {
|
||||||
tracing::debug!("conditionals: `foo ? bar : true` => `!foo || bar");
|
report_change!("conditionals: `foo ? bar : true` => `!foo || bar");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
|
|
||||||
self.negate(&mut cond.test, false, false);
|
self.negate(&mut cond.test, false, false);
|
||||||
@ -105,7 +105,7 @@ impl Pure<'_> {
|
|||||||
{
|
{
|
||||||
let cons_span = cons.span;
|
let cons_span = cons.span;
|
||||||
|
|
||||||
tracing::debug!("conditionals: `x ? y || z : z` => `x || y && z`");
|
report_change!("conditionals: `x ? y || z : z` => `x || y && z`");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
|
|
||||||
*e = Expr::Bin(BinExpr {
|
*e = Expr::Bin(BinExpr {
|
||||||
@ -129,19 +129,17 @@ impl Pure<'_> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::debug!("conditionals: `a ? foo : bar` => `!a ? bar : foo` (considered cost)");
|
report_change!("conditionals: `a ? foo : bar` => `!a ? bar : foo` (considered cost)");
|
||||||
let start_str = dump(&*cond, false);
|
let start_str = dump(&*cond, false);
|
||||||
|
|
||||||
self.negate(&mut cond.test, true, false);
|
self.negate(&mut cond.test, true, false);
|
||||||
swap(&mut cond.cons, &mut cond.alt);
|
swap(&mut cond.cons, &mut cond.alt);
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
dump_change_detail!(
|
||||||
tracing::trace!(
|
"[Change] Negated cond: `{}` => `{}`",
|
||||||
"[Change] Negated cond: `{}` => `{}`",
|
start_str,
|
||||||
start_str,
|
dump(&*cond, false)
|
||||||
dump(&*cond, false)
|
);
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes useless operands of an logical expressions.
|
/// Removes useless operands of an logical expressions.
|
||||||
@ -174,7 +172,7 @@ impl Pure<'_> {
|
|||||||
// `!!b || true` => true
|
// `!!b || true` => true
|
||||||
if let Value::Known(true) = rb {
|
if let Value::Known(true) = rb {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("conditionals: `!!foo || true` => `true`");
|
report_change!("conditionals: `!!foo || true` => `true`");
|
||||||
*e = make_bool(bin.span, true);
|
*e = make_bool(bin.span, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ impl Pure<'_> {
|
|||||||
{
|
{
|
||||||
if label.sym == ls.label.sym {
|
if label.sym == ls.label.sym {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Dropping instant break");
|
report_change!("Dropping instant break");
|
||||||
s.take();
|
s.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@ impl Pure<'_> {
|
|||||||
{
|
{
|
||||||
if ls.label.sym == label.sym {
|
if ls.label.sym == label.sym {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Optimizing labeled stmt with a break to if statement");
|
report_change!("Optimizing labeled stmt with a break to if statement");
|
||||||
|
|
||||||
self.negate(test, true, false);
|
self.negate(test, true, false);
|
||||||
let test = test.take();
|
let test = test.take();
|
||||||
@ -99,7 +99,7 @@ impl Pure<'_> {
|
|||||||
{
|
{
|
||||||
if ls.label.sym == label.sym {
|
if ls.label.sym == label.sym {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"Optimizing labeled stmt with a break in alt to if statement"
|
"Optimizing labeled stmt with a break in alt to if statement"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -175,7 +175,7 @@ impl Pure<'_> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Remove useless continue (last stmt of a loop)");
|
report_change!("Remove useless continue (last stmt of a loop)");
|
||||||
b.stmts.remove(b.stmts.len() - 1);
|
b.stmts.remove(b.stmts.len() - 1);
|
||||||
|
|
||||||
if let Some(label) = &label {
|
if let Some(label) = &label {
|
||||||
@ -222,7 +222,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Some(..) => {
|
Some(..) => {
|
||||||
tracing::debug!("Removing unreachable statements");
|
report_change!("Removing unreachable statements");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
stmt.take();
|
stmt.take();
|
||||||
}
|
}
|
||||||
@ -249,7 +249,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Dropping useless block");
|
report_change!("Dropping useless block");
|
||||||
|
|
||||||
let mut new = vec![];
|
let mut new = vec![];
|
||||||
for stmt in stmts.take() {
|
for stmt in stmts.take() {
|
||||||
@ -277,7 +277,7 @@ impl Pure<'_> {
|
|||||||
arg,
|
arg,
|
||||||
})) = r.arg.as_deref_mut()
|
})) = r.arg.as_deref_mut()
|
||||||
{
|
{
|
||||||
tracing::debug!("unused: Removing `return void` in end of a function");
|
report_change!("unused: Removing `return void` in end of a function");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*s = Stmt::Expr(ExprStmt {
|
*s = Stmt::Expr(ExprStmt {
|
||||||
span: *span,
|
span: *span,
|
||||||
@ -303,7 +303,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("dead_code: Removing dead codes");
|
report_change!("dead_code: Removing dead codes");
|
||||||
|
|
||||||
let mut new = vec![];
|
let mut new = vec![];
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::debug!("drop_console: Removing console call");
|
report_change!("drop_console: Removing console call");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*e = *undefined(DUMMY_SP);
|
*e = *undefined(DUMMY_SP);
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ impl Pure<'_> {
|
|||||||
|
|
||||||
if args.is_empty() && params.is_empty() {
|
if args.is_empty() && params.is_empty() {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Flattening iife");
|
report_change!("Flattening iife");
|
||||||
*s = Stmt::Block(body.take());
|
*s = Stmt::Block(body.take());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,7 +157,7 @@ impl Pure<'_> {
|
|||||||
match call.args.len() {
|
match call.args.len() {
|
||||||
0 => {
|
0 => {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("evaluate: Dropping array.slice call");
|
report_change!("evaluate: Dropping array.slice call");
|
||||||
*e = *obj.take();
|
*e = *obj.take();
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
@ -165,7 +165,7 @@ impl Pure<'_> {
|
|||||||
let start = start.floor() as usize;
|
let start = start.floor() as usize;
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("evaluate: Reducing array.slice({}) call", start);
|
report_change!("evaluate: Reducing array.slice({}) call", start);
|
||||||
|
|
||||||
if start >= arr.elems.len() {
|
if start >= arr.elems.len() {
|
||||||
*e = Expr::Array(ArrayLit {
|
*e = Expr::Array(ArrayLit {
|
||||||
@ -189,7 +189,7 @@ impl Pure<'_> {
|
|||||||
if let Value::Known(end) = end {
|
if let Value::Known(end) = end {
|
||||||
let end = end.floor() as usize;
|
let end = end.floor() as usize;
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"evaluate: Reducing array.slice({}, {}) call",
|
"evaluate: Reducing array.slice({}, {}) call",
|
||||||
start,
|
start,
|
||||||
end
|
end
|
||||||
@ -216,7 +216,7 @@ impl Pure<'_> {
|
|||||||
|
|
||||||
if self.options.unsafe_passes && &*method_name.sym == "toString" && arr.elems.len() == 1
|
if self.options.unsafe_passes && &*method_name.sym == "toString" && arr.elems.len() == 1
|
||||||
{
|
{
|
||||||
tracing::debug!("evaluate: Reducing array.toString() call");
|
report_change!("evaluate: Reducing array.toString() call");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*obj = arr.elems[0]
|
*obj = arr.elems[0]
|
||||||
.take()
|
.take()
|
||||||
@ -274,9 +274,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!("evaluate: Reduced `function.valueOf()` into a function expression");
|
||||||
"evaluate: Reduced `function.valueOf()` into a function expression"
|
|
||||||
);
|
|
||||||
|
|
||||||
*e = *obj.take();
|
*e = *obj.take();
|
||||||
return;
|
return;
|
||||||
@ -292,7 +290,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("evaluate: Reduced `function.toString()` into a string");
|
report_change!("evaluate: Reduced `function.toString()` into a string");
|
||||||
|
|
||||||
*e = Str {
|
*e = Str {
|
||||||
span: call.span,
|
span: call.span,
|
||||||
@ -321,7 +319,7 @@ impl Pure<'_> {
|
|||||||
}) = &**callee
|
}) = &**callee
|
||||||
{
|
{
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"evaluate: Reducing a call to `Number` into an unary operation"
|
"evaluate: Reducing a call to `Number` into an unary operation"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -372,7 +370,7 @@ impl Pure<'_> {
|
|||||||
let value = num_to_fixed(num.value, precision + 1);
|
let value = num_to_fixed(num.value, precision + 1);
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"evaluate: Evaluating `{}.toFixed({})` as `{}`",
|
"evaluate: Evaluating `{}.toFixed({})` as `{}`",
|
||||||
num,
|
num,
|
||||||
precision,
|
precision,
|
||||||
@ -399,7 +397,7 @@ impl Pure<'_> {
|
|||||||
//
|
//
|
||||||
if is_pure_undefined_or_null(obj) {
|
if is_pure_undefined_or_null(obj) {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"evaluate: Reduced an optional chaining operation because object is \
|
"evaluate: Reduced an optional chaining operation because object is \
|
||||||
always null or undefined"
|
always null or undefined"
|
||||||
);
|
);
|
||||||
@ -411,7 +409,7 @@ impl Pure<'_> {
|
|||||||
OptChainBase::Call(OptCall { span, callee, .. }) => {
|
OptChainBase::Call(OptCall { span, callee, .. }) => {
|
||||||
if is_pure_undefined_or_null(callee) {
|
if is_pure_undefined_or_null(callee) {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"evaluate: Reduced a call expression with optional chaining operation \
|
"evaluate: Reduced a call expression with optional chaining operation \
|
||||||
because object is always null or undefined"
|
because object is always null or undefined"
|
||||||
);
|
);
|
||||||
@ -441,7 +439,7 @@ impl Pure<'_> {
|
|||||||
// foo || 1 => foo, 1
|
// foo || 1 => foo, 1
|
||||||
if v {
|
if v {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("evaluate: `foo || true` => `foo, 1`");
|
report_change!("evaluate: `foo || true` => `foo, 1`");
|
||||||
|
|
||||||
*e = Expr::Seq(SeqExpr {
|
*e = Expr::Seq(SeqExpr {
|
||||||
span: bin_expr.span,
|
span: bin_expr.span,
|
||||||
@ -450,7 +448,7 @@ impl Pure<'_> {
|
|||||||
e.visit_mut_with(self);
|
e.visit_mut_with(self);
|
||||||
} else {
|
} else {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("evaluate: `foo || false` => `foo` (bool ctx)");
|
report_change!("evaluate: `foo || false` => `foo` (bool ctx)");
|
||||||
|
|
||||||
*e = *bin_expr.left.take();
|
*e = *bin_expr.left.take();
|
||||||
}
|
}
|
||||||
@ -460,7 +458,7 @@ impl Pure<'_> {
|
|||||||
// 1 || foo => foo
|
// 1 || foo => foo
|
||||||
if let Value::Known(true) = bin_expr.left.as_pure_bool() {
|
if let Value::Known(true) = bin_expr.left.as_pure_bool() {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("evaluate: `true || foo` => `foo`");
|
report_change!("evaluate: `true || foo` => `foo`");
|
||||||
|
|
||||||
*e = *bin_expr.right.take();
|
*e = *bin_expr.right.take();
|
||||||
}
|
}
|
||||||
@ -470,12 +468,12 @@ impl Pure<'_> {
|
|||||||
if let Value::Known(v) = bin_expr.right.as_pure_bool() {
|
if let Value::Known(v) = bin_expr.right.as_pure_bool() {
|
||||||
if v {
|
if v {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("evaluate: `foo && true` => `foo` (bool ctx)");
|
report_change!("evaluate: `foo && true` => `foo` (bool ctx)");
|
||||||
|
|
||||||
*e = *bin_expr.left.take();
|
*e = *bin_expr.left.take();
|
||||||
} else {
|
} else {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("evaluate: `foo && false` => `foo, false`");
|
report_change!("evaluate: `foo && false` => `foo, false`");
|
||||||
|
|
||||||
*e = Expr::Seq(SeqExpr {
|
*e = Expr::Seq(SeqExpr {
|
||||||
span: bin_expr.span,
|
span: bin_expr.span,
|
||||||
@ -488,7 +486,7 @@ impl Pure<'_> {
|
|||||||
|
|
||||||
if let Value::Known(true) = bin_expr.left.as_pure_bool() {
|
if let Value::Known(true) = bin_expr.left.as_pure_bool() {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("evaluate: `true && foo` => `foo`");
|
report_change!("evaluate: `true && foo` => `foo`");
|
||||||
|
|
||||||
*e = *bin_expr.right.take();
|
*e = *bin_expr.right.take();
|
||||||
}
|
}
|
||||||
@ -540,7 +538,7 @@ impl Pure<'_> {
|
|||||||
if let Pat::Ident(a_left) = &**a_left {
|
if let Pat::Ident(a_left) = &**a_left {
|
||||||
if let Expr::Ident(b_id) = b {
|
if let Expr::Ident(b_id) = b {
|
||||||
if b_id.to_id() == a_left.id.to_id() {
|
if b_id.to_id() == a_left.id.to_id() {
|
||||||
tracing::debug!("evaluate: Trivial: `{}`", a_left.id);
|
report_change!("evaluate: Trivial: `{}`", a_left.id);
|
||||||
*b = *a_right.clone();
|
*b = *a_right.clone();
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
}
|
}
|
||||||
@ -631,7 +629,7 @@ impl Pure<'_> {
|
|||||||
match c {
|
match c {
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"evaluate: Evaluated `charCodeAt` of a string literal as `{}`",
|
"evaluate: Evaluated `charCodeAt` of a string literal as `{}`",
|
||||||
v
|
v
|
||||||
);
|
);
|
||||||
@ -643,7 +641,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"evaluate: Evaluated `charCodeAt` of a string literal as `NaN`",
|
"evaluate: Evaluated `charCodeAt` of a string literal as `NaN`",
|
||||||
);
|
);
|
||||||
*e = Expr::Ident(Ident::new(
|
*e = Expr::Ident(Ident::new(
|
||||||
@ -659,7 +657,7 @@ impl Pure<'_> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("evaluate: Evaluated `{}` of a string literal", method);
|
report_change!("evaluate: Evaluated `{}` of a string literal", method);
|
||||||
*e = Expr::Lit(Lit::Str(Str {
|
*e = Expr::Lit(Lit::Str(Str {
|
||||||
value: new_val.into(),
|
value: new_val.into(),
|
||||||
..s
|
..s
|
||||||
|
@ -80,7 +80,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"if_return: Negating `foo` in `if (foo) return; bar()` to make it `if (!foo) bar()`"
|
"if_return: Negating `foo` in `if (foo) return; bar()` to make it `if (!foo) bar()`"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ impl Pure<'_> {
|
|||||||
match s {
|
match s {
|
||||||
Stmt::While(stmt) => {
|
Stmt::While(stmt) => {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("loops: Converting a while loop to a for loop");
|
report_change!("loops: Converting a while loop to a for loop");
|
||||||
*s = Stmt::For(ForStmt {
|
*s = Stmt::For(ForStmt {
|
||||||
span: stmt.span,
|
span: stmt.span,
|
||||||
init: None,
|
init: None,
|
||||||
@ -29,7 +29,7 @@ impl Pure<'_> {
|
|||||||
let val = stmt.test.as_pure_bool();
|
let val = stmt.test.as_pure_bool();
|
||||||
if let Value::Known(true) = val {
|
if let Value::Known(true) = val {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("loops: Converting an always-true do-while loop to a for loop");
|
report_change!("loops: Converting an always-true do-while loop to a for loop");
|
||||||
|
|
||||||
*s = Stmt::For(ForStmt {
|
*s = Stmt::For(ForStmt {
|
||||||
span: stmt.span,
|
span: stmt.span,
|
||||||
@ -91,7 +91,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::debug!("loops: Optimizing a for loop with an if-then-break");
|
report_change!("loops: Optimizing a for loop with an if-then-break");
|
||||||
|
|
||||||
first.take();
|
first.take();
|
||||||
return None;
|
return None;
|
||||||
@ -122,7 +122,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::debug!("loops: Optimizing a for loop with an if-else-break");
|
report_change!("loops: Optimizing a for loop with an if-else-break");
|
||||||
|
|
||||||
*first = *cons.take();
|
*first = *cons.take();
|
||||||
return None;
|
return None;
|
||||||
@ -166,7 +166,7 @@ impl Pure<'_> {
|
|||||||
// will remove block and with the next pass we can apply
|
// will remove block and with the next pass we can apply
|
||||||
// this pass.
|
// this pass.
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("loops: Compressing for-if-break into a for statement");
|
report_change!("loops: Compressing for-if-break into a for statement");
|
||||||
|
|
||||||
// We negate because this `test` is used as a condition for `break`.
|
// We negate because this `test` is used as a condition for `break`.
|
||||||
self.negate(test, true, false);
|
self.negate(test, true, false);
|
||||||
|
@ -27,7 +27,7 @@ impl Pure<'_> {
|
|||||||
if let Some(e) = s.arg.as_deref() {
|
if let Some(e) = s.arg.as_deref() {
|
||||||
if is_pure_undefined(e) {
|
if is_pure_undefined(e) {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Dropped `undefined` from `return undefined`");
|
report_change!("Dropped `undefined` from `return undefined`");
|
||||||
s.arg.take();
|
s.arg.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,7 +36,7 @@ impl Pure<'_> {
|
|||||||
pub(super) fn remove_useless_return(&mut self, stmts: &mut Vec<Stmt>) {
|
pub(super) fn remove_useless_return(&mut self, stmts: &mut Vec<Stmt>) {
|
||||||
if let Some(Stmt::Return(ReturnStmt { arg: None, .. })) = stmts.last() {
|
if let Some(Stmt::Return(ReturnStmt { arg: None, .. })) = stmts.last() {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("misc: Removing useless return");
|
report_change!("misc: Removing useless return");
|
||||||
stmts.pop();
|
stmts.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,9 +82,7 @@ impl Pure<'_> {
|
|||||||
Stmt::Block(s) => self.drop_return_value(&mut s.stmts),
|
Stmt::Block(s) => self.drop_return_value(&mut s.stmts),
|
||||||
Stmt::Return(ret) => {
|
Stmt::Return(ret) => {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
if cfg!(feature = "debug") {
|
report_change!("Dropping `return` token");
|
||||||
tracing::trace!("Dropping `return` token");
|
|
||||||
}
|
|
||||||
|
|
||||||
let span = ret.span;
|
let span = ret.span;
|
||||||
match ret.arg.take() {
|
match ret.arg.take() {
|
||||||
@ -177,7 +175,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Expr::Call(CallExpr { span, args, .. }) if span.has_mark(self.marks.pure) => {
|
Expr::Call(CallExpr { span, args, .. }) if span.has_mark(self.marks.pure) => {
|
||||||
tracing::debug!("ignore_return_value: Dropping a pure call");
|
report_change!("ignore_return_value: Dropping a pure call");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
|
|
||||||
let new = self.make_ignored_expr(args.take().into_iter().map(|arg| arg.expr));
|
let new = self.make_ignored_expr(args.take().into_iter().map(|arg| arg.expr));
|
||||||
@ -191,7 +189,7 @@ impl Pure<'_> {
|
|||||||
tpl: Tpl { exprs, .. },
|
tpl: Tpl { exprs, .. },
|
||||||
..
|
..
|
||||||
}) if span.has_mark(self.marks.pure) => {
|
}) if span.has_mark(self.marks.pure) => {
|
||||||
tracing::debug!("ignore_return_value: Dropping a pure call");
|
report_change!("ignore_return_value: Dropping a pure call");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
|
|
||||||
let new = self.make_ignored_expr(exprs.take().into_iter());
|
let new = self.make_ignored_expr(exprs.take().into_iter());
|
||||||
@ -201,7 +199,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Expr::New(NewExpr { span, args, .. }) if span.has_mark(self.marks.pure) => {
|
Expr::New(NewExpr { span, args, .. }) if span.has_mark(self.marks.pure) => {
|
||||||
tracing::debug!("ignore_return_value: Dropping a pure call");
|
report_change!("ignore_return_value: Dropping a pure call");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
|
|
||||||
let new =
|
let new =
|
||||||
@ -232,13 +230,13 @@ impl Pure<'_> {
|
|||||||
|| (self.options.unused && opts.drop_global_refs_if_unused)
|
|| (self.options.unused && opts.drop_global_refs_if_unused)
|
||||||
{
|
{
|
||||||
if is_global_var(&i.sym) {
|
if is_global_var(&i.sym) {
|
||||||
tracing::debug!("Dropping a reference to a global variable");
|
report_change!("Dropping a reference to a global variable");
|
||||||
*e = Expr::Invalid(Invalid { span: DUMMY_SP });
|
*e = Expr::Invalid(Invalid { span: DUMMY_SP });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tracing::debug!("Dropping an identifier as it's declared");
|
report_change!("Dropping an identifier as it's declared");
|
||||||
*e = Expr::Invalid(Invalid { span: DUMMY_SP });
|
*e = Expr::Invalid(Invalid { span: DUMMY_SP });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -262,7 +260,7 @@ impl Pure<'_> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if arg.is_invalid() {
|
if arg.is_invalid() {
|
||||||
tracing::debug!("Dropping an unary expression");
|
report_change!("Dropping an unary expression");
|
||||||
*e = Expr::Invalid(Invalid { span: DUMMY_SP });
|
*e = Expr::Invalid(Invalid { span: DUMMY_SP });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -277,7 +275,7 @@ impl Pure<'_> {
|
|||||||
self.ignore_return_value(&mut be.right, opts);
|
self.ignore_return_value(&mut be.right, opts);
|
||||||
|
|
||||||
if be.right.is_invalid() {
|
if be.right.is_invalid() {
|
||||||
tracing::debug!("Dropping the RHS of a binary expression ('&&' / '||')");
|
report_change!("Dropping the RHS of a binary expression ('&&' / '||')");
|
||||||
*e = *be.left.take();
|
*e = *be.left.take();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -300,7 +298,7 @@ impl Pure<'_> {
|
|||||||
Expr::Ident(i) => {
|
Expr::Ident(i) => {
|
||||||
if let Some(bindings) = self.bindings.as_deref() {
|
if let Some(bindings) = self.bindings.as_deref() {
|
||||||
if bindings.contains(&i.to_id()) {
|
if bindings.contains(&i.to_id()) {
|
||||||
tracing::debug!("Dropping an identifier as it's declared");
|
report_change!("Dropping an identifier as it's declared");
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*e = Expr::Invalid(Invalid { span: DUMMY_SP });
|
*e = Expr::Invalid(Invalid { span: DUMMY_SP });
|
||||||
@ -310,7 +308,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Expr::Lit(Lit::Null(..) | Lit::BigInt(..) | Lit::Bool(..) | Lit::Regex(..)) => {
|
Expr::Lit(Lit::Null(..) | Lit::BigInt(..) | Lit::Bool(..) | Lit::Regex(..)) => {
|
||||||
tracing::debug!("Dropping literals");
|
report_change!("Dropping literals");
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*e = Expr::Invalid(Invalid { span: DUMMY_SP });
|
*e = Expr::Invalid(Invalid { span: DUMMY_SP });
|
||||||
@ -376,7 +374,7 @@ impl Pure<'_> {
|
|||||||
|
|
||||||
if matches!(*bin.left, Expr::Await(..) | Expr::Update(..)) {
|
if matches!(*bin.left, Expr::Await(..) | Expr::Update(..)) {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("ignore_return_value: Compressing binary as seq");
|
report_change!("ignore_return_value: Compressing binary as seq");
|
||||||
*e = Expr::Seq(SeqExpr {
|
*e = Expr::Seq(SeqExpr {
|
||||||
span,
|
span,
|
||||||
exprs: vec![bin.left.take(), bin.right.take()],
|
exprs: vec![bin.left.take(), bin.right.take()],
|
||||||
|
@ -7,7 +7,7 @@ use swc_common::{collections::AHashSet, pass::Repeated, util::take::Take, DUMMY_
|
|||||||
use swc_ecma_ast::*;
|
use swc_ecma_ast::*;
|
||||||
use swc_ecma_utils::{collect_decls, undefined};
|
use swc_ecma_utils::{collect_decls, undefined};
|
||||||
use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith, VisitWith};
|
use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith, VisitWith};
|
||||||
use tracing::{span, Level};
|
use tracing::{debug, span, Level};
|
||||||
|
|
||||||
use self::{ctx::Ctx, misc::DropOpts};
|
use self::{ctx::Ctx, misc::DropOpts};
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -551,7 +551,7 @@ impl VisitMut for Pure<'_> {
|
|||||||
e.exprs.retain(|e| {
|
e.exprs.retain(|e| {
|
||||||
if e.is_invalid() {
|
if e.is_invalid() {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("Removing invalid expr in seq");
|
report_change!("Removing invalid expr in seq");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,7 +615,7 @@ impl VisitMut for Pure<'_> {
|
|||||||
let text = dump(&*s, false);
|
let text = dump(&*s, false);
|
||||||
|
|
||||||
if text.lines().count() < 10 {
|
if text.lines().count() < 10 {
|
||||||
tracing::debug!("after: visit_mut_children_with: {}", text);
|
debug!("after: visit_mut_children_with: {}", text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -623,7 +623,7 @@ impl VisitMut for Pure<'_> {
|
|||||||
if let Stmt::Debugger(..) = s {
|
if let Stmt::Debugger(..) = s {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
*s = Stmt::Empty(EmptyStmt { span: DUMMY_SP });
|
*s = Stmt::Empty(EmptyStmt { span: DUMMY_SP });
|
||||||
tracing::debug!("drop_debugger: Dropped a debugger statement");
|
report_change!("drop_debugger: Dropped a debugger statement");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -649,7 +649,7 @@ impl VisitMut for Pure<'_> {
|
|||||||
let text = dump(&*s, false);
|
let text = dump(&*s, false);
|
||||||
|
|
||||||
if text.lines().count() < 10 {
|
if text.lines().count() < 10 {
|
||||||
tracing::debug!("after: visit_mut_stmt: {}", text);
|
debug!("after: visit_mut_stmt: {}", text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ impl Pure<'_> {
|
|||||||
let value = if value.is_empty() { 0f64 } else { 1f64 };
|
let value = if value.is_empty() { 0f64 } else { 1f64 };
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("numbers: Converting a string literal to {:?}", value);
|
report_change!("numbers: Converting a string literal to {:?}", value);
|
||||||
*e = Expr::Lit(Lit::Num(Number {
|
*e = Expr::Lit(Lit::Num(Number {
|
||||||
span: *span,
|
span: *span,
|
||||||
value,
|
value,
|
||||||
@ -37,7 +37,7 @@ impl Pure<'_> {
|
|||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("numbers: Lifting `-`");
|
report_change!("numbers: Lifting `-`");
|
||||||
|
|
||||||
*e = Expr::Unary(UnaryExpr {
|
*e = Expr::Unary(UnaryExpr {
|
||||||
span: arg.span,
|
span: arg.span,
|
||||||
@ -54,7 +54,7 @@ impl Pure<'_> {
|
|||||||
Expr::Lit(Lit::Num(Number { span, value, .. })) => {
|
Expr::Lit(Lit::Num(Number { span, value, .. })) => {
|
||||||
if value.is_sign_negative() {
|
if value.is_sign_negative() {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("numbers: Lifting `-` in a literal");
|
report_change!("numbers: Lifting `-` in a literal");
|
||||||
|
|
||||||
*e = Expr::Unary(UnaryExpr {
|
*e = Expr::Unary(UnaryExpr {
|
||||||
span: arg.span,
|
span: arg.span,
|
||||||
|
@ -25,7 +25,7 @@ impl Pure<'_> {
|
|||||||
match &*c.expr {
|
match &*c.expr {
|
||||||
Expr::Lit(Lit::Str(s)) if is_valid_identifier(&s.value, true) => {
|
Expr::Lit(Lit::Str(s)) if is_valid_identifier(&s.value, true) => {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"properties: Computed member => member expr with identifier as a prop"
|
"properties: Computed member => member expr with identifier as a prop"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ impl Pure<'_> {
|
|||||||
|
|
||||||
if is_valid_identifier(&s.value, false) {
|
if is_valid_identifier(&s.value, false) {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("misc: Optimizing string property name");
|
report_change!("misc: Optimizing string property name");
|
||||||
*name = PropName::Ident(Ident {
|
*name = PropName::Ident(Ident {
|
||||||
span: s.span,
|
span: s.span,
|
||||||
sym: s.value.clone(),
|
sym: s.value.clone(),
|
||||||
@ -165,7 +165,7 @@ impl Pure<'_> {
|
|||||||
Prop::Shorthand(_) => {}
|
Prop::Shorthand(_) => {}
|
||||||
Prop::KeyValue(p) => {
|
Prop::KeyValue(p) => {
|
||||||
if prop_name_eq(&p.key, &key.sym) {
|
if prop_name_eq(&p.key, &key.sym) {
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"properties: Inlining a key-value property `{}`",
|
"properties: Inlining a key-value property `{}`",
|
||||||
key.sym
|
key.sym
|
||||||
);
|
);
|
||||||
|
@ -25,7 +25,7 @@ impl Pure<'_> {
|
|||||||
PatOrExpr::Pat(left) => {
|
PatOrExpr::Pat(left) => {
|
||||||
if let Pat::Ident(left) = &**left {
|
if let Pat::Ident(left) = &**left {
|
||||||
if left.id.sym == ident.sym && left.id.span.ctxt == ident.span.ctxt {
|
if left.id.sym == ident.sym && left.id.span.ctxt == ident.span.ctxt {
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"drop_useless_ident_ref_in_seq: Dropping `{}` as it's useless",
|
"drop_useless_ident_ref_in_seq: Dropping `{}` as it's useless",
|
||||||
left.id
|
left.id
|
||||||
);
|
);
|
||||||
@ -52,7 +52,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("sequences: Lifting sequence in a binary expression");
|
report_change!("sequences: Lifting sequence in a binary expression");
|
||||||
|
|
||||||
let left_last = left.exprs.pop().unwrap();
|
let left_last = left.exprs.pop().unwrap();
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ impl Pure<'_> {
|
|||||||
new_seq.extend(test.exprs.drain(..test.exprs.len() - 1));
|
new_seq.extend(test.exprs.drain(..test.exprs.len() - 1));
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("sequences: Lifting sequences in a assignment with cond expr");
|
report_change!("sequences: Lifting sequences in a assignment with cond expr");
|
||||||
let new_cond = CondExpr {
|
let new_cond = CondExpr {
|
||||||
span: cond.span,
|
span: cond.span,
|
||||||
test: test.exprs.pop().unwrap(),
|
test: test.exprs.pop().unwrap(),
|
||||||
@ -188,7 +188,7 @@ impl Pure<'_> {
|
|||||||
});
|
});
|
||||||
b.take();
|
b.take();
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"sequences: Reducing `(a = foo, a.call())` to `((a = foo).call())`"
|
"sequences: Reducing `(a = foo, a.call())` to `((a = foo).call())`"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -55,9 +55,7 @@ impl Pure<'_> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
trace_op!("compress_tpl");
|
||||||
tracing::debug!("compress_tpl");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut quasis = vec![];
|
let mut quasis = vec![];
|
||||||
let mut exprs = vec![];
|
let mut exprs = vec![];
|
||||||
@ -112,7 +110,7 @@ impl Pure<'_> {
|
|||||||
if let Some(l_last) = l.quasis.last_mut() {
|
if let Some(l_last) = l.quasis.last_mut() {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
|
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"template: Concatted a string (`{}`) on rhs of `+` to a template literal",
|
"template: Concatted a string (`{}`) on rhs of `+` to a template literal",
|
||||||
rs.value
|
rs.value
|
||||||
);
|
);
|
||||||
@ -130,7 +128,7 @@ impl Pure<'_> {
|
|||||||
if let Some(r_first) = r.quasis.first_mut() {
|
if let Some(r_first) = r.quasis.first_mut() {
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
|
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"template: Prepended a string (`{}`) on lhs of `+` to a template literal",
|
"template: Prepended a string (`{}`) on lhs of `+` to a template literal",
|
||||||
ls.value
|
ls.value
|
||||||
);
|
);
|
||||||
@ -162,7 +160,7 @@ impl Pure<'_> {
|
|||||||
|
|
||||||
debug_assert!(l.quasis.len() == l.exprs.len() + 1, "{:?} is invalid", l);
|
debug_assert!(l.quasis.len() == l.exprs.len() + 1, "{:?} is invalid", l);
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("strings: Merged to template literals");
|
report_change!("strings: Merged to template literals");
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -194,7 +192,7 @@ impl Pure<'_> {
|
|||||||
let left_span = left.span;
|
let left_span = left.span;
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"strings: Concatting `{} + {}` to `{}`",
|
"strings: Concatting `{} + {}` to `{}`",
|
||||||
second_str,
|
second_str,
|
||||||
third_str,
|
third_str,
|
||||||
@ -237,7 +235,7 @@ impl Pure<'_> {
|
|||||||
})) = &**left
|
})) = &**left
|
||||||
{
|
{
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"string: Dropping empty string literal (in lhs) because it does not \
|
"string: Dropping empty string literal (in lhs) because it does not \
|
||||||
changes type"
|
changes type"
|
||||||
);
|
);
|
||||||
@ -252,7 +250,7 @@ impl Pure<'_> {
|
|||||||
})) = &**right
|
})) = &**right
|
||||||
{
|
{
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"string: Dropping empty string literal (in rhs) because it does not \
|
"string: Dropping empty string literal (in rhs) because it does not \
|
||||||
changes type"
|
changes type"
|
||||||
);
|
);
|
||||||
|
@ -53,7 +53,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::debug!("join_vars: Joining variables");
|
report_change!("join_vars: Joining variables");
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
|
|
||||||
let mut cur: Option<VarDecl> = None;
|
let mut cur: Option<VarDecl> = None;
|
||||||
@ -209,7 +209,7 @@ impl Pure<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
tracing::debug!("collapse_vars: Collapsing variables without an initializer");
|
report_change!("collapse_vars: Collapsing variables without an initializer");
|
||||||
|
|
||||||
let vars = {
|
let vars = {
|
||||||
let mut v = VarMover {
|
let mut v = VarMover {
|
||||||
|
@ -54,7 +54,7 @@ fn negate_inner(e: &mut Expr, in_bool_ctx: bool, is_ret_val_ignored: bool) -> bo
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
tracing::debug!("negate: binary");
|
report_change!("negate: binary");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ fn negate_inner(e: &mut Expr, in_bool_ctx: bool, is_ret_val_ignored: bool) -> bo
|
|||||||
op: op @ op!("&&"),
|
op: op @ op!("&&"),
|
||||||
..
|
..
|
||||||
}) if is_ok_to_negate_rhs(right) => {
|
}) if is_ok_to_negate_rhs(right) => {
|
||||||
tracing::debug!("negate: a && b => !a || !b");
|
trace_op!("negate: a && b => !a || !b");
|
||||||
|
|
||||||
let a = negate_inner(&mut **left, in_bool_ctx, false);
|
let a = negate_inner(&mut **left, in_bool_ctx, false);
|
||||||
let b = negate_inner(&mut **right, in_bool_ctx, is_ret_val_ignored);
|
let b = negate_inner(&mut **right, in_bool_ctx, is_ret_val_ignored);
|
||||||
@ -78,7 +78,7 @@ fn negate_inner(e: &mut Expr, in_bool_ctx: bool, is_ret_val_ignored: bool) -> bo
|
|||||||
op: op @ op!("||"),
|
op: op @ op!("||"),
|
||||||
..
|
..
|
||||||
}) if is_ok_to_negate_rhs(right) => {
|
}) if is_ok_to_negate_rhs(right) => {
|
||||||
tracing::debug!("negate: a || b => !a && !b");
|
trace_op!("negate: a || b => !a && !b");
|
||||||
|
|
||||||
let a = negate_inner(&mut **left, in_bool_ctx, false);
|
let a = negate_inner(&mut **left, in_bool_ctx, false);
|
||||||
let b = negate_inner(&mut **right, in_bool_ctx, is_ret_val_ignored);
|
let b = negate_inner(&mut **right, in_bool_ctx, is_ret_val_ignored);
|
||||||
@ -89,7 +89,7 @@ fn negate_inner(e: &mut Expr, in_bool_ctx: bool, is_ret_val_ignored: bool) -> bo
|
|||||||
Expr::Cond(CondExpr { cons, alt, .. })
|
Expr::Cond(CondExpr { cons, alt, .. })
|
||||||
if is_ok_to_negate_for_cond(cons) && is_ok_to_negate_for_cond(alt) =>
|
if is_ok_to_negate_for_cond(cons) && is_ok_to_negate_for_cond(alt) =>
|
||||||
{
|
{
|
||||||
tracing::debug!("negate: cond");
|
trace_op!("negate: cond");
|
||||||
|
|
||||||
let a = negate_inner(&mut **cons, in_bool_ctx, false);
|
let a = negate_inner(&mut **cons, in_bool_ctx, false);
|
||||||
let b = negate_inner(&mut **alt, in_bool_ctx, is_ret_val_ignored);
|
let b = negate_inner(&mut **alt, in_bool_ctx, is_ret_val_ignored);
|
||||||
@ -98,7 +98,7 @@ fn negate_inner(e: &mut Expr, in_bool_ctx: bool, is_ret_val_ignored: bool) -> bo
|
|||||||
|
|
||||||
Expr::Seq(SeqExpr { exprs, .. }) => {
|
Expr::Seq(SeqExpr { exprs, .. }) => {
|
||||||
if let Some(last) = exprs.last_mut() {
|
if let Some(last) = exprs.last_mut() {
|
||||||
tracing::debug!("negate: seq");
|
trace_op!("negate: seq");
|
||||||
|
|
||||||
return negate_inner(&mut **last, in_bool_ctx, is_ret_val_ignored);
|
return negate_inner(&mut **last, in_bool_ctx, is_ret_val_ignored);
|
||||||
}
|
}
|
||||||
@ -115,7 +115,7 @@ fn negate_inner(e: &mut Expr, in_bool_ctx: bool, is_ret_val_ignored: bool) -> bo
|
|||||||
{
|
{
|
||||||
match &mut **arg {
|
match &mut **arg {
|
||||||
Expr::Unary(UnaryExpr { op: op!("!"), .. }) => {
|
Expr::Unary(UnaryExpr { op: op!("!"), .. }) => {
|
||||||
tracing::debug!("negate: !!bool => !bool");
|
report_change!("negate: !!bool => !bool");
|
||||||
*e = *arg.take();
|
*e = *arg.take();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -124,19 +124,19 @@ fn negate_inner(e: &mut Expr, in_bool_ctx: bool, is_ret_val_ignored: bool) -> bo
|
|||||||
op: op!("instanceof"),
|
op: op!("instanceof"),
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
tracing::debug!("negate: !bool => bool");
|
report_change!("negate: !bool => bool");
|
||||||
*e = *arg.take();
|
*e = *arg.take();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if in_bool_ctx {
|
if in_bool_ctx {
|
||||||
tracing::debug!("negate: !expr => expr (in bool context)");
|
report_change!("negate: !expr => expr (in bool context)");
|
||||||
*e = *arg.take();
|
*e = *arg.take();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_ret_val_ignored {
|
if is_ret_val_ignored {
|
||||||
tracing::debug!("negate: !expr => expr (return value ignored)");
|
report_change!("negate: !expr => expr (return value ignored)");
|
||||||
*e = *arg.take();
|
*e = *arg.take();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -145,12 +145,12 @@ fn negate_inner(e: &mut Expr, in_bool_ctx: bool, is_ret_val_ignored: bool) -> bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if is_ret_val_ignored {
|
if is_ret_val_ignored {
|
||||||
tracing::debug!("negate: noop because it's ignored");
|
log_abort!("negate: noop because it's ignored");
|
||||||
*e = *arg;
|
*e = *arg;
|
||||||
|
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
tracing::debug!("negate: e => !e");
|
report_change!("negate: e => !e");
|
||||||
|
|
||||||
*e = Expr::Unary(UnaryExpr {
|
*e = Expr::Unary(UnaryExpr {
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
@ -158,9 +158,7 @@ fn negate_inner(e: &mut Expr, in_bool_ctx: bool, is_ret_val_ignored: bool) -> bo
|
|||||||
arg,
|
arg,
|
||||||
});
|
});
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
dump_change_detail!("Negated `{}` as `{}`", start_str, dump(&*e, false));
|
||||||
tracing::trace!("[Change] Negated `{}` as `{}`", start_str, dump(&*e, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -343,7 +341,7 @@ pub(crate) fn negate_cost(e: &Expr, in_bool_ctx: bool, is_ret_val_ignored: bool)
|
|||||||
|
|
||||||
// Print more info while testing negate_cost
|
// Print more info while testing negate_cost
|
||||||
if cfg!(test) {
|
if cfg!(test) {
|
||||||
tracing::debug!(
|
trace_op!(
|
||||||
"negation cost of `{}` = {}",
|
"negation cost of `{}` = {}",
|
||||||
dump(&e.clone().fold_with(&mut as_folder(fixer(None))), true),
|
dump(&e.clone().fold_with(&mut as_folder(fixer(None))), true),
|
||||||
cost,
|
cost,
|
||||||
@ -355,15 +353,13 @@ pub(crate) fn negate_cost(e: &Expr, in_bool_ctx: bool, is_ret_val_ignored: bool)
|
|||||||
|
|
||||||
let cost = cost(e, in_bool_ctx, None, is_ret_val_ignored);
|
let cost = cost(e, in_bool_ctx, None, is_ret_val_ignored);
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
trace_op!(
|
||||||
tracing::trace!(
|
"negation cost of `{}` = {}\nin_book_ctx={:?}\nis_ret_val_ignored={:?}",
|
||||||
"negation cost of `{}` = {}\nin_book_ctx={:?}\nis_ret_val_ignored={:?}",
|
dump(&e.clone().fold_with(&mut as_folder(fixer(None))), false),
|
||||||
dump(&e.clone().fold_with(&mut as_folder(fixer(None))), false),
|
cost,
|
||||||
cost,
|
in_bool_ctx,
|
||||||
in_bool_ctx,
|
is_ret_val_ignored
|
||||||
is_ret_val_ignored
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
cost
|
cost
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,8 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod macros;
|
||||||
mod analyzer;
|
mod analyzer;
|
||||||
mod compress;
|
mod compress;
|
||||||
mod debug;
|
mod debug;
|
||||||
|
42
crates/swc_ecma_minifier/src/macros.rs
Normal file
42
crates/swc_ecma_minifier/src/macros.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/// Used when something is modified.
|
||||||
|
macro_rules! report_change {
|
||||||
|
($($tt:tt)+) => {{
|
||||||
|
tracing::debug!(
|
||||||
|
kind = "change",
|
||||||
|
$($tt)*
|
||||||
|
);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used when a function decided to give up.
|
||||||
|
macro_rules! log_abort {
|
||||||
|
($($tt:tt)+) => {{
|
||||||
|
if cfg!(feature = "debug") {
|
||||||
|
tracing::trace!(
|
||||||
|
kind = "abort",
|
||||||
|
$($tt)*
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! dump_change_detail {
|
||||||
|
($($tt:tt)+) => {{
|
||||||
|
if cfg!(feature = "debug") {
|
||||||
|
tracing::trace!(
|
||||||
|
kind = "detail",
|
||||||
|
$($tt)*
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! trace_op {
|
||||||
|
($($tt:tt)+) => {{
|
||||||
|
if cfg!(feature = "debug") {
|
||||||
|
tracing::trace!(
|
||||||
|
$($tt)*
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
@ -292,27 +292,25 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
if external_bindings.contains(used_id) {
|
if external_bindings.contains(used_id) {
|
||||||
if cfg!(feature = "debug") {
|
trace_op!(
|
||||||
tracing::debug!(
|
"bundle: Due to {}{:?} (top-level), it's not a bundle",
|
||||||
"bundle: Due to {}{:?} (top-level), it's not a bundle",
|
used_id.0,
|
||||||
used_id.0,
|
used_id.1
|
||||||
used_id.1
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if used_id.1 == top_level_ctxt {
|
if used_id.1 == top_level_ctxt {
|
||||||
// if cfg!(feature = "debug") {
|
// if cfg!(feature = "debug") {
|
||||||
// tracing::debug!("bundle: Ignoring {}{:?} (top level)", used_id.0,
|
// debug!("bundle: Ignoring {}{:?} (top level)", used_id.0,
|
||||||
// used_id.1); }
|
// used_id.1); }
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if bindings.contains(used_id) {
|
if bindings.contains(used_id) {
|
||||||
// if cfg!(feature = "debug") {
|
// if cfg!(feature = "debug") {
|
||||||
// tracing::debug!(
|
// debug!(
|
||||||
// "bundle: Ignoring {}{:?} (local to fn)",
|
// "bundle: Ignoring {}{:?} (local to fn)",
|
||||||
// used_id.0,
|
// used_id.0,
|
||||||
// used_id.1
|
// used_id.1
|
||||||
@ -321,13 +319,12 @@ where
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg!(feature = "debug") {
|
trace_op!(
|
||||||
tracing::debug!(
|
"bundle: Due to {}{:?}, it's not a bundle",
|
||||||
"bundle: Due to {}{:?}, it's not a bundle",
|
used_id.0,
|
||||||
used_id.0,
|
used_id.1
|
||||||
used_id.1
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,9 +499,7 @@ fn value_to_expr(v: Value) -> Box<Expr> {
|
|||||||
value,
|
value,
|
||||||
}))),
|
}))),
|
||||||
Value::Number(v) => {
|
Value::Number(v) => {
|
||||||
if cfg!(feature = "debug") {
|
trace_op!("Creating a numeric literal from value");
|
||||||
tracing::debug!("Creating a numeric literal from value");
|
|
||||||
}
|
|
||||||
|
|
||||||
Box::new(Expr::Lit(Lit::Num(Number {
|
Box::new(Expr::Lit(Lit::Num(Number {
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use fxhash::{AHashMap, AHashSet};
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
use fxhash::{AHashMap, AHashSet};
|
||||||
use swc_atoms::JsWord;
|
use swc_atoms::JsWord;
|
||||||
use swc_common::{SyntaxContext, DUMMY_SP};
|
use swc_common::{SyntaxContext, DUMMY_SP};
|
||||||
use swc_ecma_ast::*;
|
use swc_ecma_ast::*;
|
||||||
@ -100,7 +101,7 @@ impl Visit for VarAnalyzer<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_ident(&mut self, i: &Ident) {
|
fn visit_ident(&mut self, i: &Ident) {
|
||||||
tracing::trace!("hygiene/vars: Found {}", i);
|
trace!("hygiene/vars: Found {}", i);
|
||||||
|
|
||||||
self.cur.add(i);
|
self.cur.add(i);
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ impl PostcompressOptimizer<'_> {
|
|||||||
op!("&&")
|
op!("&&")
|
||||||
};
|
};
|
||||||
|
|
||||||
tracing::debug!(
|
report_change!(
|
||||||
"bools: `(a {} !b)` => `(a {} b)` (in bool context)",
|
"bools: `(a {} !b)` => `(a {} b)` (in bool context)",
|
||||||
*op,
|
*op,
|
||||||
new_op
|
new_op
|
||||||
|
@ -16,9 +16,7 @@ pub(crate) mod unit;
|
|||||||
|
|
||||||
///
|
///
|
||||||
pub(crate) fn make_number(span: Span, value: f64) -> Expr {
|
pub(crate) fn make_number(span: Span, value: f64) -> Expr {
|
||||||
if cfg!(feature = "debug") {
|
trace_op!("Creating a numeric literal");
|
||||||
tracing::debug!("Creating a numeric literal");
|
|
||||||
}
|
|
||||||
Expr::Lit(Lit::Num(Number {
|
Expr::Lit(Lit::Num(Number {
|
||||||
span,
|
span,
|
||||||
value,
|
value,
|
||||||
@ -94,9 +92,8 @@ impl ModuleItemExt for ModuleItem {
|
|||||||
/// - `!0` for true
|
/// - `!0` for true
|
||||||
/// - `!1` for false
|
/// - `!1` for false
|
||||||
pub(crate) fn make_bool(span: Span, value: bool) -> Expr {
|
pub(crate) fn make_bool(span: Span, value: bool) -> Expr {
|
||||||
if cfg!(feature = "debug") {
|
trace_op!("Creating a boolean literal");
|
||||||
tracing::debug!("Creating a boolean literal");
|
|
||||||
}
|
|
||||||
Expr::Unary(UnaryExpr {
|
Expr::Unary(UnaryExpr {
|
||||||
span,
|
span,
|
||||||
op: op!("!"),
|
op: op!("!"),
|
||||||
|
@ -455,9 +455,6 @@ issue_2719/warn/input.js
|
|||||||
issue_281/collapse_vars_constants/input.js
|
issue_281/collapse_vars_constants/input.js
|
||||||
issue_281/inner_var_for_in_1/input.js
|
issue_281/inner_var_for_in_1/input.js
|
||||||
issue_281/issue_1758/input.js
|
issue_281/issue_1758/input.js
|
||||||
issue_281/pure_annotation_1/input.js
|
|
||||||
issue_281/pure_annotation_2/input.js
|
|
||||||
issue_281/ref_scope/input.js
|
|
||||||
issue_2871/comparison_with_undefined/input.js
|
issue_2871/comparison_with_undefined/input.js
|
||||||
issue_368/collapse/input.js
|
issue_368/collapse/input.js
|
||||||
issue_417/test_unexpected_crash/input.js
|
issue_417/test_unexpected_crash/input.js
|
||||||
|
@ -788,6 +788,9 @@ issue_281/negate_iife_4/input.js
|
|||||||
issue_281/negate_iife_5/input.js
|
issue_281/negate_iife_5/input.js
|
||||||
issue_281/negate_iife_5_off/input.js
|
issue_281/negate_iife_5_off/input.js
|
||||||
issue_281/negate_iife_issue_1073/input.js
|
issue_281/negate_iife_issue_1073/input.js
|
||||||
|
issue_281/pure_annotation_1/input.js
|
||||||
|
issue_281/pure_annotation_2/input.js
|
||||||
|
issue_281/ref_scope/input.js
|
||||||
issue_281/safe_undefined/input.js
|
issue_281/safe_undefined/input.js
|
||||||
issue_281/wrap_iife/input.js
|
issue_281/wrap_iife/input.js
|
||||||
issue_281/wrap_iife_in_expression/input.js
|
issue_281/wrap_iife_in_expression/input.js
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
(function () {
|
/*#__PURE__*/ (function () {
|
||||||
console.log("hello");
|
console.log("hello");
|
||||||
})();
|
})();
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
(function (n) {
|
/*#__PURE__*/ (function (n) {
|
||||||
console.log("hello", n);
|
console.log("hello", n);
|
||||||
})(42);
|
})(42);
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
console.log(
|
console.log(function() {
|
||||||
(function () {
|
var a = 1, b = 2, c = 3;
|
||||||
var a = 1,
|
var a = c++, b = b /= a;
|
||||||
b = 2,
|
return a + b;
|
||||||
c = 3;
|
}());
|
||||||
b = b /= a = c++;
|
|
||||||
return a + b;
|
|
||||||
})()
|
|
||||||
);
|
|
||||||
|
@ -75,6 +75,7 @@
|
|||||||
"impls",
|
"impls",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"initializers",
|
"initializers",
|
||||||
|
"inlinable",
|
||||||
"inlines",
|
"inlines",
|
||||||
"instanceof",
|
"instanceof",
|
||||||
"interner",
|
"interner",
|
||||||
|
Loading…
Reference in New Issue
Block a user