feat(isolated-declarations): report errors that are consistent with typescript. (#3720)

This commit is contained in:
Dunqing 2024-06-17 13:53:19 +00:00
parent 3c597356e4
commit 77d553364d
7 changed files with 152 additions and 44 deletions

View file

@ -5,7 +5,10 @@ use oxc_allocator::Box;
use oxc_span::{GetSpan, SPAN};
use crate::{
diagnostics::{computed_property_name, extends_clause_expression},
diagnostics::{
accessor_must_have_explicit_return_type, computed_property_name, extends_clause_expression,
method_must_have_explicit_return_type, property_must_have_explicit_type,
},
IsolatedDeclarations,
};
@ -59,16 +62,17 @@ impl<'a> IsolatedDeclarations<'a> {
.as_ref()
.map(|type_annotation| self.ast.copy(type_annotation))
.or_else(|| {
let new_type = property
property
.value
.as_ref()
.and_then(|expr| self.infer_type_from_expression(expr))
.unwrap_or_else(|| {
// report error for has no type annotation
self.ast.ts_unknown_keyword(property.span)
});
Some(self.ast.ts_type_annotation(SPAN, new_type))
.and_then(|expr| {
let ts_type = self.infer_type_from_expression(expr);
if ts_type.is_none() {
self.error(property_must_have_explicit_type(property.key.span()));
}
ts_type
})
.map(|ts_type| self.ast.ts_type_annotation(SPAN, ts_type))
})
};
@ -115,6 +119,20 @@ impl<'a> IsolatedDeclarations<'a> {
let type_annotation = self.infer_function_return_type(function);
if type_annotation.is_none() {
match definition.kind {
MethodDefinitionKind::Method => {
self.error(method_must_have_explicit_return_type(definition.key.span()));
}
MethodDefinitionKind::Get => {
self.error(accessor_must_have_explicit_return_type(definition.key.span()));
}
MethodDefinitionKind::Constructor | MethodDefinitionKind::Set => {}
}
}
// TODO: Infer the parameter type of the `set` method from the `get` method
let value = self.ast.function(
FunctionType::TSEmptyBodyFunctionExpression,
function.span,

View file

@ -7,7 +7,10 @@ use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{GetSpan, SPAN};
use oxc_syntax::scope::ScopeFlags;
use crate::{diagnostics::signature_computed_property_name, IsolatedDeclarations};
use crate::{
diagnostics::{inferred_type_of_expression, signature_computed_property_name},
IsolatedDeclarations,
};
impl<'a> IsolatedDeclarations<'a> {
pub fn transform_variable_declaration(
@ -264,6 +267,9 @@ impl<'a> IsolatedDeclarations<'a> {
impl<'a> Visit<'a> for IsolatedDeclarations<'a> {
fn visit_ts_method_signature(&mut self, signature: &TSMethodSignature<'a>) {
if signature.return_type.is_none() {
self.error(inferred_type_of_expression(signature.span));
}
self.report_signature_property_key(&signature.key, signature.computed);
}
fn visit_ts_property_signature(&mut self, signature: &TSPropertySignature<'a>) {

View file

@ -1,18 +1,32 @@
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 {
pub fn method_must_have_explicit_return_type(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error(
"Method must have an explicit return type annotation with --isolatedDeclarations.",
)
.with_label(span)
}
pub fn function_must_have_explicit_return_type(span: Span) -> 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,
))
.with_label(span)
}
pub fn accessor_must_have_explicit_return_type(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error(
"At least one accessor must have an explicit return type annotation with --isolatedDeclarations.",
)
.with_label(span)
}
pub fn property_must_have_explicit_type(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error(
"Property must have an explicit type annotation with --isolatedDeclarations.",
)
.with_label(span)
}
pub fn type_containing_private_name(name: &Atom<'_>, span: Span) -> OxcDiagnostic {
@ -41,3 +55,31 @@ pub fn extends_clause_expression(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error("Extends clause can't contain an expression with --isolatedDeclarations.")
.with_label(span)
}
pub fn default_export_inferred(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error("Default exports can't be inferred with --isolatedDeclarations.")
.with_label(span)
}
pub fn array_inferred(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error("Arrays can't be inferred with --isolatedDeclarations.").with_label(span)
}
pub fn shorthand_property(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error(
"Objects that contain shorthand properties can't be inferred with --isolatedDeclarations.",
)
.with_label(span)
}
pub fn inferred_type_of_expression(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error("Expression type can't be inferred with --isolatedDeclarations.")
.with_label(span)
}
// Inference from class expressions is not supported with --isolatedDeclarations.
pub fn inferred_type_of_class_expression(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error("Class expression type can't be inferred with --isolatedDeclarations.")
.with_label(span)
}

View file

@ -4,9 +4,9 @@ use oxc_ast::ast::*;
use oxc_allocator::Box;
use oxc_ast::ast::Function;
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::SPAN;
use oxc_span::{Span, SPAN};
use crate::IsolatedDeclarations;
use crate::{diagnostics::function_must_have_explicit_return_type, IsolatedDeclarations};
impl<'a> IsolatedDeclarations<'a> {
pub fn transform_function(&mut self, func: &Function<'a>) -> Option<Box<'a, Function<'a>>> {
@ -14,6 +14,9 @@ impl<'a> IsolatedDeclarations<'a> {
None
} else {
let return_type = self.infer_function_return_type(func);
if return_type.is_none() {
self.error(function_must_have_explicit_return_type(get_function_span(func)));
}
let params = self.transform_formal_parameters(&func.params);
Some(self.ast.function(
func.r#type,
@ -126,3 +129,13 @@ impl<'a> IsolatedDeclarations<'a> {
)
}
}
pub fn get_function_span(func: &Function<'_>) -> Span {
func.id.as_ref().map_or_else(
|| {
let start = func.params.span.start;
Span::new(start, start)
},
|id| id.span,
)
}

View file

@ -7,7 +7,8 @@ use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{GetSpan, SPAN};
use crate::{
diagnostics::function_must_have_explicit_return_type, return_type::FunctionReturnType,
diagnostics::{array_inferred, inferred_type_of_class_expression},
return_type::FunctionReturnType,
IsolatedDeclarations,
};
@ -35,6 +36,10 @@ impl<'a> IsolatedDeclarations<'a> {
Expression::ObjectExpression(expr) => {
Some(self.transform_object_expression_to_ts_type(expr, false))
}
Expression::ArrayExpression(expr) => {
self.error(array_inferred(expr.span));
Some(self.ast.ts_unknown_keyword(expr.span))
}
Expression::TSAsExpression(expr) => {
if expr.type_annotation.is_const_type_reference() {
Some(self.transform_expression_to_ts_type(&expr.expression))
@ -43,14 +48,7 @@ impl<'a> IsolatedDeclarations<'a> {
}
}
Expression::ClassExpression(expr) => {
self.error(
OxcDiagnostic::error(
"
Inference from class expressions is not supported with --isolatedDeclarations.
",
)
.with_label(expr.span),
);
self.error(inferred_type_of_class_expression(expr.span));
Some(self.ast.ts_unknown_keyword(SPAN))
}
Expression::TSNonNullExpression(expr) => {
@ -104,25 +102,17 @@ impl<'a> IsolatedDeclarations<'a> {
}
if function.r#async || function.generator {
self.error(function_must_have_explicit_return_type(function));
return None;
}
let return_type = FunctionReturnType::infer(
FunctionReturnType::infer(
self,
function
.body
.as_ref()
.unwrap_or_else(|| unreachable!("Only declare function can have no body")),
)
.map(|type_annotation| self.ast.ts_type_annotation(SPAN, type_annotation));
if return_type.is_none() {
self.error(function_must_have_explicit_return_type(function));
Some(self.ast.ts_type_annotation(SPAN, self.ast.ts_unknown_keyword(SPAN)))
} else {
return_type
}
.map(|type_annotation| self.ast.ts_type_annotation(SPAN, type_annotation))
}
pub fn infer_arrow_function_return_type(
@ -133,6 +123,14 @@ impl<'a> IsolatedDeclarations<'a> {
return self.ast.copy(&function.return_type);
}
if function.r#async {
return None;
}
if function.r#async {
return None;
}
if function.expression {
if let Some(Statement::ExpressionStatement(stmt)) = function.body.statements.first() {
return self
@ -140,6 +138,7 @@ impl<'a> IsolatedDeclarations<'a> {
.map(|type_annotation| self.ast.ts_type_annotation(SPAN, type_annotation));
}
}
FunctionReturnType::infer(self, &function.body)
.map(|type_annotation| self.ast.ts_type_annotation(SPAN, type_annotation))
}

View file

@ -5,7 +5,7 @@ use oxc_allocator::Box;
use oxc_ast::Visit;
use oxc_span::{GetSpan, SPAN};
use crate::IsolatedDeclarations;
use crate::{diagnostics::default_export_inferred, IsolatedDeclarations};
impl<'a> IsolatedDeclarations<'a> {
pub fn transform_export_named_declaration(
@ -46,6 +46,7 @@ impl<'a> IsolatedDeclarations<'a> {
} else {
// declare const _default: Type
let kind = VariableDeclarationKind::Const;
// TODO: create unique name for this
let name = self.ast.new_atom("_default");
let id = self
.ast
@ -54,6 +55,10 @@ impl<'a> IsolatedDeclarations<'a> {
.infer_type_from_expression(expr)
.map(|ts_type| self.ast.ts_type_annotation(SPAN, ts_type));
if type_annotation.is_none() {
self.error(default_export_inferred(expr.span()));
}
let id = BindingPattern { kind: id, type_annotation, optional: false };
let declarations = self
.ast

View file

@ -4,13 +4,23 @@ use oxc_ast::ast::{
TSTypeOperatorOperator,
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::SPAN;
use oxc_span::{GetSpan, SPAN};
use crate::IsolatedDeclarations;
use crate::{
diagnostics::{
function_must_have_explicit_return_type, inferred_type_of_expression, shorthand_property,
},
function::get_function_span,
IsolatedDeclarations,
};
impl<'a> IsolatedDeclarations<'a> {
pub fn transform_function_to_ts_type(&self, func: &Function<'a>) -> Option<TSType<'a>> {
let return_type = self.infer_function_return_type(func);
if return_type.is_none() {
self.error(function_must_have_explicit_return_type(get_function_span(func)));
}
let params = self.transform_formal_parameters(&func.params);
return_type.map(|return_type| {
@ -29,6 +39,11 @@ impl<'a> IsolatedDeclarations<'a> {
func: &ArrowFunctionExpression<'a>,
) -> Option<TSType<'a>> {
let return_type = self.infer_arrow_function_return_type(func);
if return_type.is_none() {
self.error(function_must_have_explicit_return_type(func.span));
}
let params = self.transform_formal_parameters(&func.params);
return_type.map(|return_type| {
@ -66,6 +81,11 @@ impl<'a> IsolatedDeclarations<'a> {
return None;
}
if object.shorthand {
self.error(shorthand_property(object.span));
return None;
}
if let Expression::FunctionExpression(function) = &object.value {
if !is_const && object.method {
let return_type = self.infer_function_return_type(function);
@ -86,6 +106,11 @@ impl<'a> IsolatedDeclarations<'a> {
let type_annotation = self.infer_type_from_expression(&object.value);
if type_annotation.is_none() {
self.error(inferred_type_of_expression(object.value.span()));
return None;
}
let property_signature = self.ast.ts_property_signature(
object.span,
false,