Skip to content

Commit 66428a2

Browse files
authored
fix(es/compat): Apply Array.prototype.slice to arguments in loose spread (#11122)
**Related issue:** - Closes #11118
1 parent 70a3734 commit 66428a2

File tree

13 files changed

+133
-59
lines changed

13 files changed

+133
-59
lines changed

.changeset/tender-buses-allow.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
swc_ecma_compat_es2015: major
3+
---
4+
5+
fix(es/compat): Apply `Array.prototype.slice` to `arguments` in loose spread
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"jsc": {
3+
"parser": {
4+
"syntax": "ecmascript",
5+
"jsx": false
6+
},
7+
"target": "es5",
8+
"loose": true,
9+
"minify": {
10+
"compress": false,
11+
"mangle": false
12+
}
13+
},
14+
"module": {
15+
"type": "es6"
16+
},
17+
"minify": false,
18+
"isModule": true
19+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
function xxx() {
2+
const b = [...arguments];
3+
const c = [2, ...arguments];
4+
return b.length + c.length;
5+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
function xxx() {
2+
var b = [].concat(Array.prototype.slice.call(arguments));
3+
var c = [].concat([
4+
2
5+
], Array.prototype.slice.call(arguments));
6+
return b.length + c.length;
7+
}

crates/swc_ecma_compat_es2015/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ where
7474
template_literal(c.template_literal),
7575
classes(c.classes),
7676
new_target(),
77-
spread(c.spread),
77+
spread(c.spread, unresolved_mark),
7878
),
7979
// https://github.com/Microsoft/TypeScript/issues/5441
8080
if !c.typescript {

crates/swc_ecma_compat_es2015/src/spread.rs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::mem;
22

33
use serde::Deserialize;
44
use swc_atoms::atom;
5-
use swc_common::{util::take::Take, Span, Spanned, DUMMY_SP};
5+
use swc_common::{util::take::Take, Mark, Span, Spanned, SyntaxContext, DUMMY_SP};
66
use swc_ecma_ast::*;
77
use swc_ecma_transforms_base::{ext::ExprRefExt, helper, perf::Check};
88
use swc_ecma_transforms_macros::fast_path;
@@ -14,9 +14,11 @@ use swc_ecma_visit::{
1414
};
1515
use swc_trace_macro::swc_trace;
1616

17-
pub fn spread(c: Config) -> impl Pass {
17+
pub fn spread(c: Config, unresolved_mark: Mark) -> impl Pass {
18+
let unresolved_ctxt = SyntaxContext::empty().apply_mark(unresolved_mark);
1819
visit_mut_pass(Spread {
1920
c,
21+
unresolved_ctxt,
2022
vars: Default::default(),
2123
})
2224
}
@@ -28,9 +30,9 @@ pub struct Config {
2830
}
2931

3032
/// es2015 - `SpreadElement`
31-
#[derive(Default)]
3233
struct Spread {
3334
c: Config,
35+
unresolved_ctxt: SyntaxContext,
3436
vars: Vec<VarDeclarator>,
3537
}
3638

@@ -271,7 +273,7 @@ impl Spread {
271273
for arg in args.flatten() {
272274
let expr = arg.expr;
273275
match arg.spread {
274-
Some(_) => {
276+
Some(span) => {
275277
if !current_elems.is_empty() {
276278
arg_list.push(
277279
ArrayLit {
@@ -282,6 +284,27 @@ impl Spread {
282284
);
283285
current_elems = Vec::new();
284286
}
287+
// Special handling for `arguments` to call Array.prototype.slice
288+
// https://github.com/babel/babel/blob/61ad8555b875cb0c0996f18f803b6bf1d2150173/packages/babel-plugin-transform-spread/src/index.ts#L43-L47
289+
let expr = match *expr {
290+
Expr::Ident(Ident { ref sym, ctxt, .. })
291+
if &**sym == "arguments" && ctxt == self.unresolved_ctxt =>
292+
{
293+
CallExpr {
294+
span,
295+
callee: member_expr!(
296+
Default::default(),
297+
DUMMY_SP,
298+
Array.prototype.slice.call
299+
)
300+
.as_callee(),
301+
args: vec![expr.as_arg()],
302+
..Default::default()
303+
}
304+
.into()
305+
}
306+
_ => *expr,
307+
};
285308
arg_list.push(expr.as_arg());
286309
}
287310
None => {

crates/swc_ecma_preset_env/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ where
253253
let pass = add!(
254254
pass,
255255
Spread,
256-
es2015::spread(es2015::spread::Config { loose }),
256+
es2015::spread(es2015::spread::Config { loose }, unresolved_mark),
257257
true
258258
);
259259
let pass = add!(pass, ObjectSuper, es2015::object_super());

crates/swc_ecma_transforms_compat/tests/es2015_classes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ fn spec_tr(_: &Tester) -> impl Pass {
2525
(
2626
resolver(unresolved_mark, Mark::new(), false),
2727
classes(Default::default()),
28-
spread(Default::default()),
28+
spread(Default::default(), unresolved_mark),
2929
block_scoping(unresolved_mark),
3030
)
3131
}

0 commit comments

Comments
 (0)