Skip to content

Commit

Permalink
fix(swc): Fixes for typescript type checker (#1146)
Browse files Browse the repository at this point in the history
swc_ecma_codegen:
 - Fix codegen of `TsConstructorSignature`.
 - Fix codegen of `TsIndexSignature`.
 - Fix codegen of type parameters in arrow expressions.
 - No panic on dummy span.

swc_ecma_parser:
 - Parse optoinal method correctly.

swc_ecma_transforms:
 - resolver: Handle type parameters in arrow expressions.
  • Loading branch information
kdy1 authored Dec 27, 2020
1 parent 08c5d83 commit 6941f29
Show file tree
Hide file tree
Showing 13 changed files with 113 additions and 44 deletions.
2 changes: 1 addition & 1 deletion ecmascript/ast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecma_ast"
repository = "https://github.com/swc-project/swc.git"
version = "0.36.1"
version = "0.36.2"

[features]
default = []
Expand Down
11 changes: 5 additions & 6 deletions ecmascript/ast/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,11 @@ pub struct Ident {
impl arbitrary::Arbitrary for Ident {
fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
let span = u.arbitrary()?;
let sym = loop {
let v = u.arbitrary::<String>()?;
if !v.is_empty() {
break v.into();
}
};
let sym = u.arbitrary::<String>()?;
if sym.is_empty() {
return Err(arbitrary::Error::NotEnoughData);
}
let sym = sym.into();

let type_ann = u.arbitrary()?;
let optional = u.arbitrary()?;
Expand Down
2 changes: 1 addition & 1 deletion ecmascript/codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"]
license = "Apache-2.0/MIT"
name = "swc_ecma_codegen"
repository = "https://github.com/swc-project/swc.git"
version = "0.42.0"
version = "0.42.1"

[dependencies]
bitflags = "1"
Expand Down
21 changes: 14 additions & 7 deletions ecmascript/codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -663,9 +663,12 @@ impl<'a> Emitter<'a> {
_ => true,
};

emit!(node.type_params);

if parens {
punct!("(");
}

self.emit_list(node.span, Some(&node.params), ListFormat::CommaListElements)?;
if parens {
punct!(")");
Expand Down Expand Up @@ -1614,15 +1617,19 @@ impl<'a> Emitter<'a> {

// Write a trailing comma, if requested.
let has_trailing_comma = format.contains(ListFormat::AllowTrailingComma) && {
match self.cm.span_to_snippet(parent_node) {
Ok(snippet) => {
if snippet.len() < 3 {
false
} else {
snippet[..snippet.len() - 1].trim().ends_with(',')
if parent_node.is_dummy() {
false
} else {
match self.cm.span_to_snippet(parent_node) {
Ok(snippet) => {
if snippet.len() < 3 {
false
} else {
snippet[..snippet.len() - 1].trim().ends_with(',')
}
}
_ => false,
}
_ => false,
}
};

Expand Down
24 changes: 17 additions & 7 deletions ecmascript/codegen/src/typescript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ impl<'a> Emitter<'a> {
fn emit_ts_constructor_signature_decl(&mut self, n: &TsConstructSignatureDecl) -> Result {
self.emit_leading_comments_of_pos(n.span().lo())?;

unimplemented!("emit_ts_constructor_signature_decl")
keyword!("constructor");

punct!("(");
self.emit_list(n.span, Some(&n.params), ListFormat::Parameters)?;
punct!(")");
}

#[emitter]
Expand Down Expand Up @@ -171,7 +175,11 @@ impl<'a> Emitter<'a> {
fn emit_ts_export_assignment(&mut self, n: &TsExportAssignment) -> Result {
self.emit_leading_comments_of_pos(n.span().lo())?;

unimplemented!("emit_ts_export_assignment")
keyword!("export");
formatting_space!();
punct!("=");
formatting_space!();
emit!(n.expr);
}

#[emitter]
Expand Down Expand Up @@ -252,10 +260,11 @@ impl<'a> Emitter<'a> {
self.emit_list(n.span, Some(&n.params), ListFormat::Parameters)?;
punct!("]");

punct!(":");
formatting_space!();
emit!(n.type_ann);
semi!();
if let Some(type_ann) = &n.type_ann {
punct!(":");
formatting_space!();
emit!(type_ann);
}
}

#[emitter]
Expand Down Expand Up @@ -572,7 +581,8 @@ impl<'a> Emitter<'a> {
fn emit_ts_non_null_expr(&mut self, n: &TsNonNullExpr) -> Result {
self.emit_leading_comments_of_pos(n.span().lo())?;

unimplemented!("emit_ts_non_null_expr")
emit!(n.expr);
punct!("!")
}

#[emitter]
Expand Down
2 changes: 1 addition & 1 deletion ecmascript/parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs", "examples/**/*.rs"]
license = "Apache-2.0/MIT"
name = "swc_ecma_parser"
repository = "https://github.com/swc-project/swc.git"
version = "0.44.0"
version = "0.44.1"

[features]
default = []
Expand Down
15 changes: 10 additions & 5 deletions ecmascript/parser/src/parser/class_and_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,17 +477,22 @@ impl<'a, I: Tokens> Parser<I> {
);
}

let key = self.parse_class_prop_name()?;
let mut key = self.parse_class_prop_name()?;
let is_optional = self.input.syntax().typescript() && eat!('?');

let is_private = match key {
Either::Left(PrivateName { .. }) => true,
_ => false,
};
let is_simple = match key {
Either::Right(PropName::Ident(..)) => true,
_ => false,
let is_simple = {
match &mut key {
Either::Right(PropName::Ident(i)) => {
i.optional = is_optional;
true
}
_ => false,
}
};
let is_optional = self.input.syntax().typescript() && eat!('?');

if self.is_class_method()? {
// handle a(){} / get(){} / set(){} / async(){}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
},
"value": "m",
"typeAnnotation": null,
"optional": false
"optional": true
},
"function": {
"params": [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
},
"value": "r2",
"typeAnnotation": null,
"optional": false
"optional": true
},
"value": null,
"typeAnnotation": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
},
"value": "x",
"typeAnnotation": null,
"optional": false
"optional": true
},
"value": null,
"typeAnnotation": null,
Expand Down
2 changes: 1 addition & 1 deletion ecmascript/transforms/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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.31.0"
version = "0.31.1"

[features]
const-modules = ["dashmap"]
Expand Down
23 changes: 21 additions & 2 deletions ecmascript/transforms/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,18 @@ macro_rules! typed_ref {
};
}

macro_rules! typed_decl {
($name:ident, $T:ty) => {
fn $name(&mut self, node: &mut $T) {
if self.handle_types {
self.ident_type = IdentType::Binding;
self.in_type = true;
node.visit_mut_children_with(self)
}
}
};
}

macro_rules! noop {
($name:ident, $T:ty) => {
#[inline]
Expand Down Expand Up @@ -401,7 +413,7 @@ impl<'a> VisitMut for Resolver<'a> {
typed_ref!(visit_mut_ts_tuple_type, TsTupleType);
typed_ref!(visit_mut_ts_intersection_type, TsIntersectionType);
typed_ref!(visit_mut_ts_type_ref, TsTypeRef);
typed!(visit_mut_ts_type_param_decl, TsTypeParamDecl);
typed_decl!(visit_mut_ts_type_param_decl, TsTypeParamDecl);
typed!(visit_mut_ts_enum_member, TsEnumMember);
typed!(visit_mut_ts_fn_param, TsFnParam);
typed!(visit_mut_ts_indexed_access_type, TsIndexedAccessType);
Expand Down Expand Up @@ -434,9 +446,12 @@ impl<'a> VisitMut for Resolver<'a> {
return;
}
self.in_type = true;
self.visit_mut_binding_ident(&mut param.name, None);
param.name.visit_mut_with(self);

let ident_type = self.ident_type;
param.default.visit_mut_with(self);
param.constraint.visit_mut_with(self);
self.ident_type = ident_type;
}

fn visit_mut_ts_construct_signature_decl(&mut self, decl: &mut TsConstructSignatureDecl) {
Expand Down Expand Up @@ -663,6 +678,8 @@ impl<'a> VisitMut for Resolver<'a> {
self.handle_types,
);

e.type_params.visit_mut_with(&mut folder);

let old_hoist = self.hoist;
let old = folder.ident_type;
folder.ident_type = IdentType::Binding;
Expand All @@ -673,6 +690,8 @@ impl<'a> VisitMut for Resolver<'a> {

e.body.visit_mut_with(&mut folder);

e.return_type.visit_mut_with(&mut folder);

self.cur_defining = folder.cur_defining;
}

Expand Down
49 changes: 39 additions & 10 deletions ecmascript/transforms/src/resolver/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ struct TsHygiene {

impl VisitMut for TsHygiene {
fn visit_mut_ident(&mut self, i: &mut Ident) {
i.type_ann.visit_mut_with(self);

if SyntaxContext::empty().apply_mark(self.top_level_mark) == i.span.ctxt {
println!("ts_hygiene: {} is top-level", i.sym);
return;
}

Expand All @@ -32,12 +35,11 @@ impl VisitMut for TsHygiene {
}
}

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 visit_mut_ts_qualified_name(&mut self, q: &mut TsQualifiedName) {
q.left.visit_mut_with(self);
}
}

fn tr() -> impl Fold {
Expand Down Expand Up @@ -1352,13 +1354,13 @@ const bar = {} as Foo;
",
"
enum Foo {
name,
string
name__0,
string__0
}
function foo() {
enum Foo__2 {
name,
string
name__0,
string__0
}
const foo__2 = {
} as Foo__2;
Expand Down Expand Up @@ -1534,7 +1536,7 @@ to_ts!(
"#,
r#"
class PartWriter {
constructor(private writer__2: Deno.Writer., readonly boundary__2: string, public headers__2: Headers, isFirstBoundary__2: boolean){
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`;
Expand Down Expand Up @@ -1770,6 +1772,33 @@ to!(
"#
);

to_ts!(
type_checker_001,
"
const assign = <T, K1 extends keyof T, K2 extends keyof T[K1]>(object: T, key1: K1, key2: K2) \
=> (value: T[K1][K2]) => object[key1][key2] = value;
",
"const assign = <T__2, K1__2 extends keyof T__2, K2__2 extends keyof T__2[K1__2]>(object__2: \
T__2, key1__2: K1__2, key2__2: K2__2)=>(value__3: \
T__2[K1__2][K2__2])=>object__2[key1__2][key2__2] = value__3"
);

to_ts!(
type_checker_002,
"
export declare function foo<T>(obj: T): T extends () => infer P ? P : never;
export function bar<T>(obj: T) {
return foo(obj);
}
",
"
export declare function foo<T__2>(obj__2: T__2): T__2 extends () => infer P ? P : never;
export function bar<T__3>(obj__3: T__3) {
return foo(obj__3);
}
"
);

to_ts!(
deno_lint_486,
"
Expand Down

0 comments on commit 6941f29

Please sign in to comment.