mirror of
https://github.com/danbulant/oxc
synced 2026-05-22 05:38:54 +00:00
Because we lack specialization in stable Rust, `Vec::from_iter_in` is unable to take advantage of the fact that `[T; N]` has a statically knowable size. Introduce `Vec::from_array_in` for this case, which should be able to create the `Vec` with a single static-sized memcpy, or may allow the compiler to see that it can construct the array directly in the arena, rather than construct on stack and then copy to the arena. Also add a corresponding `AstBuilder::vec_from_array` method, and use it in various places in codebase.
168 lines
6.5 KiB
Rust
168 lines
6.5 KiB
Rust
use oxc_allocator::Box;
|
|
use oxc_ast::{ast::*, NONE};
|
|
use oxc_span::{Span, SPAN};
|
|
|
|
use crate::{
|
|
diagnostics::{
|
|
function_must_have_explicit_return_type, implicitly_adding_undefined_to_type,
|
|
parameter_must_have_explicit_type,
|
|
},
|
|
formal_parameter_binding_pattern::FormalParameterBindingPattern,
|
|
IsolatedDeclarations,
|
|
};
|
|
|
|
impl<'a> IsolatedDeclarations<'a> {
|
|
pub(crate) fn transform_function(
|
|
&mut self,
|
|
func: &Function<'a>,
|
|
declare: Option<bool>,
|
|
) -> Option<Box<'a, Function<'a>>> {
|
|
if func.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.alloc_function(
|
|
func.r#type,
|
|
func.span,
|
|
// SAFETY: `ast.copy` is unsound! We need to fix.
|
|
unsafe { self.ast.copy(&func.id) },
|
|
false,
|
|
false,
|
|
declare.unwrap_or_else(|| self.is_declare()),
|
|
// SAFETY: `ast.copy` is unsound! We need to fix.
|
|
unsafe { self.ast.copy(&func.type_parameters) },
|
|
// SAFETY: `ast.copy` is unsound! We need to fix.
|
|
unsafe { self.ast.copy(&func.this_param) },
|
|
params,
|
|
return_type,
|
|
NONE,
|
|
))
|
|
}
|
|
}
|
|
|
|
pub(crate) fn transform_formal_parameter(
|
|
&self,
|
|
param: &FormalParameter<'a>,
|
|
is_remaining_params_have_required: bool,
|
|
) -> Option<FormalParameter<'a>> {
|
|
let pattern = ¶m.pattern;
|
|
if let BindingPatternKind::AssignmentPattern(pattern) = &pattern.kind {
|
|
if pattern.left.kind.is_destructuring_pattern()
|
|
&& pattern.left.type_annotation.is_none()
|
|
{
|
|
self.error(parameter_must_have_explicit_type(param.span));
|
|
return None;
|
|
}
|
|
}
|
|
|
|
let is_assignment_pattern = pattern.kind.is_assignment_pattern();
|
|
let mut pattern =
|
|
if let BindingPatternKind::AssignmentPattern(pattern) = ¶m.pattern.kind {
|
|
// SAFETY: `ast.copy` is unsound! We need to fix.
|
|
unsafe { self.ast.copy(&pattern.left) }
|
|
} else {
|
|
// SAFETY: `ast.copy` is unsound! We need to fix.
|
|
unsafe { self.ast.copy(¶m.pattern) }
|
|
};
|
|
|
|
FormalParameterBindingPattern::remove_assignments_from_kind(self.ast, &mut pattern.kind);
|
|
|
|
if is_assignment_pattern || pattern.type_annotation.is_none() {
|
|
let type_annotation = pattern
|
|
.type_annotation
|
|
.as_ref()
|
|
.map(|type_annotation| {
|
|
// SAFETY: `ast.copy` is unsound! We need to fix.
|
|
unsafe { self.ast.copy(&type_annotation.type_annotation) }
|
|
})
|
|
.or_else(|| {
|
|
// report error for has no type annotation
|
|
let new_type = self.infer_type_from_formal_parameter(param);
|
|
if new_type.is_none() {
|
|
self.error(parameter_must_have_explicit_type(param.span));
|
|
}
|
|
new_type
|
|
})
|
|
.map(|ts_type| {
|
|
// jf next param is not optional and current param is assignment pattern
|
|
// we need to add undefined to it's type
|
|
if is_remaining_params_have_required {
|
|
if matches!(ts_type, TSType::TSTypeReference(_)) {
|
|
self.error(implicitly_adding_undefined_to_type(param.span));
|
|
} else if !ts_type.is_maybe_undefined() {
|
|
// union with `undefined`
|
|
return self.ast.ts_type_annotation(
|
|
SPAN,
|
|
self.ast.ts_type_union_type(
|
|
SPAN,
|
|
self.ast.vec_from_array([
|
|
ts_type,
|
|
self.ast.ts_type_undefined_keyword(SPAN),
|
|
]),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
self.ast.ts_type_annotation(SPAN, ts_type)
|
|
});
|
|
|
|
pattern = self.ast.binding_pattern(
|
|
// SAFETY: `ast.copy` is unsound! We need to fix.
|
|
unsafe { self.ast.copy(&pattern.kind) },
|
|
type_annotation,
|
|
// if it's assignment pattern, it's optional
|
|
pattern.optional || (!is_remaining_params_have_required && is_assignment_pattern),
|
|
);
|
|
}
|
|
|
|
Some(self.ast.formal_parameter(param.span, self.ast.vec(), pattern, None, false, false))
|
|
}
|
|
|
|
pub(crate) fn transform_formal_parameters(
|
|
&self,
|
|
params: &FormalParameters<'a>,
|
|
) -> Box<'a, FormalParameters<'a>> {
|
|
if params.kind.is_signature() || (params.rest.is_none() && params.items.is_empty()) {
|
|
// SAFETY: `ast.copy` is unsound! We need to fix.
|
|
return self.ast.alloc(unsafe { self.ast.copy(params) });
|
|
}
|
|
|
|
let items =
|
|
self.ast.vec_from_iter(params.items.iter().enumerate().filter_map(|(index, item)| {
|
|
let is_remaining_params_have_required =
|
|
params.items.iter().skip(index).any(|item| {
|
|
!(item.pattern.optional || item.pattern.kind.is_assignment_pattern())
|
|
});
|
|
self.transform_formal_parameter(item, is_remaining_params_have_required)
|
|
}));
|
|
|
|
if let Some(rest) = ¶ms.rest {
|
|
if rest.argument.type_annotation.is_none() {
|
|
self.error(parameter_must_have_explicit_type(rest.span));
|
|
}
|
|
}
|
|
|
|
self.ast.alloc_formal_parameters(
|
|
params.span,
|
|
FormalParameterKind::Signature,
|
|
items,
|
|
// SAFETY: `ast.copy` is unsound! We need to fix.
|
|
unsafe { self.ast.copy(¶ms.rest) },
|
|
)
|
|
}
|
|
}
|
|
|
|
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,
|
|
)
|
|
}
|