Fix resolver (#1064)

swc_ecma_transforms:
 - resolver: properly handle let and const
 - resolver: handle catch parameters
 - resolver: handle parameter properties

swc_ecma_visit:
 - reduced compile time of debug build
This commit is contained in:
강동윤 2020-09-11 23:33:36 +09:00 committed by GitHub
parent 1dd06d525d
commit 5c76aea82b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 293 additions and 45 deletions

View File

@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecmascript"
repository = "https://github.com/swc-project/swc.git"
version = "0.7.3"
version = "0.7.4"
[features]
codegen = ["swc_ecma_codegen"]

View File

@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecma_transforms"
repository = "https://github.com/swc-project/swc.git"
version = "0.23.8"
version = "0.23.9"
[features]
const-modules = ["dashmap"]

View File

@ -125,6 +125,15 @@ impl<'a> Resolver<'a> {
}
}
fn visit_mut_stmt_within_same_scope(&mut self, s: &mut Stmt) {
match s {
Stmt::Block(s) => {
s.visit_mut_children_with(self);
}
_ => s.visit_mut_with(self),
}
}
/// Returns a [Mark] for an identifier reference.
fn mark_for_ref(&self, sym: &JsWord) -> Option<Mark> {
if self.handle_types && self.in_type {
@ -168,9 +177,14 @@ impl<'a> Resolver<'a> {
None
}
fn visit_mut_binding_ident(&mut self, ident: &mut Ident) {
fn visit_mut_binding_ident(&mut self, ident: &mut Ident, kind: Option<VarDeclKind>) {
if cfg!(debug_assertions) && LOG {
eprintln!("resolver: Binding {}{:?}", ident.sym, ident.span.ctxt());
eprintln!(
"resolver: Binding {}{:?} {:?}",
ident.sym,
ident.span.ctxt(),
kind
);
}
if ident.span.ctxt() != SyntaxContext::empty() {
@ -231,14 +245,19 @@ impl<'a> Resolver<'a> {
}
}
let (should_insert, mark) = if let Some((ref cur, override_mark)) = self.cur_defining {
if *cur != ident.sym {
(true, self.mark)
} else {
(false, override_mark)
let (should_insert, mark) = match kind {
None | Some(VarDeclKind::Var) => {
if let Some((ref cur, override_mark)) = self.cur_defining {
if *cur != ident.sym {
(true, self.mark)
} else {
(false, override_mark)
}
} else {
(true, self.mark)
}
}
} else {
(true, self.mark)
_ => (true, self.mark),
};
let mut mark = mark;
@ -247,13 +266,23 @@ impl<'a> Resolver<'a> {
if self.hoist {
let mut cursor = Some(&self.current);
while let Some(c) = cursor {
if c.kind == ScopeKind::Fn {
c.hoisted_symbols.borrow_mut().insert(ident.sym.clone());
break;
match kind {
Some(VarDeclKind::Var) | None => {
while let Some(c) = cursor {
if c.kind == ScopeKind::Fn {
c.hoisted_symbols.borrow_mut().insert(ident.sym.clone());
break;
}
cursor = c.parent;
mark = mark.parent();
}
}
Some(VarDeclKind::Let) | Some(VarDeclKind::Const) => {
self.current
.hoisted_symbols
.borrow_mut()
.insert(ident.sym.clone());
}
cursor = c.parent;
mark = mark.parent();
}
} else {
self.current.declared_symbols.insert(ident.sym.clone());
@ -373,7 +402,7 @@ impl<'a> VisitMut for Resolver<'a> {
return;
}
self.in_type = true;
self.visit_mut_binding_ident(&mut param.name);
self.visit_mut_binding_ident(&mut param.name, None);
param.default.visit_mut_with(self);
param.constraint.visit_mut_with(self);
}
@ -428,7 +457,7 @@ impl<'a> VisitMut for Resolver<'a> {
}
self.in_type = false;
self.visit_mut_binding_ident(&mut decl.id);
self.visit_mut_binding_ident(&mut decl.id, None);
decl.members.visit_mut_with(self);
}
@ -506,7 +535,7 @@ impl<'a> VisitMut for Resolver<'a> {
}
self.in_type = true;
self.visit_mut_binding_ident(&mut n.id);
self.visit_mut_binding_ident(&mut n.id, None);
let child_mark = Mark::fresh(self.mark);
// Child folder
let mut child = Resolver::new(
@ -528,7 +557,7 @@ impl<'a> VisitMut for Resolver<'a> {
}
self.in_type = true;
self.visit_mut_binding_ident(&mut n.id);
self.visit_mut_binding_ident(&mut n.id, None);
let child_mark = Mark::fresh(self.mark);
// Child folder
let mut child = Resolver::new(
@ -549,7 +578,7 @@ impl<'a> VisitMut for Resolver<'a> {
}
self.in_type = true;
self.visit_mut_binding_ident(&mut n.id);
self.visit_mut_binding_ident(&mut n.id, None);
n.module_ref.visit_mut_with(self);
}
@ -560,7 +589,7 @@ impl<'a> VisitMut for Resolver<'a> {
}
self.in_type = true;
self.visit_mut_binding_ident(&mut n.id);
self.visit_mut_binding_ident(&mut n.id, None);
n.body.visit_mut_with(self);
}
@ -570,7 +599,7 @@ impl<'a> VisitMut for Resolver<'a> {
return;
}
self.in_type = true;
self.in_type = false;
self.ident_type = IdentType::Binding;
n.visit_mut_children_with(self)
}
@ -605,10 +634,10 @@ impl<'a> VisitMut for Resolver<'a> {
let old_hoist = self.hoist;
let old = folder.ident_type;
folder.ident_type = IdentType::Binding;
self.hoist = false;
folder.hoist = false;
e.params.visit_mut_with(&mut folder);
folder.ident_type = old;
self.hoist = old_hoist;
folder.hoist = old_hoist;
e.body.visit_mut_with(&mut folder);
@ -621,6 +650,61 @@ impl<'a> VisitMut for Resolver<'a> {
param.visit_mut_children_with(self);
}
fn visit_mut_for_stmt(&mut self, n: &mut ForStmt) {
let child_mark = Mark::fresh(self.mark);
let mut child = Resolver::new(
child_mark,
Scope::new(ScopeKind::Block, Some(&self.current)),
self.cur_defining.take(),
self.handle_types,
);
self.ident_type = IdentType::Binding;
n.init.visit_mut_with(&mut child);
self.ident_type = IdentType::Ref;
n.test.visit_mut_with(&mut child);
self.ident_type = IdentType::Ref;
n.update.visit_mut_with(&mut child);
child.visit_mut_stmt_within_same_scope(&mut *n.body);
self.cur_defining = child.cur_defining;
}
fn visit_mut_for_of_stmt(&mut self, n: &mut ForOfStmt) {
let child_mark = Mark::fresh(self.mark);
let mut child = Resolver::new(
child_mark,
Scope::new(ScopeKind::Block, Some(&self.current)),
self.cur_defining.take(),
self.handle_types,
);
n.left.visit_mut_with(&mut child);
n.right.visit_mut_with(&mut child);
child.visit_mut_stmt_within_same_scope(&mut *n.body);
self.cur_defining = child.cur_defining;
}
fn visit_mut_for_in_stmt(&mut self, n: &mut ForInStmt) {
let child_mark = Mark::fresh(self.mark);
let mut child = Resolver::new(
child_mark,
Scope::new(ScopeKind::Block, Some(&self.current)),
self.cur_defining.take(),
self.handle_types,
);
n.left.visit_mut_with(&mut child);
n.right.visit_mut_with(&mut child);
child.visit_mut_stmt_within_same_scope(&mut *n.body);
self.cur_defining = child.cur_defining;
}
fn visit_mut_block_stmt(&mut self, block: &mut BlockStmt) {
let child_mark = Mark::fresh(self.mark);
@ -713,8 +797,12 @@ impl<'a> VisitMut for Resolver<'a> {
c.params.visit_mut_with(&mut folder);
self.ident_type = old;
c.body.visit_mut_with(&mut folder);
c.key.visit_mut_with(&mut folder);
match &mut c.body {
Some(body) => {
body.visit_mut_children_with(&mut folder);
}
None => {}
}
}
/// Leftmost one of a member expression should be resolved.
@ -762,7 +850,7 @@ impl<'a> VisitMut for Resolver<'a> {
fn visit_mut_fn_expr(&mut self, e: &mut FnExpr) {
if let Some(ident) = &mut e.ident {
self.visit_mut_binding_ident(ident)
self.visit_mut_binding_ident(ident, None)
}
let child_mark = Mark::fresh(self.mark);
@ -790,9 +878,7 @@ impl<'a> VisitMut for Resolver<'a> {
f.params.visit_mut_with(self);
self.ident_type = IdentType::Ref;
f.body
.as_mut()
.map(|stmt| stmt.visit_mut_children_with(self));
f.body.visit_mut_with(self);
f.return_type.visit_mut_with(self);
}
@ -805,7 +891,7 @@ impl<'a> VisitMut for Resolver<'a> {
self.ident_type = ident_type;
match self.ident_type {
IdentType::Binding => self.visit_mut_binding_ident(i),
IdentType::Binding => self.visit_mut_binding_ident(i, None),
IdentType::Ref => {
let Ident { span, sym, .. } = i;
@ -857,7 +943,7 @@ impl<'a> VisitMut for Resolver<'a> {
i.span = span;
// Support hoisting
self.visit_mut_binding_ident(i)
self.visit_mut_binding_ident(i, None)
}
}
// We currently does not touch labels
@ -951,7 +1037,11 @@ impl<'a> VisitMut for Resolver<'a> {
// Phase 1: Handle hoisting
{
let mut hoister = Hoister { resolver: self };
let mut hoister = Hoister {
resolver: self,
kind: None,
in_block: false,
};
stmts.visit_mut_children_with(&mut hoister)
}
@ -962,7 +1052,11 @@ impl<'a> VisitMut for Resolver<'a> {
fn visit_mut_stmts(&mut self, stmts: &mut Vec<Stmt>) {
// Phase 1: Handle hoisting
{
let mut hoister = Hoister { resolver: self };
let mut hoister = Hoister {
resolver: self,
kind: None,
in_block: false,
};
stmts.visit_mut_children_with(&mut hoister)
}
@ -974,28 +1068,49 @@ impl<'a> VisitMut for Resolver<'a> {
/// The folder which handles var / function hoisting.
struct Hoister<'a, 'b> {
resolver: &'a mut Resolver<'b>,
kind: Option<VarDeclKind>,
/// Hoister should not touch let / const in the block.
in_block: bool,
}
impl VisitMut for Hoister<'_, '_> {
noop_visit_mut_type!();
fn visit_mut_fn_decl(&mut self, node: &mut FnDecl) {
self.resolver.visit_mut_binding_ident(&mut node.ident);
self.resolver
.visit_mut_binding_ident(&mut node.ident, Some(VarDeclKind::Var));
}
fn visit_mut_expr(&mut self, _: &mut Expr) {}
#[inline]
fn visit_mut_arrow_expr(&mut self, _: &mut ArrowExpr) {}
#[inline]
fn visit_mut_tagged_tpl(&mut self, _: &mut TaggedTpl) {}
#[inline]
fn visit_mut_tpl(&mut self, _: &mut Tpl) {}
#[inline]
fn visit_mut_function(&mut self, _: &mut Function) {}
fn visit_mut_var_decl(&mut self, node: &mut VarDecl) {
if node.kind != VarDeclKind::Var {
return;
if self.in_block {
match node.kind {
VarDeclKind::Const | VarDeclKind::Let => return,
_ => {}
}
}
let old_kind = self.kind;
self.kind = Some(node.kind);
self.resolver.hoist = false;
node.visit_mut_children_with(self)
node.visit_mut_children_with(self);
self.kind = old_kind;
}
#[inline]
@ -1005,14 +1120,59 @@ impl VisitMut for Hoister<'_, '_> {
fn visit_mut_pat(&mut self, node: &mut Pat) {
match node {
Pat::Ident(i) => self.resolver.visit_mut_binding_ident(i),
Pat::Ident(i) => self.resolver.visit_mut_binding_ident(i, self.kind),
_ => node.visit_mut_children_with(self),
}
}
#[inline]
fn visit_mut_catch_clause(&mut self, _: &mut CatchClause) {}
#[inline]
fn visit_mut_pat_or_expr(&mut self, _: &mut PatOrExpr) {}
#[inline]
fn visit_mut_param(&mut self, _: &mut Param) {}
#[inline]
fn visit_mut_constructor(&mut self, _: &mut Constructor) {}
fn visit_mut_var_decl_or_expr(&mut self, n: &mut VarDeclOrExpr) {
match n {
VarDeclOrExpr::VarDecl(VarDecl {
kind: VarDeclKind::Let,
..
})
| VarDeclOrExpr::VarDecl(VarDecl {
kind: VarDeclKind::Const,
..
}) => {}
_ => {
n.visit_mut_children_with(self);
}
}
}
fn visit_mut_var_decl_or_pat(&mut self, n: &mut VarDeclOrPat) {
match n {
VarDeclOrPat::VarDecl(VarDecl {
kind: VarDeclKind::Let,
..
})
| VarDeclOrPat::VarDecl(VarDecl {
kind: VarDeclKind::Const,
..
}) => {}
_ => {
n.visit_mut_children_with(self);
}
}
}
fn visit_mut_block_stmt(&mut self, n: &mut BlockStmt) {
let old_in_block = self.in_block;
self.in_block = true;
n.visit_mut_children_with(self);
self.in_block = old_in_block;
}
}

View File

@ -1477,3 +1477,91 @@ to_ts!(
});
"
);
// See: https://github.com/denoland/deno_lint/pull/304
to_ts!(
let_scoping,
"
function wrapper() {
const usage = () => {
return a;
};
let a;
}
",
"
function wrapper() {
const usage__2 = ()=>{
return a__2;
};
let a__2;
}
"
);
to_ts!(
ts_resolver_parameter_property,
r#"
class PartWriter implements Deno.Writer {
constructor(
private writer: Deno.Writer,
readonly boundary: string,
public headers: Headers,
isFirstBoundary: boolean,
) {
let buf = "";
if (isFirstBoundary) {
buf += `--${boundary}\r\n`;
} else {
buf += `\r\n--${boundary}\r\n`;
}
for (const [key, value] of headers.entries()) {
buf += `${key}: ${value}\r\n`;
}
buf += `\r\n`;
this.partHeader = buf;
}
}
"#,
r#"
class PartWriter {
constructor(private writer__2: Deno.Writer., readonly boundary__2: string, public headers__2: Headers, isFirstBoundary__2: boolean){
let buf__2 = "";
if (isFirstBoundary__2) {
buf__2 += `--${boundary__2}\r\n`;
} else {
buf__2 += `\r\n--${boundary__2}\r\n`;
}
for (const [key__3, value__3] of headers__2.entries()){
buf__2 += `${key__3}: ${value__3}\r\n`;
}
buf__2 += `\r\n`;
this.partHeader = buf__2;
}
}
"#
);
to_ts!(
ts_resolver_catch_param,
r#"
function wrapper(...args) {
try {
return target(...args);
} catch (err) {
switch (err.name) {
}
}
}
"#,
"
function wrapper(...args__2) {
try {
return target(...args__2);
} catch (err__3) {
switch(err__3.name){
}
}
}
"
);

View File

@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecma_visit"
repository = "https://github.com/swc-project/swc.git"
version = "0.17.1"
version = "0.17.2"
[dependencies]
num-bigint = {version = "0.2", features = ["serde"]}

View File

@ -182,7 +182,7 @@ where
#[macro_export]
macro_rules! noop_fold_type {
($name:ident, $N:tt) => {
#[inline(always)]
#[inline]
fn $name(&mut self, node: $crate::swc_ecma_ast::$N) -> $crate::swc_ecma_ast::$N {
node
}
@ -261,7 +261,7 @@ macro_rules! noop_fold_type {
#[macro_export]
macro_rules! noop_visit_type {
($name:ident, $N:tt) => {
#[inline(always)]
#[inline]
fn $name(&mut self, _: &$crate::swc_ecma_ast::$N, _: &dyn $crate::Node) {}
};
() => {
@ -338,7 +338,7 @@ macro_rules! noop_visit_type {
#[macro_export]
macro_rules! noop_visit_mut_type {
($name:ident, $N:ident) => {
#[inline(always)]
#[inline]
fn $name(&mut self, _: &mut $crate::swc_ecma_ast::$N) {}
};
() => {