mirror of
https://github.com/swc-project/swc.git
synced 2024-12-01 09:52:57 +03:00
fix(swc): Fixes for typescript type checker (#1146)
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.
This commit is contained in:
parent
08c5d83d20
commit
6941f29943
@ -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 = []
|
||||
|
@ -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()?;
|
||||
|
@ -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"
|
||||
|
@ -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!(")");
|
||||
@ -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,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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]
|
||||
@ -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]
|
||||
@ -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]
|
||||
@ -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]
|
||||
|
@ -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 = []
|
||||
|
@ -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(){}
|
||||
|
@ -43,7 +43,7 @@
|
||||
},
|
||||
"value": "m",
|
||||
"typeAnnotation": null,
|
||||
"optional": false
|
||||
"optional": true
|
||||
},
|
||||
"function": {
|
||||
"params": [],
|
||||
|
@ -73,7 +73,7 @@
|
||||
},
|
||||
"value": "r2",
|
||||
"typeAnnotation": null,
|
||||
"optional": false
|
||||
"optional": true
|
||||
},
|
||||
"value": null,
|
||||
"typeAnnotation": {
|
||||
|
@ -73,7 +73,7 @@
|
||||
},
|
||||
"value": "x",
|
||||
"typeAnnotation": null,
|
||||
"optional": false
|
||||
"optional": true
|
||||
},
|
||||
"value": null,
|
||||
"typeAnnotation": null,
|
||||
|
@ -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"]
|
||||
|
@ -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]
|
||||
@ -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);
|
||||
@ -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) {
|
||||
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
@ -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;
|
||||
@ -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`;
|
||||
@ -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,
|
||||
"
|
||||
|
Loading…
Reference in New Issue
Block a user