Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(es/minifier): Make sequential inliner self-repeat #6168

Merged
merged 9 commits into from Oct 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,4 +1,7 @@
//// [computedPropertyNames12_ES5.ts]
var a;
import _class_call_check from "@swc/helpers/src/_class_call_check.mjs";
"hello ".concat(a, " bye");
var n, a, _ref = (void 0) + n;
(function C() {
"use strict";
_class_call_check(this, C), this[n] = n, this[_ref] = 2, this["hello bye"] = 0;
})["hello ".concat(a, " bye")] = 0;
254 changes: 133 additions & 121 deletions crates/swc_ecma_minifier/src/compress/optimize/sequences.rs
Expand Up @@ -771,166 +771,178 @@ where
)
};

for idx in 0..exprs.len() {
for j in idx..exprs.len() {
let (a1, a2) = exprs.split_at_mut(idx);
loop {
let mut did_work = false;

if a1.is_empty() || a2.is_empty() {
break;
}

let a = a1.last_mut().unwrap();
for idx in 0..exprs.len() {
for j in idx..exprs.len() {
let (a1, a2) = exprs.split_at_mut(idx);

if self.options.unused && self.options.sequences() {
if let (Mergable::Var(av), Mergable::Var(bv)) = (&mut *a, &mut a2[j - idx]) {
// We try dropping variable assignments first.
if a1.is_empty() || a2.is_empty() {
break;
}

// Currently, we only drop variable declarations if they have the same name.
if let (Pat::Ident(an), Pat::Ident(bn)) = (&av.name, &bv.name) {
if an.to_id() == bn.to_id() {
// We need to preserve side effect of `av.init`
let a = a1.last_mut().unwrap();

match bv.init.as_deref_mut() {
Some(b_init) => {
if IdentUsageFinder::find(&an.to_id(), b_init) {
log_abort!(
"We can't duplicated binding because initializer \
uses the previous declaration of the variable"
);
break;
}
if self.options.unused && self.options.sequences() {
if let (Mergable::Var(av), Mergable::Var(bv)) = (&mut *a, &mut a2[j - idx])
{
// We try dropping variable assignments first.

// Currently, we only drop variable declarations if they have the same
// name.
if let (Pat::Ident(an), Pat::Ident(bn)) = (&av.name, &bv.name) {
if an.to_id() == bn.to_id() {
// We need to preserve side effect of `av.init`

match bv.init.as_deref_mut() {
Some(b_init) => {
if IdentUsageFinder::find(&an.to_id(), b_init) {
log_abort!(
"We can't duplicated binding because \
initializer uses the previous declaration of \
the variable"
);
break;
}

if let Some(a_init) = av.init.take() {
let b_seq = b_init.force_seq();
b_seq.exprs.insert(0, a_init);
if let Some(a_init) = av.init.take() {
let b_seq = b_init.force_seq();
b_seq.exprs.insert(0, a_init);

self.changed = true;
report_change!(
"Moving initializer sequentially as they have \
a same name"
);
av.name.take();
continue;
} else {
self.changed = true;
report_change!(
"Dropping the previous var declaration of {} \
which does not have an initializer",
an.id
);
av.name.take();
continue;
}
}
None => {
// As variable name is same, we can move initializer

// Th code below
//
// var a = 5;
// var a;
//
// console.log(a)
//
// prints 5
bv.init = av.init.take();
self.changed = true;
report_change!(
"Moving initializer sequentially as they have a \
same name"
);
av.name.take();
continue;
} else {
self.changed = true;
report_change!(
"Dropping the previous var declaration of {} \
which does not have an initializer",
an.id
"Moving initializer to the next variable \
declaration as they have the same name"
);
av.name.take();
continue;
}
}
None => {
// As variable name is same, we can move initializer

// Th code below
//
// var a = 5;
// var a;
//
// console.log(a)
//
// prints 5
bv.init = av.init.take();
self.changed = true;
report_change!(
"Moving initializer to the next variable declaration \
as they have the same name"
);
av.name.take();
continue;
}
}
}
}
}
}

// Merge sequentially
// Merge sequentially

if self.merge_sequential_expr(
a,
match &mut a2[j - idx] {
Mergable::Var(b) => match b.init.as_deref_mut() {
Some(v) => v,
None => continue,
if self.merge_sequential_expr(
a,
match &mut a2[j - idx] {
Mergable::Var(b) => match b.init.as_deref_mut() {
Some(v) => v,
None => continue,
},
Mergable::Expr(e) => e,
},
Mergable::Expr(e) => e,
},
)? {
break;
}
)? {
did_work = true;
break;
}

// This logic is required to handle
//
// var b;
// (function () {
// function f() {
// a++;
// }
// f();
// var c = f();
// var a = void 0;
// c || (b = a);
// })();
// console.log(b);
//
//
// at the code above, c cannot be shifted to `c` in `c || (b = a)`
//
// This logic is required to handle
//
// var b;
// (function () {
// function f() {
// a++;
// }
// f();
// var c = f();
// var a = void 0;
// c || (b = a);
// })();
// console.log(b);
//
//
// at the code above, c cannot be shifted to `c` in `c || (b = a)`
//

match a {
Mergable::Var(VarDeclarator {
init: Some(init), ..
}) => {
if !self.is_skippable_for_seq(None, init) {
break;
}
}
Mergable::Expr(Expr::Assign(a)) => {
if let Some(a) = a.left.as_expr() {
if !self.is_skippable_for_seq(None, a) {
match a {
Mergable::Var(VarDeclarator {
init: Some(init), ..
}) => {
if !self.is_skippable_for_seq(None, init) {
break;
}
}
Mergable::Expr(Expr::Assign(a)) => {
if let Some(a) = a.left.as_expr() {
if !self.is_skippable_for_seq(None, a) {
break;
}
}

if !self.is_skippable_for_seq(None, &a.right) {
break;
if !self.is_skippable_for_seq(None, &a.right) {
break;
}
}
_ => {}
}
_ => {}
}

match &a2[j - idx] {
Mergable::Var(e2) => {
if let Some(e2) = &e2.init {
if !self.is_skippable_for_seq(Some(a), e2) {
break;
match &a2[j - idx] {
Mergable::Var(e2) => {
if let Some(e2) = &e2.init {
if !self.is_skippable_for_seq(Some(a), e2) {
break;
}
}
}

if let Some(id) = a1.last_mut().unwrap().id() {
if IdentUsageFinder::find(&id, &**e2) {
break;
if let Some(id) = a1.last_mut().unwrap().id() {
if IdentUsageFinder::find(&id, &**e2) {
break;
}
}
}
}
Mergable::Expr(e2) => {
if !self.is_skippable_for_seq(Some(a), e2) {
break;
}

if let Some(id) = a1.last_mut().unwrap().id() {
// TODO(kdy1): Optimize
if IdentUsageFinder::find(&id, &**e2) {
Mergable::Expr(e2) => {
if !self.is_skippable_for_seq(Some(a), e2) {
break;
}

if let Some(id) = a1.last_mut().unwrap().id() {
// TODO(kdy1): Optimize
if IdentUsageFinder::find(&id, &**e2) {
break;
}
}
}
}
}
}

if !did_work {
break;
}
}

Ok(())
Expand Down