Skip to content

Commit

Permalink
feat(isolated-declarations): report errors that are consistent with t…
Browse files Browse the repository at this point in the history
…ypescript. (#3720)
  • Loading branch information
Dunqing committed Jun 17, 2024
1 parent 3c59735 commit 77d5533
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 44 deletions.
36 changes: 27 additions & 9 deletions crates/oxc_isolated_declarations/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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))
})
};

Expand Down Expand Up @@ -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,
Expand Down
8 changes: 7 additions & 1 deletion crates/oxc_isolated_declarations/src/declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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>) {
Expand Down
60 changes: 51 additions & 9 deletions crates/oxc_isolated_declarations/src/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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)
}
17 changes: 15 additions & 2 deletions crates/oxc_isolated_declarations/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@ 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>>> {
if func.modifiers.is_contains_declare() {
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,
Expand Down Expand Up @@ -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,
)
}
39 changes: 19 additions & 20 deletions crates/oxc_isolated_declarations/src/inferrer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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))
Expand All @@ -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) => {
Expand Down Expand Up @@ -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(
Expand All @@ -133,13 +123,22 @@ 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
.infer_type_from_expression(&stmt.expression)
.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))
}
Expand Down
7 changes: 6 additions & 1 deletion crates/oxc_isolated_declarations/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
29 changes: 27 additions & 2 deletions crates/oxc_isolated_declarations/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand All @@ -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| {
Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand Down

0 comments on commit 77d5533

Please sign in to comment.