Skip to content

Commit 68dabd7

Browse files
committed
lookahead decl
1 parent f7a6df1 commit 68dabd7

File tree

13 files changed

+534
-186
lines changed

13 files changed

+534
-186
lines changed

crates/swc_ecma_ast/src/expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#![allow(clippy::vec_box)]
2-
use std::{borrow::Cow, mem::transmute};
2+
use std::mem::transmute;
33

44
use is_macro::Is;
55
use string_enum::StringEnum;

crates/swc_ecma_minifier/src/compress/optimize/conditionals.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ impl Optimizer<'_> {
387387
// to f(a, a = 1 ? true : false)
388388
let side_effects_in_test = test.may_have_side_effects(self.ctx.expr_ctx);
389389

390-
if self.data.contains_unresolved(test) {
390+
if self.data.contains_unresolved(test, self.r) {
391391
return None;
392392
}
393393

@@ -526,7 +526,7 @@ impl Optimizer<'_> {
526526
}
527527

528528
(Expr::New(cons), Expr::New(alt)) => {
529-
if self.data.contains_unresolved(test) {
529+
if self.data.contains_unresolved(test, self.r) {
530530
return None;
531531
}
532532

@@ -590,7 +590,7 @@ impl Optimizer<'_> {
590590
) if cons.left.eq_ignore_span(&alt.left) && cons.left.as_ident().is_some() => {
591591
if self
592592
.data
593-
.ident_is_unresolved(&cons.left.as_ident().unwrap().id)
593+
.ident_is_unresolved(&cons.left.as_ident().unwrap().id, self.r)
594594
{
595595
return None;
596596
}

crates/swc_ecma_minifier/src/compress/optimize/evaluate.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,13 +488,15 @@ impl Optimizer<'_> {
488488
report_change!("evaluate: `{} / 0` => `Infinity`", ln);
489489

490490
// Sign does not matter for NaN
491+
let mut ident = Ident::new_no_ctxt(atom!("Infinity"), bin.span);
492+
self.r.add_unresolved(&mut ident);
491493
*e = if ln.is_sign_positive() == rn.is_sign_positive() {
492-
Ident::new_no_ctxt(atom!("Infinity"), bin.span).into()
494+
ident.into()
493495
} else {
494496
UnaryExpr {
495497
span: bin.span,
496498
op: op!(unary, "-"),
497-
arg: Ident::new_no_ctxt(atom!("Infinity"), bin.span).into(),
499+
arg: ident.into(),
498500
}
499501
.into()
500502
};

crates/swc_ecma_minifier/src/compress/optimize/inline.rs

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,13 @@ impl Optimizer<'_> {
5959
}
6060
}
6161

62-
if let Some(usage) = self.data.vars.get(&ident.node_id) {
62+
let node_id = match self.r.find_binding_by_ident(ident) {
63+
RefTo::Itself => ident.node_id,
64+
RefTo::Binding(node_id) => node_id,
65+
RefTo::Unresolved => return,
66+
};
67+
debug_assert!(node_id != NodeId::DUMMY);
68+
if let Some(usage) = self.data.vars.get(&node_id) {
6369
let ref_count = usage.ref_count - u32::from(can_drop && usage.ref_count > 1);
6470
if !usage.flags.contains(VarUsageInfoFlags::VAR_INITIALIZED) {
6571
return;
@@ -97,7 +103,7 @@ impl Optimizer<'_> {
97103

98104
// No use => dropped
99105
if ref_count == 0 {
100-
self.mode.store(ident.node_id, &*init);
106+
self.mode.store(node_id, &*init);
101107

102108
if init.may_have_side_effects(self.ctx.expr_ctx) {
103109
// TODO: Inline partially
@@ -113,8 +119,6 @@ impl Optimizer<'_> {
113119

114120
let mut inlined_into_init = false;
115121

116-
let id = ident.node_id;
117-
118122
// We inline arrays partially if it's pure (all elements are literal), and not
119123
// modified.
120124
// We don't drop definition, but we just inline array accesses with numeric
@@ -150,7 +154,7 @@ impl Optimizer<'_> {
150154
);
151155
self.vars
152156
.lits_for_array_access
153-
.insert(ident.node_id, Box::new(init.clone()));
157+
.insert(node_id, Box::new(init.clone()));
154158
}
155159
}
156160
}
@@ -194,7 +198,7 @@ impl Optimizer<'_> {
194198
}
195199

