Skip to content

Commit

Permalink
fix(es/compat): Fix block_scoping (#3058)
Browse files Browse the repository at this point in the history
swc_ecma_transforms_compat:
 - `block_scoping`: Consider the location of variable declarations. (Closes #2998)
  • Loading branch information
kwonoj authored Dec 17, 2021
1 parent a2a0b63 commit a381fb8
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
21 changes: 21 additions & 0 deletions crates/swc_ecma_transforms_compat/src/es2015/block_scoping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub fn block_scoping() -> impl Fold {
scope: Default::default(),
vars: vec![],
var_decl_kind: VarDeclKind::Var,
in_loop_body_scope: false,
})
}

Expand All @@ -54,6 +55,7 @@ struct BlockScoping {
scope: ScopeStack,
vars: Vec<VarDeclarator>,
var_decl_kind: VarDeclKind,
in_loop_body_scope: bool,
}

impl BlockScoping {
Expand All @@ -71,7 +73,9 @@ impl BlockScoping {
};
self.scope.push(kind);

self.in_loop_body_scope = true;
node.visit_mut_with(self);
self.in_loop_body_scope = false;

if remove {
self.scope.truncate(len);
Expand Down Expand Up @@ -557,6 +561,23 @@ impl VisitMut for BlockScoping {
self.var_decl_kind = old;

var.kind = VarDeclKind::Var;

if !self.in_loop_body_scope {
return;
}

// If loop body contains same ident to loop node's ident, rename it to avoid
// variable hoisting overwrites inner declaration.
for decl in var.decls.iter_mut() {
if let Pat::Ident(name) = &mut decl.name {
if let Some(ScopeKind::ForLetLoop { args, .. }) = self.scope.last() {
let id = &(*name).id.to_id();
if args.contains(id) {
(*name).id = private_ident!((*name).id.take().sym);
}
}
}
}
}

fn visit_mut_var_declarator(&mut self, var: &mut VarDeclarator) {
Expand Down
48 changes: 48 additions & 0 deletions crates/swc_ecma_transforms_compat/tests/es2015_block_scoping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -956,3 +956,51 @@ test!(
for(var key in keys)_loop(key);
"
);

test!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
issue_2998_1,
"
let a = 5;
for (let b = 0; b < a; b++) {
let c = 0, b = 10, d = 100;
console.log(b);
}
",
"
var a = 5;
for(var b = 0; b < a; b++){
var c = 0, b1 = 10, d = 100;
console.log(b);
}
"
);

test!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
issue_2998_2,
"
for (var a; ;) { }
for (var a = ['a', 'b']; ;) { }
",
"
for (var a; ;) { }
for (var a = ['a', 'b']; ;) { }
"
);

test_exec!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
issue_2998_3,
"let a = 5;
const expected = [];
for (let b = 0; b < a; b++) {
let c = 0, b = 10, d = 100;
expected.push(b);
}
expect(expected).toEqual([0,1,2,3,4]);
"
);

0 comments on commit a381fb8

Please sign in to comment.