feat(transformer-dts): report error for async function and generator (#3688)

feat(transformer-dts): report error for async function and generator

fix(transformer-dts): correct span for type containing private name error

fix(transformer-dts): should add reference for export specifiers
This commit is contained in:
Dunqing 2024-06-15 13:34:25 +00:00
parent fa7a6babce
commit 0e6d3ceee5
7 changed files with 63 additions and 22 deletions

View file

@ -237,6 +237,20 @@ macro_rules! match_ts_type {
pub use match_ts_type; pub use match_ts_type;
impl<'a> TSType<'a> { impl<'a> TSType<'a> {
pub fn get_identifier_reference(&self) -> Option<IdentifierReference<'a>> {
match self {
TSType::TSTypeReference(reference) => {
Some(TSTypeName::get_first_name(&reference.type_name))
}
TSType::TSQualifiedName(qualified) => Some(TSTypeName::get_first_name(&qualified.left)),
TSType::TSTypeQuery(query) => match &query.expr_name {
TSTypeQueryExprName::IdentifierReference(ident) => Some((*ident).clone()),
_ => None,
},
_ => None,
}
}
pub fn is_const_type_reference(&self) -> bool { pub fn is_const_type_reference(&self) -> bool {
matches!(self, TSType::TSTypeReference(reference) if reference.type_name.is_const()) matches!(self, TSType::TSTypeReference(reference) if reference.type_name.is_const())
} }

View file

@ -0,0 +1,23 @@
use oxc_ast::ast::Function;
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{Atom, Span};
pub fn function_must_have_explicit_return_type(func: &Function<'_>) -> OxcDiagnostic {
OxcDiagnostic::error(
"Function must have an explicit return type annotation with --isolatedDeclarations.",
)
.with_label(func.id.as_ref().map_or_else(
|| {
let start = func.params.span.start;
Span::new(start, start)
},
|id| id.span,
))
}
pub fn type_containing_private_name(name: &Atom<'_>, span: Span) -> OxcDiagnostic {
OxcDiagnostic::error(format!(
"Type containing private name '{name}' can't be used with --isolatedDeclarations."
))
.with_label(span)
}

View file

@ -6,7 +6,10 @@ use oxc_ast::ast::{
use oxc_diagnostics::OxcDiagnostic; use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{GetSpan, SPAN}; use oxc_span::{GetSpan, SPAN};
use crate::{return_type::FunctionReturnType, TransformerDts}; use crate::{
diagnostics::function_must_have_explicit_return_type, return_type::FunctionReturnType,
TransformerDts,
};
impl<'a> TransformerDts<'a> { impl<'a> TransformerDts<'a> {
pub fn infer_type_from_expression(&self, expr: &Expression<'a>) -> Option<TSType<'a>> { pub fn infer_type_from_expression(&self, expr: &Expression<'a>) -> Option<TSType<'a>> {
@ -100,19 +103,21 @@ impl<'a> TransformerDts<'a> {
return self.ctx.ast.copy(&function.return_type); return self.ctx.ast.copy(&function.return_type);
} }
if function.r#async || function.generator {
self.ctx.error(function_must_have_explicit_return_type(function));
}
let return_type = FunctionReturnType::infer( let return_type = FunctionReturnType::infer(
self, self,
function function
.body .body
.as_ref() .as_ref()
.unwrap_or_else(|| unreachable!("declare function can not have body")), .unwrap_or_else(|| unreachable!("Only declare function can have no body")),
) )
.map(|type_annotation| self.ctx.ast.ts_type_annotation(SPAN, type_annotation)); .map(|type_annotation| self.ctx.ast.ts_type_annotation(SPAN, type_annotation));
if return_type.is_none() { if return_type.is_none() {
self.ctx.error(OxcDiagnostic::error( self.ctx.error(function_must_have_explicit_return_type(function));
"Function must have an explicit return type annotation with --isolatedDeclarations.",
).with_label(function.span));
Some(self.ctx.ast.ts_type_annotation(SPAN, self.ctx.ast.ts_unknown_keyword(SPAN))) Some(self.ctx.ast.ts_type_annotation(SPAN, self.ctx.ast.ts_unknown_keyword(SPAN)))
} else { } else {

View file

@ -8,6 +8,7 @@
mod class; mod class;
mod context; mod context;
mod declaration; mod declaration;
mod diagnostics;
mod function; mod function;
mod inferrer; mod inferrer;
mod module; mod module;

View file

@ -7,11 +7,10 @@ use oxc_ast::{
}, },
Visit, Visit,
}; };
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{Atom, GetSpan}; use oxc_span::{Atom, GetSpan};
use oxc_syntax::scope::ScopeFlags; use oxc_syntax::scope::ScopeFlags;
use crate::{context::Ctx, TransformerDts}; use crate::{context::Ctx, diagnostics::type_containing_private_name, TransformerDts};
/// Infer return type from return statement. Does not support multiple return statements. /// Infer return type from return statement. Does not support multiple return statements.
pub struct FunctionReturnType<'a> { pub struct FunctionReturnType<'a> {
@ -67,11 +66,12 @@ impl<'a> FunctionReturnType<'a> {
}; };
if is_defined_in_current_scope { if is_defined_in_current_scope {
transformer.ctx.error( transformer.ctx.error(type_containing_private_name(
OxcDiagnostic::error(format!("Type containing private name '{reference_name}' can't be used with --isolatedDeclarations.")).with_label( &reference_name,
expr.span() expr_type
) .get_identifier_reference()
); .map_or_else(|| expr_type.span(), |ident| ident.span),
));
} }
} }

View file

@ -51,11 +51,11 @@ impl<'a> ScopeTree<'a> {
self.type_bindings.last_mut().unwrap().insert(ident.clone()); self.type_bindings.last_mut().unwrap().insert(ident.clone());
} }
fn add_unresolved_value_reference(&mut self, ident: &Atom<'a>) { fn add_value_reference(&mut self, ident: &Atom<'a>) {
self.value_references.last_mut().unwrap().insert(ident.clone()); self.value_references.last_mut().unwrap().insert(ident.clone());
} }
fn add_unresolved_type_reference(&mut self, ident: &Atom<'a>) { fn add_type_reference(&mut self, ident: &Atom<'a>) {
self.type_references.last_mut().unwrap().insert(ident.clone()); self.type_references.last_mut().unwrap().insert(ident.clone());
} }
@ -65,7 +65,6 @@ impl<'a> ScopeTree<'a> {
fn resolve_references(&mut self) { fn resolve_references(&mut self) {
let current_value_bindings = self.value_bindings.pop().unwrap_or_default(); let current_value_bindings = self.value_bindings.pop().unwrap_or_default();
let current_value_references = self.value_references.pop().unwrap_or_default(); let current_value_references = self.value_references.pop().unwrap_or_default();
self.type_references self.type_references
.last_mut() .last_mut()
.unwrap() .unwrap()
@ -95,7 +94,7 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
} }
fn visit_identifier_reference(&mut self, ident: &IdentifierReference<'a>) { fn visit_identifier_reference(&mut self, ident: &IdentifierReference<'a>) {
self.add_unresolved_value_reference(&ident.name); self.add_value_reference(&ident.name);
} }
fn visit_binding_pattern(&mut self, pattern: &BindingPattern<'a>) { fn visit_binding_pattern(&mut self, pattern: &BindingPattern<'a>) {
@ -107,7 +106,7 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
fn visit_ts_type_name(&mut self, name: &TSTypeName<'a>) { fn visit_ts_type_name(&mut self, name: &TSTypeName<'a>) {
if let TSTypeName::IdentifierReference(ident) = name { if let TSTypeName::IdentifierReference(ident) = name {
self.add_unresolved_type_reference(&ident.name); self.add_type_reference(&ident.name);
} else { } else {
walk_ts_type_name(self, name); walk_ts_type_name(self, name);
} }
@ -116,7 +115,7 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
fn visit_ts_type_query(&mut self, ty: &TSTypeQuery<'a>) { fn visit_ts_type_query(&mut self, ty: &TSTypeQuery<'a>) {
if let Some(type_name) = ty.expr_name.as_ts_type_name() { if let Some(type_name) = ty.expr_name.as_ts_type_name() {
let ident = TSTypeName::get_first_name(type_name); let ident = TSTypeName::get_first_name(type_name);
self.add_unresolved_value_reference(&ident.name); self.add_value_reference(&ident.name);
} else { } else {
walk_ts_type_query(self, ty); walk_ts_type_query(self, ty);
} }
@ -125,8 +124,8 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
fn visit_export_named_declaration(&mut self, decl: &ExportNamedDeclaration<'a>) { fn visit_export_named_declaration(&mut self, decl: &ExportNamedDeclaration<'a>) {
for specifier in &decl.specifiers { for specifier in &decl.specifiers {
if let ModuleExportName::Identifier(ident) = &specifier.local { if let ModuleExportName::Identifier(ident) = &specifier.local {
self.add_type_binding(&ident.name); self.add_type_reference(&ident.name);
self.add_value_binding(&ident.name); self.add_value_reference(&ident.name);
} }
} }
} }

View file

@ -2,14 +2,13 @@ commit: d8086f14
transpile Summary: transpile Summary:
AST Parsed : 20/20 (100.00%) AST Parsed : 20/20 (100.00%)
Positive Passed: 7/20 (35.00%) Positive Passed: 8/20 (40.00%)
Mismatch: "declarationAsyncAndGeneratorFunctions.ts" Mismatch: "declarationAsyncAndGeneratorFunctions.ts"
Mismatch: "declarationBasicSyntax.ts" Mismatch: "declarationBasicSyntax.ts"
Mismatch: "declarationComputedPropertyNames.ts" Mismatch: "declarationComputedPropertyNames.ts"
Mismatch: "declarationCrossFileInferences.ts" Mismatch: "declarationCrossFileInferences.ts"
Mismatch: "declarationEmitPartialNodeReuse.ts" Mismatch: "declarationEmitPartialNodeReuse.ts"
Mismatch: "declarationFunctionDeclarations.ts" Mismatch: "declarationFunctionDeclarations.ts"
Mismatch: "declarationLinkedAliases.ts"
Mismatch: "declarationNotInScopeTypes.ts" Mismatch: "declarationNotInScopeTypes.ts"
Mismatch: "declarationPartialNodeReuseTypeOf.ts" Mismatch: "declarationPartialNodeReuseTypeOf.ts"
Mismatch: "declarationRestParameters.ts" Mismatch: "declarationRestParameters.ts"