Skip to content

Commit 01e2c7f

Browse files
authoredNov 23, 2023
fix(es/minifier): Fix if_return bug related to await and yield (#8328)
**Related issue:** - Closes #8324
1 parent 0004ce3 commit 01e2c7f

File tree

8 files changed

+185
-1
lines changed

8 files changed

+185
-1
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"jsc": {
3+
"parser": {
4+
"syntax": "ecmascript",
5+
"jsx": false
6+
},
7+
"target": "es2022",
8+
"loose": false,
9+
"minify": {
10+
"compress": {
11+
"arguments": false,
12+
"arrows": false,
13+
"booleans": false,
14+
"booleans_as_integers": false,
15+
"collapse_vars": false,
16+
"comparisons": false,
17+
"computed_props": false,
18+
"conditionals": false,
19+
"dead_code": false,
20+
"directives": false,
21+
"drop_console": false,
22+
"drop_debugger": false,
23+
"evaluate": false,
24+
"expression": false,
25+
"hoist_funs": false,
26+
"hoist_props": false,
27+
"hoist_vars": false,
28+
"if_return": true,
29+
"join_vars": false,
30+
"keep_classnames": false,
31+
"keep_fargs": false,
32+
"keep_fnames": false,
33+
"keep_infinity": false,
34+
"loops": false,
35+
"negate_iife": false,
36+
"properties": false,
37+
"reduce_funcs": false,
38+
"reduce_vars": false,
39+
"side_effects": false,
40+
"switches": false,
41+
"typeofs": false,
42+
"unsafe": false,
43+
"unsafe_arrows": false,
44+
"unsafe_comps": false,
45+
"unsafe_Function": false,
46+
"unsafe_math": false,
47+
"unsafe_symbols": false,
48+
"unsafe_methods": false,
49+
"unsafe_proto": false,
50+
"unsafe_regexp": false,
51+
"unsafe_undefined": false,
52+
"unused": false,
53+
"const_to_let": false,
54+
"pristine_globals": false,
55+
"passes": 3
56+
},
57+
"mangle": false
58+
}
59+
},
60+
"module": {
61+
"type": "es6"
62+
},
63+
"minify": false,
64+
"isModule": true
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
function Deferred() {
2+
const deferred = this;
3+
deferred.promise = new Promise(function (resolve, reject) {
4+
deferred.resolve = resolve;
5+
deferred.reject = reject;
6+
});
7+
}
8+
9+
export async function bug() {
10+
const s = `next`;
11+
if (!window[s]) {
12+
for (window[s] = new Deferred(); ;)
13+
if (window.current) await window.current.promise;
14+
else {
15+
window.current = window[s];
16+
try {
17+
return await window[s].promise // This line compressed to 'break'. I guess compressor intended jump to 23 line which is looks like same code.
18+
} finally {
19+
delete window.current // Above 'break' makes unintended delete
20+
}
21+
}
22+
}
23+
return await window[s].promise
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
function Deferred() {
2+
const deferred = this;
3+
deferred.promise = new Promise(function(resolve, reject) {
4+
deferred.resolve = resolve, deferred.reject = reject;
5+
});
6+
}
7+
export async function bug() {
8+
const s = "next";
9+
if (!window[s]) for(window[s] = new Deferred();;)if (window.current) await window.current.promise;
10+
else {
11+
window.current = window[s];
12+
try {
13+
return await window[s].promise;
14+
} finally{
15+
delete window.current;
16+
}
17+
}
18+
return await window[s].promise;
19+
}

‎crates/swc_ecma_minifier/src/compress/pure/dead_code.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ use swc_ecma_utils::{extract_var_ids, ExprExt, StmtExt, StmtLike, Value};
66
use swc_ecma_visit::{noop_visit_type, Visit, VisitWith};
77

88
use super::Pure;
9-
use crate::{compress::util::is_fine_for_if_cons, maybe_par, util::ModuleItemExt};
9+
use crate::{
10+
compress::util::is_fine_for_if_cons,
11+
maybe_par,
12+
util::{contains_await_or_yield, ModuleItemExt},
13+
};
1014

1115
/// Methods related to option `dead_code`.
1216
impl Pure<'_> {
@@ -285,6 +289,10 @@ impl Pure<'_> {
285289
_ => return,
286290
};
287291

292+
if contains_await_or_yield(last) {
293+
return;
294+
}
295+
288296
fn drop<T: StmtLike>(stmt: &mut T, last: &Stmt, need_break: bool) -> bool {
289297
match stmt.as_stmt_mut() {
290298
Some(s) if s.eq_ignore_span(last) => {

‎crates/swc_ecma_minifier/src/util/mod.rs

+17
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ where
211211

212212
#[derive(Default)]
213213
pub(crate) struct LeapFinder {
214+
found_await: bool,
214215
found_yield: bool,
215216
found_continue_with_label: bool,
216217
target_label: Option<Id>,
@@ -219,6 +220,12 @@ pub(crate) struct LeapFinder {
219220
impl Visit for LeapFinder {
220221
noop_visit_type!();
221222

223+
fn visit_await_expr(&mut self, n: &AwaitExpr) {
224+
n.visit_children_with(self);
225+
226+
self.found_await = true;
227+
}
228+
222229
fn visit_arrow_expr(&mut self, _: &ArrowExpr) {}
223230

224231
fn visit_class_method(&mut self, _: &ClassMethod) {}
@@ -249,6 +256,16 @@ impl Visit for LeapFinder {
249256
}
250257
}
251258

259+
#[allow(unused)]
260+
pub(crate) fn contains_await_or_yield<N>(n: &N) -> bool
261+
where
262+
N: VisitWith<LeapFinder>,
263+
{
264+
let mut v = LeapFinder::default();
265+
n.visit_with(&mut v);
266+
v.found_yield || v.found_await
267+
}
268+
252269
/// This method returns true only if `T` is `var`. (Not `const` or `let`)
253270
pub(crate) fn is_hoisted_var_decl_without_init<T>(t: &T) -> bool
254271
where
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"defaults": false,
3+
"if_return": true,
4+
"passes": 3
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
function Deferred() {
2+
const deferred = this;
3+
deferred.promise = new Promise(function (resolve, reject) {
4+
deferred.resolve = resolve;
5+
deferred.reject = reject;
6+
});
7+
}
8+
9+
export async function bug() {
10+
const s = `next`;
11+
if (!window[s]) {
12+
for (window[s] = new Deferred(); ;)
13+
if (window.current) await window.current.promise;
14+
else {
15+
window.current = window[s];
16+
try {
17+
return await window[s].promise // This line compressed to 'break'. I guess compressor intended jump to 23 line which is looks like same code.
18+
} finally {
19+
delete window.current // Above 'break' makes unintended delete
20+
}
21+
}
22+
}
23+
return await window[s].promise
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
function Deferred() {
2+
const deferred = this;
3+
deferred.promise = new Promise(function(resolve, reject) {
4+
deferred.resolve = resolve;
5+
deferred.reject = reject;
6+
});
7+
}
8+
export async function bug() {
9+
const s = "next";
10+
if (!window[s]) {
11+
for(window[s] = new Deferred();;)if (window.current) await window.current.promise;
12+
else {
13+
window.current = window[s];
14+
try {
15+
return await window[s].promise;
16+
} finally{
17+
delete window.current;
18+
}
19+
}
20+
}
21+
return await window[s].promise;
22+
}

0 commit comments

Comments
 (0)
Please sign in to comment.