From 0a83809b2ac6aaa4e98a6115c4bd3d4e8cbc78ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Mon, 24 Aug 2020 18:48:54 +0900 Subject: [PATCH] Improve type resolver (#994) --- ecmascript/transforms/Cargo.toml | 2 +- ecmascript/transforms/src/hygiene.rs | 12 ++- ecmascript/transforms/src/resolver.rs | 84 +++++++++++------- ecmascript/transforms/src/resolver/tests.rs | 97 +++++++++++++++++++-- package.json | 2 +- 5 files changed, 156 insertions(+), 41 deletions(-) diff --git a/ecmascript/transforms/Cargo.toml b/ecmascript/transforms/Cargo.toml index 273526136c6..c69d3121157 100644 --- a/ecmascript/transforms/Cargo.toml +++ b/ecmascript/transforms/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swc_ecma_transforms" -version = "0.21.1" +version = "0.21.2" authors = ["강동윤 "] license = "Apache-2.0/MIT" repository = "https://github.com/swc-project/swc.git" diff --git a/ecmascript/transforms/src/hygiene.rs b/ecmascript/transforms/src/hygiene.rs index 62a48ac8a41..46083405e9a 100644 --- a/ecmascript/transforms/src/hygiene.rs +++ b/ecmascript/transforms/src/hygiene.rs @@ -455,8 +455,16 @@ macro_rules! track_ident { let old = self.ident_type; self.ident_type = IdentType::Ref; let decorators = c.decorators.fold_with(self); + self.ident_type = IdentType::Ref; let super_class = c.super_class.fold_with(self); + + self.ident_type = IdentType::Binding; + let type_params = c.type_params.fold_with(self); + + self.ident_type = IdentType::Ref; + let super_type_params = c.super_type_params.fold_with(self); + self.ident_type = IdentType::Ref; let implements = c.implements.fold_with(self); self.ident_type = old; @@ -470,8 +478,8 @@ macro_rules! track_ident { implements, body, super_class, - type_params: c.type_params, - super_type_params: c.super_type_params, + type_params, + super_type_params, } } diff --git a/ecmascript/transforms/src/resolver.rs b/ecmascript/transforms/src/resolver.rs index 5149ca35973..1d8cc285329 100644 --- a/ecmascript/transforms/src/resolver.rs +++ b/ecmascript/transforms/src/resolver.rs @@ -117,7 +117,7 @@ impl<'a> Resolver<'a> { /// Returns a [Mark] for an identifier reference. fn mark_for_ref(&self, sym: &JsWord) -> Option { - if self.in_type { + if self.handle_types && self.in_type { let mut mark = self.mark; let mut scope = Some(&self.current); @@ -126,39 +126,36 @@ impl<'a> Resolver<'a> { // cur.hoisted_symbols.borrow().contains(sym) { if cur.declared_types.contains(sym) { if mark == Mark::root() { - return None; + break; } return Some(mark); } mark = mark.parent(); scope = cur.parent; } - - None - } else { - let mut mark = self.mark; - let mut scope = Some(&self.current); - - while let Some(cur) = scope { - if cur.declared_symbols.contains(sym) || cur.hoisted_symbols.borrow().contains(sym) - { - if mark == Mark::root() { - return None; - } - return Some(mark); - } - mark = mark.parent(); - scope = cur.parent; - } - - if let Some((ref c, mark)) = self.cur_defining { - if *c == *sym { - return Some(mark); - } - } - - None } + + let mut mark = self.mark; + let mut scope = Some(&self.current); + + while let Some(cur) = scope { + if cur.declared_symbols.contains(sym) || cur.hoisted_symbols.borrow().contains(sym) { + if mark == Mark::root() { + return None; + } + return Some(mark); + } + mark = mark.parent(); + scope = cur.parent; + } + + if let Some((ref c, mark)) = self.cur_defining { + if *c == *sym { + return Some(mark); + } + } + + None } fn fold_binding_ident(&mut self, ident: Ident) -> Ident { @@ -622,6 +619,7 @@ impl<'a> Fold for Resolver<'a> { return n; } + self.in_type = true; self.ident_type = IdentType::Binding; n.fold_children_with(self) } @@ -631,6 +629,7 @@ impl<'a> Fold for Resolver<'a> { return n; } + self.in_type = true; self.ident_type = IdentType::Ref; TsQualifiedName { left: n.left.fold_with(self), @@ -747,10 +746,13 @@ impl<'a> Fold for Resolver<'a> { let value = p.value.fold_with(self); self.ident_type = old; + let type_ann = p.type_ann.fold_with(self); + ClassProp { decorators, key, value, + type_ann, ..p } } @@ -773,6 +775,7 @@ impl<'a> Fold for Resolver<'a> { } fn fold_expr(&mut self, expr: Expr) -> Expr { + self.in_type = false; let expr = validate!(expr); let old = self.ident_type; @@ -827,6 +830,11 @@ impl<'a> Fold for Resolver<'a> { } } + fn fold_decl(&mut self, decl: Decl) -> Decl { + self.in_type = false; + decl.fold_children_with(self) + } + fn fold_fn_expr(&mut self, e: FnExpr) -> FnExpr { let ident = if let Some(ident) = e.ident { Some(self.fold_binding_ident(ident)) @@ -851,6 +859,9 @@ impl<'a> Fold for Resolver<'a> { } fn fold_function(&mut self, mut f: Function) -> Function { + f.type_params = f.type_params.fold_with(self); + + self.in_type = false; self.ident_type = IdentType::Ref; f.decorators = f.decorators.fold_with(self); @@ -860,17 +871,26 @@ impl<'a> Fold for Resolver<'a> { self.ident_type = IdentType::Ref; f.body = f.body.map(|stmt| stmt.fold_children_with(self)); + f.return_type = f.return_type.fold_with(self); + f } - fn fold_ident(&mut self, i: Ident) -> Ident { + fn fold_ident(&mut self, mut i: Ident) -> Ident { + i = i.fold_children_with(self); + match self.ident_type { IdentType::Binding => self.fold_binding_ident(i), IdentType::Ref => { let Ident { span, sym, .. } = i; if cfg!(debug_assertions) && LOG { - eprintln!("resolver: IdentRef {}{:?}", sym, i.span.ctxt()); + eprintln!( + "resolver: IdentRef (type = {}) {}{:?}", + self.in_type, + sym, + i.span.ctxt() + ); } if span.ctxt() != SyntaxContext::empty() { @@ -922,8 +942,9 @@ impl<'a> Fold for Resolver<'a> { } fn fold_import_named_specifier(&mut self, s: ImportNamedSpecifier) -> ImportNamedSpecifier { + self.in_type = false; let old = self.ident_type; - self.ident_type = IdentType::Ref; + self.ident_type = IdentType::Binding; let local = s.local.fold_with(self); self.ident_type = old; @@ -966,6 +987,7 @@ impl<'a> Fold for Resolver<'a> { } fn fold_pat(&mut self, p: Pat) -> Pat { + self.in_type = false; let old = self.cur_defining.take(); let p = p.fold_children_with(self); @@ -974,6 +996,8 @@ impl<'a> Fold for Resolver<'a> { } fn fold_var_decl(&mut self, decl: VarDecl) -> VarDecl { + self.in_type = false; + let old_hoist = self.hoist; self.hoist = VarDeclKind::Var == decl.kind; diff --git a/ecmascript/transforms/src/resolver/tests.rs b/ecmascript/transforms/src/resolver/tests.rs index ee20288297e..8e33578af6d 100644 --- a/ecmascript/transforms/src/resolver/tests.rs +++ b/ecmascript/transforms/src/resolver/tests.rs @@ -8,7 +8,7 @@ use crate::{ }; use swc_common::chain; use swc_ecma_parser::{EsConfig, Syntax, TsConfig}; -use swc_ecma_visit::{as_folder, VisitMut}; +use swc_ecma_visit::{as_folder, VisitMut, VisitMutWith}; struct TsHygiene { top_level_mark: Mark, @@ -16,9 +16,7 @@ struct TsHygiene { impl VisitMut for TsHygiene { fn visit_mut_ident(&mut self, i: &mut Ident) { - if i.span.ctxt == SyntaxContext::empty() - || SyntaxContext::empty().apply_mark(self.top_level_mark) == i.span.ctxt - { + if SyntaxContext::empty().apply_mark(self.top_level_mark) == i.span.ctxt { return; } @@ -26,6 +24,20 @@ impl VisitMut for TsHygiene { i.sym = format!("{}__{}", i.sym, ctxt).into(); i.span = i.span.with_ctxt(SyntaxContext::empty()); } + + fn visit_mut_member_expr(&mut self, n: &mut MemberExpr) { + n.obj.visit_mut_with(self); + if n.computed { + n.prop.visit_mut_with(self); + } + } + + fn visit_mut_ts_enum_member_id(&mut self, _: &mut TsEnumMemberId) {} + + /// TODO: Handle tyep parameter correctly + fn visit_mut_ts_type_param(&mut self, _: &mut TsTypeParam) {} + + fn visit_mut_prop_name(&mut self, _: &mut PropName) {} } fn tr() -> impl Fold { @@ -1271,7 +1283,7 @@ class Foo { } - new G(); + new G(); } } ", @@ -1321,7 +1333,7 @@ const bar = { ); to_ts!( - ts_resolver_neseted_enum, + ts_resolver_nested_enum, " enum Foo { name: string @@ -1347,7 +1359,7 @@ const bar = {} as Foo; string } const foo__2 = { - } as Foo; + } as Foo__2; } const bar = { } as Foo; @@ -1377,3 +1389,74 @@ const bar = { } as Foo; " ); + +to_ts!( + ts_resolver_import_and_type_ann, + " +import { Nullable } from 'nullable'; +const a: Nullable = 'hello'; +console.log(a); + ", + " +import { Nullable } from 'nullable'; +const a: Nullable = 'hello'; +console.log(a); + " +); + +identical_ts!( + ts_resolver_import_and_type_param, + " +import { Nullable } from 'nullable'; +import { SomeOther } from 'other'; +const a: Nullable = 'hello'; +console.log(a); + " +); + +identical_ts!( + ts_resolver_import_and_implements, + " +import { Nullable } from 'nullable'; +import { Component } from 'react'; +class Foo implements Component {} +new Foo(); + " +); + +identical_ts!( + ts_resolver_import_and_extends, + " + import { Nullable } from 'nullable'; + import { Component } from 'react'; + class Foo extends Component {} + new Foo(); + " +); + +identical_ts!( + ts_resolver_method_type_param, + " +import { Nullable } from 'nullable'; +import { Another } from 'some'; +class A { + do(): Nullable { + return null; + } +} +new A(); + " +); + +identical_ts!( + ts_resolver_nested_type_ref, + " +import { Nullable } from 'nullable'; +import { SomeOther } from 'some'; +import { Another } from 'some'; +class A extends Nullable { + other: Nullable; +} +new A(); + " +); diff --git a/package.json b/package.json index 586aecada49..a439a479371 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@swc/core", - "version": "1.2.21", + "version": "1.2.22", "description": "Super-fast alternative for babel", "main": "./index.js", "author": "강동윤 ",