fix(es/transforms/base): Fix resolver (#1710)

swc_ecma_transforms_base:
 - `ts_resolver`: Treat the type parameter of a mapped type as a binding.
This commit is contained in:
강동윤 2021-05-18 17:47:43 +09:00 committed by GitHub
parent dee82904f8
commit a0241c88b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 83 additions and 52 deletions

View File

@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecma_transforms_base"
repository = "https://github.com/swc-project/swc.git"
version = "0.15.2"
version = "0.15.3"
[dependencies]
fxhash = "0.2.1"

View File

@ -388,7 +388,6 @@ impl<'a> VisitMut for Resolver<'a> {
typed!(visit_mut_ts_fn_or_constructor_type, TsFnOrConstructorType);
typed_ref!(visit_mut_ts_union_type, TsUnionType);
typed_ref!(visit_mut_ts_infer_type, TsInferType);
typed_ref!(visit_mut_ts_mapped_type, TsMappedType);
typed_ref!(visit_mut_ts_import_type, TsImportType);
typed_ref!(visit_mut_ts_tuple_type, TsTupleType);
typed_ref!(visit_mut_ts_intersection_type, TsIntersectionType);
@ -570,6 +569,33 @@ impl<'a> VisitMut for Resolver<'a> {
decl.visit_mut_children_with(self)
}
fn visit_mut_export_default_decl(&mut self, e: &mut ExportDefaultDecl) {
// Treat default exported functions and classes as declarations
// even though they are parsed as expressions.
match &mut e.decl {
DefaultDecl::Fn(f) => {
if f.ident.is_some() {
let child_mark = Mark::fresh(self.mark);
// Child folder
let mut folder = Resolver::new(
child_mark,
Scope::new(ScopeKind::Fn, Some(&self.current)),
self.handle_types,
);
f.function.visit_mut_with(&mut folder)
} else {
f.visit_mut_with(self)
}
}
DefaultDecl::Class(c) => {
// Skip class expression visitor to treat as a declaration.
c.class.visit_mut_with(self)
}
_ => e.visit_mut_children_with(self),
}
}
fn visit_mut_expr(&mut self, expr: &mut Expr) {
self.in_type = false;
let old = self.ident_type;
@ -612,33 +638,6 @@ impl<'a> VisitMut for Resolver<'a> {
e.function.visit_mut_with(&mut folder);
}
fn visit_mut_export_default_decl(&mut self, e: &mut ExportDefaultDecl) {
// Treat default exported functions and classes as declarations
// even though they are parsed as expressions.
match &mut e.decl {
DefaultDecl::Fn(f) => {
if f.ident.is_some() {
let child_mark = Mark::fresh(self.mark);
// Child folder
let mut folder = Resolver::new(
child_mark,
Scope::new(ScopeKind::Fn, Some(&self.current)),
self.handle_types,
);
f.function.visit_mut_with(&mut folder)
} else {
f.visit_mut_with(self)
}
}
DefaultDecl::Class(c) => {
// Skip class expression visitor to treat as a declaration.
c.class.visit_mut_with(self)
}
_ => e.visit_mut_children_with(self),
}
}
fn visit_mut_for_in_stmt(&mut self, n: &mut ForInStmt) {
let child_mark = Mark::fresh(self.mark);
let mut child = Resolver::new(
@ -777,11 +776,6 @@ impl<'a> VisitMut for Resolver<'a> {
self.ident_type = old;
}
// TODO: How should I handle this?
typed!(visit_mut_ts_namespace_export_decl, TsNamespaceExportDecl);
track_ident_mut!();
/// Leftmost one of a member expression should be resolved.
fn visit_mut_member_expr(&mut self, e: &mut MemberExpr) {
e.obj.visit_mut_with(self);
@ -791,25 +785,10 @@ impl<'a> VisitMut for Resolver<'a> {
}
}
fn visit_mut_setter_prop(&mut self, n: &mut SetterProp) {
n.key.visit_mut_with(self);
// TODO: How should I handle this?
typed!(visit_mut_ts_namespace_export_decl, TsNamespaceExportDecl);
{
let child_mark = Mark::fresh(self.mark);
// Child folder
let mut child = Resolver::new(
child_mark,
Scope::new(ScopeKind::Fn, Some(&self.current)),
self.handle_types,
);
child.in_type = false;
child.ident_type = IdentType::Binding;
n.param.visit_mut_with(&mut child);
n.body.visit_mut_with(&mut child);
};
}
track_ident_mut!();
fn visit_mut_method_prop(&mut self, m: &mut MethodProp) {
m.key.visit_mut_with(self);
@ -889,6 +868,26 @@ impl<'a> VisitMut for Resolver<'a> {
fn visit_mut_private_name(&mut self, _: &mut PrivateName) {}
fn visit_mut_setter_prop(&mut self, n: &mut SetterProp) {
n.key.visit_mut_with(self);
{
let child_mark = Mark::fresh(self.mark);
// Child folder
let mut child = Resolver::new(
child_mark,
Scope::new(ScopeKind::Fn, Some(&self.current)),
self.handle_types,
);
child.in_type = false;
child.ident_type = IdentType::Binding;
n.param.visit_mut_with(&mut child);
n.body.visit_mut_with(&mut child);
};
}
fn visit_mut_stmts(&mut self, stmts: &mut Vec<Stmt>) {
// Phase 1: Handle hoisting
{
@ -1038,6 +1037,24 @@ impl<'a> VisitMut for Resolver<'a> {
n.body.visit_mut_with(&mut child);
}
fn visit_mut_ts_mapped_type(&mut self, n: &mut TsMappedType) {
if !self.handle_types {
return;
}
self.in_type = true;
self.ident_type = IdentType::Binding;
n.type_param.visit_mut_with(self);
self.in_type = true;
self.ident_type = IdentType::Ref;
n.name_type.visit_mut_with(self);
self.in_type = true;
self.ident_type = IdentType::Ref;
n.type_ann.visit_mut_with(self);
}
fn visit_mut_ts_method_signature(&mut self, n: &mut TsMethodSignature) {
if !self.handle_types {
return;

View File

@ -3000,3 +3000,17 @@ to_ts!(
}
"
);
to_ts!(
ts_mapped_type_as_clauses_01,
"
type Lazyify<T> = {
[K in keyof T as `get${Capitalize<K & string>}`]: () => T[K]
};
",
"
type Lazyify<T__2> = {
[K__2 in keyof T__2]: () => T__2[K__2];
};
"
);