196200
if !usage.mutated() {
197-
self.mode.store(ident.node_id, &*init);
201+
self.mode.store(node_id, &*init);
198202
}
199203

200204
if usage.flags.contains(VarUsageInfoFlags::USED_RECURSIVELY) {
@@ -285,9 +289,7 @@ impl Optimizer<'_> {
285289
{
286290
true
287291
} else {
288-
self.vars
289-
.lits_for_cmp
290-
.insert(ident.node_id, init.clone().into());
292+
self.vars.lits_for_cmp.insert(node_id, init.clone().into());
291293
false
292294
}
293295
}
@@ -317,7 +319,7 @@ impl Optimizer<'_> {
317319
self.vars.inline_with_multi_replacer(init, self.r);
318320
}
319321

320-
self.mode.store(id, &*init);
322+
self.mode.store(node_id, &*init);
321323

322324
let VarUsageInfo {
323325
usage_count,
@@ -327,11 +329,7 @@ impl Optimizer<'_> {
327329
} = **usage;
328330
let mut inc_usage = || {
329331
if let Expr::Ident(i) = &*init {
330-
let node_id = match self.r.find_binding_by_ident(i) {
331-
RefTo::Binding(node_id) => node_id,
332-
RefTo::Unresolved => return,
333-
RefTo::Itself => unreachable!(),
334-
};
332+
debug_assert!(matches!(self.r.find_binding_by_ident(i), RefTo::Binding(_)));
335333
debug_assert!(i.node_id != node_id);
336334
if let Some(u) = self.data.vars.get_mut(&node_id) {
337335
u.flags |= flags & VarUsageInfoFlags::USED_AS_ARG;
@@ -373,7 +371,7 @@ impl Optimizer<'_> {
373371

374372
inc_usage();
375373

376-
self.vars.lits.insert(id, init.take().into());
374+
self.vars.lits.insert(node_id, init.take().into());
377375

378376
ident.take();
379377
} else if self.options.inline != 0 || self.options.reduce_vars {
@@ -383,15 +381,15 @@ impl Optimizer<'_> {
383381
ident.ctxt
384382
);
385383

386-
self.mode.store(id, &*init);
384+
self.mode.store(node_id, &*init);
387385

388386
inc_usage();
389387

390-
self.vars.lits.insert(id, init.clone().into());
388+
self.vars.lits.insert(node_id, init.clone().into());
391389
}
392390
}
393391

394-
let usage = self.data.vars.get(&id).unwrap();
392+
let usage = self.data.vars.get(&node_id).unwrap();
395393

396394
// Single use => inlined
397395
if !self.ctx.bit_ctx.contains(BitCtx::IsExported)
@@ -500,7 +498,12 @@ impl Optimizer<'_> {
500498
return;
501499
}
502500

