fix(es/compat): Fix loose mode of the spread pass (#7760)

This commit is contained in:
Ian Kerins 2023-08-06 21:42:33 +00:00 committed by GitHub
parent 97289b4edc
commit b69ae8f433
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 2 deletions

View File

@ -0,0 +1,11 @@
{
"jsc": {
"parser": {
"syntax": "ecmascript",
"jsx": false
},
"target": "es5",
"loose": true
},
"isModule": false
}

View File

@ -0,0 +1,11 @@
[
1,
2,
...['foo', 3],
4,
...['bar', 5],
['baz', 6],
7,
8,
9,
]

View File

@ -0,0 +1,20 @@
[].concat([
1,
2
], [
"foo",
3
], [
4
], [
"bar",
5
], [
[
"baz",
6
],
7,
8,
9
]);

View File

@ -251,12 +251,45 @@ impl Spread {
};
}
// shorthand [].concat(arr1, arr2) shoule be used under loose mode
// Shorthand [].concat(arr1, arr2) should be used under loose mode.
// Array.prototype.concat has the lovely feature by which arrays passed
// to it are depth-1 flattened. This effectively implements the loose
// spread. But if any arrays that are not being spread are present, they
// will be incorrectly flattened. The solution is to wrap every
// contiguous slice of non-spread args in an array, which will protect
// array args from being flattened.
if self.c.loose {
let mut arg_list = vec![];
let mut current_elems = vec![];
for arg in args.flatten() {
let expr = arg.expr;
arg_list.push(expr.as_arg());
match arg.spread {
Some(_) => {
if !current_elems.is_empty() {
arg_list.push(
ArrayLit {
span: DUMMY_SP,
elems: current_elems,
}
.as_arg(),
);
current_elems = vec![];
}
arg_list.push(expr.as_arg());
}
None => {
current_elems.push(Some(expr.as_arg()));
}
}
}
if !current_elems.is_empty() {
arg_list.push(
ArrayLit {
span: DUMMY_SP,
elems: current_elems,
}
.as_arg(),
);
}
return Expr::Call(CallExpr {