503-
if let Some(init_usage) = self.data.vars.get(&id.node_id) {
501+
let id_node_id = match self.r.find_binding_by_ident(id) {
502+
RefTo::Binding(node_id) => node_id,
503+
RefTo::Itself => unreachable!(),
504+
RefTo::Unresolved => return,
505+
};
506+
if let Some(init_usage) = self.data.vars.get(&id_node_id) {
504507
if init_usage.flags.contains(VarUsageInfoFlags::REASSIGNED)
505508
|| !init_usage.flags.contains(VarUsageInfoFlags::DECLARED)
506509
{
@@ -534,9 +537,12 @@ impl Optimizer<'_> {
534537
_ => {
535538
for id in idents_used_by(init) {
536539
let node_id = match self.r.find_binding_by_node_id(id) {
537-
RefTo::Binding(node_id) => node_id,
540+
RefTo::Binding(node_id) => {
541+
debug_assert!(id != node_id);
542+
node_id
543+
}
544+
RefTo::Itself => id,
538545
RefTo::Unresolved => continue,
539-
RefTo::Itself => unreachable!(),
540546
};
541547
if let Some(v_usage) = self.data.vars.get(&node_id) {
542548
if v_usage.property_mutation_count > usage.property_mutation_count
@@ -664,6 +670,7 @@ impl Optimizer<'_> {
664670
return;
665671
}
666672

673+
debug_assert_eq!(self.r.find_binding_by_ident(&i), RefTo::Itself);
667674
if let Some(usage) = self.data.vars.get(&i.node_id) {
668675
if !usage.flags.contains(VarUsageInfoFlags::REASSIGNED) {
669676
trace_op!("typeofs: Storing typeof `{}{:?}`", i.sym, i.ctxt);
@@ -724,6 +731,7 @@ impl Optimizer<'_> {
724731
return;
725732
}
726733

734+
debug_assert_eq!(self.r.find_binding_by_ident(&i), RefTo::Itself);
727735
let id = i.node_id;
728736

729737
if let Some(usage) = self.data.vars.get(&id) {
@@ -792,7 +800,7 @@ impl Optimizer<'_> {
792800
}
793801

794802
self.vars.simple_functions.insert(
795-
i.node_id,
803+
id,
796804
FnExpr {
797805
ident: None,
798806
function: f.function.clone(),
@@ -888,7 +896,7 @@ impl Optimizer<'_> {
888896
}
889897
};
890898

891-
self.vars.vars_for_inlining.insert(i.node_id, e);
899+
self.vars.vars_for_inlining.insert(id, e);
892900
} else {
893901
log_abort!("inline: [x] Usage: {:?}", usage);
894902
}
@@ -906,7 +914,16 @@ impl Optimizer<'_> {
906914
if let MemberProp::Computed(prop) = &mut me.prop {
907915
if let Expr::Lit(Lit::Num(..)) = &*prop.expr {
908916
if let Expr::Ident(obj) = &*me.obj {
909-
let new = self.vars.lits_for_array_access.get(&obj.node_id);
917+
let node_id = match self.r.find_binding_by_ident(obj) {
918+
RefTo::Unresolved => None,
919+
RefTo::Binding(node_id) => Some(node_id),
920+
RefTo::Itself => unreachable!(),
921+
};
922+
923+
let new = node_id.and_then(|node_id| {
924+
debug_assert!(node_id != obj.node_id);
925+
self.vars.lits_for_array_access.get(&node_id)
926+
});
910927

911928
if let Some(new) = new {
912929
report_change!("inline: Inlined array access");
@@ -924,6 +941,9 @@ impl Optimizer<'_> {
924941
RefTo::Unresolved => return,
925942
RefTo::Itself => unreachable!(),
926943
};
944+
debug_assert!(i.node_id != node_id);
945+
debug_assert!(i.node_id != NodeId::DUMMY);
946+
debug_assert!(node_id != NodeId::DUMMY);
927947

928948
if let Some(mut value) = self
929949
.vars
@@ -946,7 +966,7 @@ impl Optimizer<'_> {
946966

947967
// currently renamer relies on the fact no distinct var has same ctxt, we need
948968
// to remap all new bindings.
949-
// let bindings: FxHashSet<NodeId> = collect_decls(&*value);
969+
let bindings: FxHashSet<NodeId> = collect_decls(&*value);
950970
// let new_mark = Mark::new();
951971
// let mut cache = FxHashMap::default();
952972
// let mut remap = FxHashMap::default();
@@ -992,7 +1012,7 @@ impl Optimizer<'_> {
9921012
}
9931013
}
9941014

995-
if let Some(value) = self.vars.vars_for_inlining.remove(&i.node_id) {
1015+
if let Some(value) = self.vars.vars_for_inlining.remove(&node_id) {
9961016
self.changed = true;
9971017
report_change!("inline: Replacing '{}' with an expression", i);
9981018

crates/swc_ecma_minifier/src/compress/optimize/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ impl Vars {
303303
hoisted_props: &self.hoisted_props,
304304
vars_to_remove: &self.removed,
305305
changed: false,
306+
r,
306307
};
307308
n.visit_mut_with(&mut v);
308309
changed |= v.changed;
@@ -1817,7 +1818,11 @@ impl VisitMut for Optimizer<'_> {
18171818
..
18181819
}) => {
18191820
if let Some(i) = left.as_ident_mut() {
1820-
let old = i.node_id;
1821+
let old = match self.r.find_binding_by_ident(i) {
1822+
RefTo::Itself => i.node_id,
1823+
RefTo::Binding(node_id) => node_id,
1824+
RefTo::Unresolved => return,
1825+
};
18211826

18221827
self.store_var_for_inlining(i, right, false);
18231828

crates/swc_ecma_minifier/src/compress/optimize/sequences.rs

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::{iter::once, mem::take};
33
use rustc_hash::FxHashSet;
44
use swc_common::{pass::Either, util::take::Take, EqIgnoreSpan, NodeId, Spanned, DUMMY_SP};
55
use swc_ecma_ast::*;
6+
use swc_ecma_transforms_base::resolve::RefTo;
67
use swc_ecma_usage_analyzer::{
78
alias::{try_collect_infects_from, AccessKind, AliasConfig},
89
util::is_global_var_with_pure_property_access,
@@ -2385,8 +2386,15 @@ impl Optimizer<'_> {
23852386
let take_a = |a: &mut Mergable, force_drop: bool, drop_op| {
23862387
match a {
23872388
Mergable::Var(a) => {
2389+
let left_node_id = match self.r.find_binding_by_ident(&left_id) {
2390+
RefTo::Binding(node_id) => node_id,
2391+
RefTo::Itself => left_id.node_id,
2392+
RefTo::Unresolved => {
2393+
return a.init.clone().unwrap_or_else(|| Expr::undefined(DUMMY_SP))
2394+
}
2395+
};
23882396
if self.options.unused {
2389-
if let Some(usage) = self.data.vars.get(&left_id.node_id) {
2397+
if let Some(usage) = self.data.vars.get(&left_node_id) {
23902398
// We are eliminating one usage, so we use 1 instead of
23912399
// 0
23922400
if !force_drop
@@ -2402,7 +2410,7 @@ impl Optimizer<'_> {
24022410
if can_take_init || force_drop {
24032411
let init = a.init.take();
24042412

2405-
if let Some(usage) = self.data.vars.get(&left_id.node_id) {
2413+
if let Some(usage) = self.data.vars.get(&left_node_id) {
24062414
if usage.var_kind == Some(VarDeclKind::Const) {
24072415
a.init = Some(Expr::undefined(DUMMY_SP));
24082416
}
@@ -2478,38 +2486,45 @@ impl Optimizer<'_> {
24782486
Mergable::FnDecl(_) => Some(op!("=")),
24792487
_ => None,
24802488
};
2481-
2482-
let var_type = self
2483-
.data
2484-
.vars
2485-
.get(&left_id.node_id)
2486-
.and_then(|info| info.merged_var_type);
24872489
let Some(a_type) = a_type else {
24882490
return Ok(false);
24892491
};
2490-
let b_type = b.right.get_type(self.ctx.expr_ctx);
24912492

24922493
if let Some(a_op) = a_op {
2493-
if can_drop_op_for(a_op, b.op, var_type, a_type, b_type) {
2494-
if b_left.ctxt == left_id.ctxt && b_left.sym == left_id.sym {
2495-
if let Some(bin_op) = b.op.to_update() {
2496-
report_change!(
2497-
"sequences: Merged assignment into another (op) assignment"
2498-
);
2499-
self.changed = true;
2500-
2501-
b.op = a_op;
2502-
2503-
let to = take_a(a, true, true);
2504-
2505-
b.right = BinExpr {
2506-
span: DUMMY_SP,
2507-
op: bin_op,
2508-
left: to,
2509-
right: b.right.take(),
2494+
let left_node_id = match self.r.find_binding_by_ident(&left_id) {
2495+
RefTo::Binding(node_id) => Some(node_id),
2496+
RefTo::Itself => Some(left_id.node_id),
2497+
RefTo::Unresolved => None,
2498+
};
2499+
if let Some(left_node_id) = left_node_id {
2500+
let var_type = self
2501+
.data
2502+
.vars
2503+
.get(&left_node_id)
2504+
.and_then(|info| info.merged_var_type);
2505+
let b_type = b.right.get_type(self.ctx.expr_ctx);
2506+
if can_drop_op_for(a_op, b.op, var_type, a_type, b_type) {
2507+
if b_left.ctxt == left_id.ctxt && b_left.sym == left_id.sym {
2508+
if let Some(bin_op) = b.op.to_update() {
2509+
report_change!(
2510+
"sequences: Merged assignment into another (op) \
2511+
assignment"
2512+
);
2513+
self.changed = true;
2514+
2515+
b.op = a_op;
2516+
2517+
let to = take_a(a, true, true);
2518+
2519+
b.right = BinExpr {
2520+
span: DUMMY_SP,
2521+
op: bin_op,
2522+
left: to,
2523+
right: b.right.take(),
2524+
}
2525+
.into();
2526+
return Ok(true);
25102527
}
2511-
.into();
2512-
return Ok(true);
25132528
}
25142529
}
25152530
}

0 commit comments

Comments
 (0)